Fixed missing license headers
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / glance_dummy_api.py
1 """
2 Copyright (c) 2017 SONATA-NFV and Paderborn University
3 ALL RIGHTS RESERVED.
4
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
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
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.
16
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
20 permission.
21
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).
27 """
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
32 import logging
33 import json
34
35
36 LOG = logging.getLogger("api.openstack.glance")
37
38
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,
44 "/shutdown")
45 self.api.add_resource(GlanceListApiVersions,
46 "/versions")
47 self.api.add_resource(GlanceSchema,
48 "/v2/schemas/image",
49 "/v2/schemas/metadefs/namespace",
50 "/v2/schemas/metadefs/resource_type")
51 self.api.add_resource(GlanceListImagesApi,
52 "/v1/images",
53 "/v1/images/detail",
54 "/v2/images",
55 "/v2/images/detail",
56 resource_class_kwargs={'api': self})
57 self.api.add_resource(GlanceImageByIdApi,
58 "/v1/images/<id>",
59 "/v2/images/<id>",
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})
65
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)
71
72
73 class Shutdown(Resource):
74 def get(self):
75 LOG.debug(("%s is beeing shut down") % (__name__))
76 func = request.environ.get('werkzeug.server.shutdown')
77 if func is None:
78 raise RuntimeError('Not running with the Werkzeug Server')
79 func()
80
81
82 class GlanceListApiVersions(Resource):
83 def get(self):
84 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
85 resp = dict()
86 resp['versions'] = dict()
87 versions = [{
88 "status": "CURRENT",
89 "id": "v2",
90 "links": [
91 {
92 "href": request.url_root + '/v2',
93 "rel": "self"
94 }
95 ]
96 }]
97 resp['versions'] = versions
98 return Response(json.dumps(resp), status=200, mimetype='application/json')
99
100
101 class GlanceSchema(Resource):
102 def get(self):
103 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
104 resp = dict()
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')
109
110
111 class GlanceListImagesApi(Resource):
112 def __init__(self, api):
113 self.api = api
114
115 def get(self):
116 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
117 try:
118 resp = dict()
119 resp['next'] = None
120 resp['first'] = "/v2/images"
121 resp['schema'] = "/v2/schemas/images"
122 resp['images'] = list()
123 limit = 18
124 c = 0
125 for image in self.api.compute.images.values():
126 f = dict()
127 f['id'] = image.id
128 f['name'] = str(image.name).replace(":latest", "")
129 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
130 f['container_format'] = "docker"
131 f['disk_format'] = "raw"
132 f['size'] = 1
133 f['created_at'] = "2016-03-15T15:09:07.000000"
134 f['deleted'] = False
135 f['deleted_at'] = None
136 f['is_public'] = True
137 f['min_disk'] = 1
138 f['min_ram'] = 128
139 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
140 f['properties'] = {}
141 f['protected'] = False
142 f['status'] = "active"
143 f['updated_at'] = "2016-03-15T15:09:07.000000"
144 f['virtual_size'] = 1
145 f['marker'] = None
146 resp['images'].append(f)
147 c += 1
148 if c > limit: # ugly hack to stop buggy glance client to do infinite requests
149 break
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")
153
154 except Exception as ex:
155 LOG.exception(u"%s: Could not retrieve the list of images." % __name__)
156 return ex.message, 500
157
158 def post(self):
159 """
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.
163 """
164 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
165 try:
166 body_data = json.loads(request.data)
167 except:
168 body_data = dict()
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
176 if img_name is None:
177 img_name = body_data.get("name")
178 img_size = 1234
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)
183 img_id = None
184 for image in self.api.compute.images.values():
185 if str(img_name) in image.name:
186 img_id = image.id
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
190 resp = dict()
191 f = dict()
192 f['id'] = img_id
193 f['name'] = img_name
194 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
195 f['container_format'] = img_container_format
196 f['disk_format'] = img_disk_format
197 f['size'] = img_size
198 f['created_at'] = "2016-03-15T15:09:07.000000"
199 f['deleted'] = False
200 f['deleted_at'] = None
201 f['is_public'] = img_is_public
202 f['min_disk'] = 1
203 f['min_ram'] = 128
204 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
205 f['properties'] = {}
206 f['protected'] = False
207 f['status'] = "active"
208 f['updated_at'] = "2016-03-15T15:09:07.000000"
209 f['virtual_size'] = 1
210 resp['image'] = f
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),
214 self.api.port,
215 img_id))
216 return r
217
218
219 class GlanceImageByIdApi(Resource):
220 def __init__(self, api):
221 self.api = api
222
223 def get(self, id):
224 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
225 try:
226 resp = dict()
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
231
232 return Response(json.dumps(resp), status=200, mimetype="application/json")
233
234 response = Response("Image with id or name %s does not exists." % id, status=404)
235 response.headers['Access-Control-Allow-Origin'] = '*'
236 return response
237
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')
241
242 def put(self, id):
243 LOG.debug("API CALL: %s " % str(self.__class__.__name__))
244 LOG.warning("Endpoint not implemented")
245 return None
246
247
248 class GlanceImageByDockerNameApi(Resource):
249 def __init__(self, api):
250 self.api = api
251
252 def get(self, owner, container):
253 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
254 try:
255 name = "%s/%s" % (owner, container)
256 if name in self.api.compute.images:
257 image = self.api.compute.images[name]
258 resp = dict()
259 resp['id'] = image.id
260 resp['name'] = image.name
261 return Response(json.dumps(resp), status=200, mimetype="application/json")
262
263 response = Response("Image with id or name %s does not exists." % id, status=404)
264 response.headers['Access-Control-Allow-Origin'] = '*'
265 return response
266
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')