2 Copyright (c) 2017 SONATA-NFV and Paderborn University
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
17 Neither the name of the SONATA-NFV, Paderborn University
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
28 from flask_restful
import Resource
29 from flask
import Response
, request
30 from emuvim
.api
.openstack
.openstack_dummies
.base_openstack_dummy
import BaseOpenstackDummy
31 from emuvim
.api
.openstack
.helper
import get_host
36 LOG
= logging
.getLogger("api.openstack.glance")
39 class GlanceDummyApi(BaseOpenstackDummy
):
40 def __init__(self
, in_ip
, in_port
, compute
):
41 super(GlanceDummyApi
, self
).__init
__(in_ip
, in_port
)
42 self
.compute
= compute
43 self
.api
.add_resource(GlanceListApiVersions
,
45 self
.api
.add_resource(GlanceSchema
,
47 "/v2/schemas/metadefs/namespace",
48 "/v2/schemas/metadefs/resource_type")
49 self
.api
.add_resource(GlanceListImagesApi
,
54 resource_class_kwargs
={'api': self
})
55 self
.api
.add_resource(GlanceImageByIdApi
,
58 resource_class_kwargs
={'api': self
})
59 self
.api
.add_resource(GlanceImageByDockerNameApi
,
60 "/v1/images/<owner>/<container>",
61 "/v2/images/<owner>/<container>",
62 resource_class_kwargs
={'api': self
})
65 class GlanceListApiVersions(Resource
):
67 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
69 resp
['versions'] = dict()
75 "href": request
.url_root
+ '/v2',
80 resp
['versions'] = versions
81 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
84 class GlanceSchema(Resource
):
86 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
88 resp
['name'] = 'someImageName'
89 resp
['properties'] = dict()
90 # just an ugly hack to allow the openstack client to work
91 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
94 class GlanceListImagesApi(Resource
):
95 def __init__(self
, api
):
99 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
103 resp
['first'] = "/v2/images"
104 resp
['schema'] = "/v2/schemas/images"
105 resp
['images'] = list()
108 for image
in self
.api
.compute
.images
.values():
111 f
['name'] = str(image
.name
).replace(":latest", "")
112 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
113 f
['container_format'] = "docker"
114 f
['disk_format'] = "raw"
116 f
['created_at'] = "2016-03-15T15:09:07.000000"
118 f
['deleted_at'] = None
119 f
['is_public'] = True
122 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
124 f
['protected'] = False
125 f
['status'] = "active"
126 f
['updated_at'] = "2016-03-15T15:09:07.000000"
127 f
['virtual_size'] = 1
129 resp
['images'].append(f
)
131 if c
> limit
: # ugly hack to stop buggy glance client to do infinite requests
133 if "marker" in request
.args
: # ugly hack to fix pageination of openstack client
134 resp
['images'] = None
135 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
137 except Exception as ex
:
138 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
139 return ex
.message
, 500
143 This one is a real fake! It does not really create anything and the mentioned image
144 should already be registered with Docker. However, this function returns a reply that looks
145 like the image was just created to make orchestrators, like OSM, happy.
147 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
149 body_data
= json
.loads(request
.data
)
152 # lets see what we should create
153 img_name
= request
.headers
.get("X-Image-Meta-Name")
154 img_size
= request
.headers
.get("X-Image-Meta-Size")
155 img_disk_format
= request
.headers
.get("X-Image-Meta-Disk-Format")
156 img_is_public
= request
.headers
.get("X-Image-Meta-Is-Public")
157 img_container_format
= request
.headers
.get("X-Image-Meta-Container-Format")
158 # try to use body payload if header fields are empty
160 img_name
= body_data
.get("name")
162 img_disk_format
= body_data
.get("disk_format")
163 img_is_public
= True if "public" in body_data
.get("visibility") else False
164 img_container_format
= body_data
.get("container_format")
165 # try to find ID of already existing image (matched by name)
167 for image
in self
.api
.compute
.images
.values():
168 if str(img_name
) in image
.name
:
170 LOG
.debug("Image name: %s" % img_name
)
171 LOG
.debug("Image id: %s" % img_id
)
172 # build a response body that looks like a real one
177 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
178 f
['container_format'] = img_container_format
179 f
['disk_format'] = img_disk_format
181 f
['created_at'] = "2016-03-15T15:09:07.000000"
183 f
['deleted_at'] = None
184 f
['is_public'] = img_is_public
187 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
189 f
['protected'] = False
190 f
['status'] = "active"
191 f
['updated_at'] = "2016-03-15T15:09:07.000000"
192 f
['virtual_size'] = 1
194 # build actual response with headers and everything
195 r
= Response(json
.dumps(resp
), status
=201, mimetype
="application/json")
196 r
.headers
.add("Location", "http://%s:%d/v1/images/%s" % (get_host(request
),
202 class GlanceImageByIdApi(Resource
):
203 def __init__(self
, api
):
207 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
210 for image
in self
.api
.compute
.images
.values():
211 if image
.id == id or image
.name
== id:
212 resp
['id'] = image
.id
213 resp
['name'] = image
.name
215 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
217 response
= Response("Image with id or name %s does not exists." % id, status
=404)
218 response
.headers
['Access-Control-Allow-Origin'] = '*'
221 except Exception as ex
:
222 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, id))
223 return Response(ex
.message
, status
=500, mimetype
='application/json')
226 LOG
.debug("API CALL: %s " % str(self
.__class
__.__name
__))
227 LOG
.warning("Endpoint not implemented")
231 class GlanceImageByDockerNameApi(Resource
):
232 def __init__(self
, api
):
235 def get(self
, owner
, container
):
236 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
238 name
= "%s/%s" % (owner
, container
)
239 if name
in self
.api
.compute
.images
:
240 image
= self
.api
.compute
.images
[name
]
242 resp
['id'] = image
.id
243 resp
['name'] = image
.name
244 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
246 response
= Response("Image with id or name %s does not exists." % id, status
=404)
247 response
.headers
['Access-Control-Allow-Origin'] = '*'
250 except Exception as ex
:
251 logging
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, id))
252 return Response(ex
.message
, status
=500, mimetype
='application/json')