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(Shutdown
,
45 self
.api
.add_resource(GlanceListApiVersions
,
47 self
.api
.add_resource(GlanceSchema
,
49 "/v2/schemas/metadefs/namespace",
50 "/v2/schemas/metadefs/resource_type")
51 self
.api
.add_resource(GlanceListImagesApi
,
56 resource_class_kwargs
={'api': self
})
57 self
.api
.add_resource(GlanceImageByIdApi
,
60 resource_class_kwargs
={'api': self
})
61 self
.api
.add_resource(GlanceImageByDockerNameApi
,
62 "/v1/images/<owner>/<container>",
63 "/v2/images/<owner>/<container>",
64 resource_class_kwargs
={'api': self
})
66 def _start_flask(self
):
67 LOG
.info("Starting %s endpoint @ http://%s:%d" % ("GlanceDummyApi", self
.ip
, self
.port
))
68 if self
.app
is not None:
69 self
.app
.before_request(self
.dump_playbook
)
70 self
.app
.run(self
.ip
, self
.port
, debug
=True, use_reloader
=False)
73 class Shutdown(Resource
):
75 LOG
.debug(("%s is beeing shut down") % (__name__
))
76 func
= request
.environ
.get('werkzeug.server.shutdown')
78 raise RuntimeError('Not running with the Werkzeug Server')
82 class GlanceListApiVersions(Resource
):
84 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
86 resp
['versions'] = dict()
92 "href": request
.url_root
+ '/v2',
97 resp
['versions'] = versions
98 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
101 class GlanceSchema(Resource
):
103 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
105 resp
['name'] = 'someImageName'
106 resp
['properties'] = dict()
107 # just an ugly hack to allow the openstack client to work
108 return Response(json
.dumps(resp
), status
=200, mimetype
='application/json')
111 class GlanceListImagesApi(Resource
):
112 def __init__(self
, api
):
116 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
120 resp
['first'] = "/v2/images"
121 resp
['schema'] = "/v2/schemas/images"
122 resp
['images'] = list()
125 for image
in self
.api
.compute
.images
.values():
128 f
['name'] = str(image
.name
).replace(":latest", "")
129 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
130 f
['container_format'] = "docker"
131 f
['disk_format'] = "raw"
133 f
['created_at'] = "2016-03-15T15:09:07.000000"
135 f
['deleted_at'] = None
136 f
['is_public'] = True
139 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
141 f
['protected'] = False
142 f
['status'] = "active"
143 f
['updated_at'] = "2016-03-15T15:09:07.000000"
144 f
['virtual_size'] = 1
146 resp
['images'].append(f
)
148 if c
> limit
: # ugly hack to stop buggy glance client to do infinite requests
150 if "marker" in request
.args
: # ugly hack to fix pageination of openstack client
151 resp
['images'] = None
152 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
154 except Exception as ex
:
155 LOG
.exception(u
"%s: Could not retrieve the list of images." % __name__
)
156 return ex
.message
, 500
160 This one is a real fake! It does not really create anything and the mentioned image
161 should already be registered with Docker. However, this function returns a reply that looks
162 like the image was just created to make orchestrators, like OSM, happy.
164 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
166 body_data
= json
.loads(request
.data
)
169 # lets see what we should create
170 img_name
= request
.headers
.get("X-Image-Meta-Name")
171 img_size
= request
.headers
.get("X-Image-Meta-Size")
172 img_disk_format
= request
.headers
.get("X-Image-Meta-Disk-Format")
173 img_is_public
= request
.headers
.get("X-Image-Meta-Is-Public")
174 img_container_format
= request
.headers
.get("X-Image-Meta-Container-Format")
175 # try to use body payload if header fields are empty
177 img_name
= body_data
.get("name")
179 img_disk_format
= body_data
.get("disk_format")
180 img_is_public
= True if "public" in body_data
.get("visibility") else False
181 img_container_format
= body_data
.get("container_format")
182 # try to find ID of already existing image (matched by name)
184 for image
in self
.api
.compute
.images
.values():
185 if str(img_name
) in image
.name
:
187 LOG
.debug("Image name: %s" % img_name
)
188 LOG
.debug("Image id: %s" % img_id
)
189 # build a response body that looks like a real one
194 f
['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
195 f
['container_format'] = img_container_format
196 f
['disk_format'] = img_disk_format
198 f
['created_at'] = "2016-03-15T15:09:07.000000"
200 f
['deleted_at'] = None
201 f
['is_public'] = img_is_public
204 f
['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
206 f
['protected'] = False
207 f
['status'] = "active"
208 f
['updated_at'] = "2016-03-15T15:09:07.000000"
209 f
['virtual_size'] = 1
211 # build actual response with headers and everything
212 r
= Response(json
.dumps(resp
), status
=201, mimetype
="application/json")
213 r
.headers
.add("Location", "http://%s:%d/v1/images/%s" % (get_host(request
),
219 class GlanceImageByIdApi(Resource
):
220 def __init__(self
, api
):
224 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
227 for image
in self
.api
.compute
.images
.values():
228 if image
.id == id or image
.name
== id:
229 resp
['id'] = image
.id
230 resp
['name'] = image
.name
232 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
234 response
= Response("Image with id or name %s does not exists." % id, status
=404)
235 response
.headers
['Access-Control-Allow-Origin'] = '*'
238 except Exception as ex
:
239 LOG
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, id))
240 return Response(ex
.message
, status
=500, mimetype
='application/json')
243 LOG
.debug("API CALL: %s " % str(self
.__class
__.__name
__))
244 LOG
.warning("Endpoint not implemented")
248 class GlanceImageByDockerNameApi(Resource
):
249 def __init__(self
, api
):
252 def get(self
, owner
, container
):
253 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
255 name
= "%s/%s" % (owner
, container
)
256 if name
in self
.api
.compute
.images
:
257 image
= self
.api
.compute
.images
[name
]
259 resp
['id'] = image
.id
260 resp
['name'] = image
.name
261 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
263 response
= Response("Image with id or name %s does not exists." % id, status
=404)
264 response
.headers
['Access-Control-Allow-Origin'] = '*'
267 except Exception as ex
:
268 logging
.exception(u
"%s: Could not retrieve image with id %s." % (__name__
, id))
269 return Response(ex
.message
, status
=500, mimetype
='application/json')