Fix: Made Glance-fake API more robust in
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / glance_dummy_api.py
1 # Copyright (c) 2015 SONATA-NFV and Paderborn University
2 # ALL RIGHTS RESERVED.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # Neither the name of the SONATA-NFV, Paderborn University
17 # nor the names of its contributors may be used to endorse or promote
18 # products derived from this software without specific prior written
19 # permission.
20 #
21 # This work has been performed in the framework of the SONATA project,
22 # funded by the European Commission under Grant number 671517 through
23 # the Horizon 2020 and 5G-PPP programmes. The authors would like to
24 # acknowledge the contributions of their colleagues of the SONATA
25 # partner consortium (www.sonata-nfv.eu).
26 from flask_restful import Resource
27 from flask import Response, request
28 from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy
29 from emuvim.api.openstack.helper import get_host
30 import logging
31 import json
32
33
34 LOG = logging.getLogger("api.openstack.glance")
35
36
37 class GlanceDummyApi(BaseOpenstackDummy):
38 def __init__(self, in_ip, in_port, compute):
39 super(GlanceDummyApi, self).__init__(in_ip, in_port)
40 self.compute = compute
41 self.api.add_resource(GlanceListApiVersions,
42 "/versions")
43 self.api.add_resource(GlanceSchema,
44 "/v2/schemas/image",
45 "/v2/schemas/metadefs/namespace",
46 "/v2/schemas/metadefs/resource_type")
47 self.api.add_resource(GlanceListImagesApi,
48 "/v1/images",
49 "/v1/images/detail",
50 "/v2/images",
51 "/v2/images/detail",
52 resource_class_kwargs={'api': self})
53 self.api.add_resource(GlanceImageByIdApi,
54 "/v1/images/<id>",
55 "/v2/images/<id>",
56 resource_class_kwargs={'api': self})
57 self.api.add_resource(GlanceImageByDockerNameApi,
58 "/v1/images/<owner>/<container>",
59 "/v2/images/<owner>/<container>",
60 resource_class_kwargs={'api': self})
61
62
63 class GlanceListApiVersions(Resource):
64 def get(self):
65 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
66 resp = dict()
67 resp['versions'] = dict()
68 versions = [{
69 "status": "CURRENT",
70 "id": "v2",
71 "links": [
72 {
73 "href": request.url_root + '/v2',
74 "rel": "self"
75 }
76 ]
77 }]
78 resp['versions'] = versions
79 return Response(json.dumps(resp), status=200,
80 mimetype='application/json')
81
82
83 class GlanceSchema(Resource):
84 def get(self):
85 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
86 resp = dict()
87 resp['name'] = 'someImageName'
88 resp['properties'] = dict()
89 resp['links'] = list()
90 # just an ugly hack to allow the openstack client to work
91 return Response(json.dumps(resp), status=200,
92 mimetype='application/json')
93
94
95 class GlanceListImagesApi(Resource):
96 def __init__(self, api):
97 self.api = api
98
99 def get(self):
100 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
101 try:
102 img_list = self.api.compute.images.values()
103 LOG.debug("Found {} Docker images: {}".format(
104 len(img_list), [i.name for i in img_list]))
105 resp = dict()
106 # resp['next'] = None
107 resp['first'] = "/v2/images"
108 resp['schema'] = "/v2/schemas/images"
109 resp['images'] = list()
110 for image in img_list:
111 f = dict()
112 f['id'] = image.id
113 f['name'] = str(image.name).replace(":latest", "")
114 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
115 f['container_format'] = "docker"
116 f['disk_format'] = "raw"
117 f['size'] = 1
118 f['created_at'] = "2016-03-15T15:09:07.000000"
119 f['deleted'] = False
120 f['deleted_at'] = None
121 f['is_public'] = True
122 f['min_disk'] = 1
123 f['min_ram'] = 128
124 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
125 f['properties'] = {}
126 f['protected'] = False
127 f['status'] = "active"
128 f['updated_at'] = "2016-03-15T15:09:07.000000"
129 f['virtual_size'] = 1
130 f['marker'] = None
131 resp['images'].append(f)
132 if "marker" in request.args: # ugly hack to fix pageination of openstack client
133 resp['images'] = None
134 return Response(json.dumps(resp), status=200,
135 mimetype="application/json")
136
137 except Exception as ex:
138 LOG.exception(
139 u"%s: Could not retrieve the list of images." % __name__)
140 return ex.message, 500
141
142 def post(self):
143 """
144 This one is a real fake! It does not really create anything and the mentioned image
145 should already be registered with Docker. However, this function returns a reply that looks
146 like the image was just created to make orchestrators, like OSM, happy.
147 """
148 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
149 try:
150 body_data = json.loads(request.data)
151 except BaseException:
152 body_data = dict()
153 # lets see what we should create
154 img_name = request.headers.get("X-Image-Meta-Name")
155 img_size = request.headers.get("X-Image-Meta-Size")
156 img_disk_format = request.headers.get("X-Image-Meta-Disk-Format")
157 img_is_public = request.headers.get("X-Image-Meta-Is-Public")
158 img_container_format = request.headers.get(
159 "X-Image-Meta-Container-Format")
160 # try to use body payload if header fields are empty
161 if img_name is None:
162 img_name = body_data.get("name")
163 img_size = 1234
164 img_disk_format = body_data.get("disk_format")
165 img_is_public = True if "public" in body_data.get(
166 "visibility") else False
167 img_container_format = body_data.get("container_format")
168 # try to find ID of already existing image (matched by name)
169 img_id = None
170 for image in self.api.compute.images.values():
171 if str(img_name) in image.name:
172 img_id = image.id
173 LOG.debug("Image name: %s" % img_name)
174 LOG.debug("Image id: %s" % img_id)
175 # build a response body that looks like a real one
176 resp = dict()
177 f = dict()
178 f['id'] = img_id
179 f['name'] = img_name
180 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
181 f['container_format'] = img_container_format
182 f['disk_format'] = img_disk_format
183 f['size'] = img_size
184 f['created_at'] = "2016-03-15T15:09:07.000000"
185 f['deleted'] = False
186 f['deleted_at'] = None
187 f['is_public'] = img_is_public
188 f['min_disk'] = 1
189 f['min_ram'] = 128
190 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
191 f['properties'] = {}
192 f['protected'] = False
193 f['status'] = "active"
194 f['updated_at'] = "2016-03-15T15:09:07.000000"
195 f['virtual_size'] = 1
196 resp['image'] = f
197 # build actual response with headers and everything
198 r = Response(json.dumps(resp), status=201, mimetype="application/json")
199 r.headers.add("Location", "http://%s:%d/v1/images/%s" % (get_host(request),
200 self.api.port,
201 img_id))
202 return r
203
204
205 class GlanceImageByIdApi(Resource):
206 def __init__(self, api):
207 self.api = api
208
209 def get(self, id):
210 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
211 try:
212 resp = dict()
213 for image in self.api.compute.images.values():
214 if image.id == id or image.name == id:
215 resp['id'] = image.id
216 resp['name'] = image.name
217
218 return Response(json.dumps(resp), status=200,
219 mimetype="application/json")
220
221 response = Response(
222 "Image with id or name %s does not exists." % id, status=404)
223 response.headers['Access-Control-Allow-Origin'] = '*'
224 return response
225
226 except Exception as ex:
227 LOG.exception(
228 u"%s: Could not retrieve image with id %s." % (__name__, id))
229 return Response(ex.message, status=500,
230 mimetype='application/json')
231
232 def put(self, id):
233 LOG.debug("API CALL: %s " % str(self.__class__.__name__))
234 LOG.warning("Endpoint not implemented")
235 return None
236
237
238 class GlanceImageByDockerNameApi(Resource):
239 def __init__(self, api):
240 self.api = api
241
242 def get(self, owner, container):
243 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
244 try:
245 name = "%s/%s" % (owner, container)
246 if name in self.api.compute.images:
247 image = self.api.compute.images[name]
248 resp = dict()
249 resp['id'] = image.id
250 resp['name'] = image.name
251 return Response(json.dumps(resp), status=200,
252 mimetype="application/json")
253
254 response = Response(
255 "Image with id or name %s does not exists." % id, status=404)
256 response.headers['Access-Control-Allow-Origin'] = '*'
257 return response
258
259 except Exception as ex:
260 logging.exception(
261 u"%s: Could not retrieve image with id %s." % (__name__, id))
262 return Response(ex.message, status=500,
263 mimetype='application/json')