Fix: Made OS Glance fake API compatible to latest pyhton-glanceclient.
[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 resp = dict()
103 # resp['next'] = None
104 resp['first'] = "/v2/images"
105 resp['schema'] = "/v2/schemas/images"
106 resp['images'] = list()
107 limit = 18
108 c = 0
109 for image in self.api.compute.images.values():
110 f = dict()
111 f['id'] = image.id
112 f['name'] = str(image.name).replace(":latest", "")
113 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
114 f['container_format'] = "docker"
115 f['disk_format'] = "raw"
116 f['size'] = 1
117 f['created_at'] = "2016-03-15T15:09:07.000000"
118 f['deleted'] = False
119 f['deleted_at'] = None
120 f['is_public'] = True
121 f['min_disk'] = 1
122 f['min_ram'] = 128
123 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
124 f['properties'] = {}
125 f['protected'] = False
126 f['status'] = "active"
127 f['updated_at'] = "2016-03-15T15:09:07.000000"
128 f['virtual_size'] = 1
129 f['marker'] = None
130 resp['images'].append(f)
131 c += 1
132 if c > limit: # ugly hack to stop buggy glance client to do infinite requests
133 break
134 if "marker" in request.args: # ugly hack to fix pageination of openstack client
135 resp['images'] = None
136 return Response(json.dumps(resp), status=200,
137 mimetype="application/json")
138
139 except Exception as ex:
140 LOG.exception(
141 u"%s: Could not retrieve the list of images." % __name__)
142 return ex.message, 500
143
144 def post(self):
145 """
146 This one is a real fake! It does not really create anything and the mentioned image
147 should already be registered with Docker. However, this function returns a reply that looks
148 like the image was just created to make orchestrators, like OSM, happy.
149 """
150 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
151 try:
152 body_data = json.loads(request.data)
153 except BaseException:
154 body_data = dict()
155 # lets see what we should create
156 img_name = request.headers.get("X-Image-Meta-Name")
157 img_size = request.headers.get("X-Image-Meta-Size")
158 img_disk_format = request.headers.get("X-Image-Meta-Disk-Format")
159 img_is_public = request.headers.get("X-Image-Meta-Is-Public")
160 img_container_format = request.headers.get(
161 "X-Image-Meta-Container-Format")
162 # try to use body payload if header fields are empty
163 if img_name is None:
164 img_name = body_data.get("name")
165 img_size = 1234
166 img_disk_format = body_data.get("disk_format")
167 img_is_public = True if "public" in body_data.get(
168 "visibility") else False
169 img_container_format = body_data.get("container_format")
170 # try to find ID of already existing image (matched by name)
171 img_id = None
172 for image in self.api.compute.images.values():
173 if str(img_name) in image.name:
174 img_id = image.id
175 LOG.debug("Image name: %s" % img_name)
176 LOG.debug("Image id: %s" % img_id)
177 # build a response body that looks like a real one
178 resp = dict()
179 f = dict()
180 f['id'] = img_id
181 f['name'] = img_name
182 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
183 f['container_format'] = img_container_format
184 f['disk_format'] = img_disk_format
185 f['size'] = img_size
186 f['created_at'] = "2016-03-15T15:09:07.000000"
187 f['deleted'] = False
188 f['deleted_at'] = None
189 f['is_public'] = img_is_public
190 f['min_disk'] = 1
191 f['min_ram'] = 128
192 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
193 f['properties'] = {}
194 f['protected'] = False
195 f['status'] = "active"
196 f['updated_at'] = "2016-03-15T15:09:07.000000"
197 f['virtual_size'] = 1
198 resp['image'] = f
199 # build actual response with headers and everything
200 r = Response(json.dumps(resp), status=201, mimetype="application/json")
201 r.headers.add("Location", "http://%s:%d/v1/images/%s" % (get_host(request),
202 self.api.port,
203 img_id))
204 return r
205
206
207 class GlanceImageByIdApi(Resource):
208 def __init__(self, api):
209 self.api = api
210
211 def get(self, id):
212 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
213 try:
214 resp = dict()
215 for image in self.api.compute.images.values():
216 if image.id == id or image.name == id:
217 resp['id'] = image.id
218 resp['name'] = image.name
219
220 return Response(json.dumps(resp), status=200,
221 mimetype="application/json")
222
223 response = Response(
224 "Image with id or name %s does not exists." % id, status=404)
225 response.headers['Access-Control-Allow-Origin'] = '*'
226 return response
227
228 except Exception as ex:
229 LOG.exception(
230 u"%s: Could not retrieve image with id %s." % (__name__, id))
231 return Response(ex.message, status=500,
232 mimetype='application/json')
233
234 def put(self, id):
235 LOG.debug("API CALL: %s " % str(self.__class__.__name__))
236 LOG.warning("Endpoint not implemented")
237 return None
238
239
240 class GlanceImageByDockerNameApi(Resource):
241 def __init__(self, api):
242 self.api = api
243
244 def get(self, owner, container):
245 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
246 try:
247 name = "%s/%s" % (owner, container)
248 if name in self.api.compute.images:
249 image = self.api.compute.images[name]
250 resp = dict()
251 resp['id'] = image.id
252 resp['name'] = image.name
253 return Response(json.dumps(resp), status=200,
254 mimetype="application/json")
255
256 response = Response(
257 "Image with id or name %s does not exists." % id, status=404)
258 response.headers['Access-Control-Allow-Origin'] = '*'
259 return response
260
261 except Exception as ex:
262 logging.exception(
263 u"%s: Could not retrieve image with id %s." % (__name__, id))
264 return Response(ex.message, status=500,
265 mimetype='application/json')