OpenStack API: Replaced Flask with WSGI
[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(GlanceListApiVersions,
44 "/versions")
45 self.api.add_resource(GlanceSchema,
46 "/v2/schemas/image",
47 "/v2/schemas/metadefs/namespace",
48 "/v2/schemas/metadefs/resource_type")
49 self.api.add_resource(GlanceListImagesApi,
50 "/v1/images",
51 "/v1/images/detail",
52 "/v2/images",
53 "/v2/images/detail",
54 resource_class_kwargs={'api': self})
55 self.api.add_resource(GlanceImageByIdApi,
56 "/v1/images/<id>",
57 "/v2/images/<id>",
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})
63
64
65 class GlanceListApiVersions(Resource):
66 def get(self):
67 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
68 resp = dict()
69 resp['versions'] = dict()
70 versions = [{
71 "status": "CURRENT",
72 "id": "v2",
73 "links": [
74 {
75 "href": request.url_root + '/v2',
76 "rel": "self"
77 }
78 ]
79 }]
80 resp['versions'] = versions
81 return Response(json.dumps(resp), status=200, mimetype='application/json')
82
83
84 class GlanceSchema(Resource):
85 def get(self):
86 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
87 resp = dict()
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')
92
93
94 class GlanceListImagesApi(Resource):
95 def __init__(self, api):
96 self.api = api
97
98 def get(self):
99 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
100 try:
101 resp = dict()
102 resp['next'] = None
103 resp['first'] = "/v2/images"
104 resp['schema'] = "/v2/schemas/images"
105 resp['images'] = list()
106 limit = 18
107 c = 0
108 for image in self.api.compute.images.values():
109 f = dict()
110 f['id'] = image.id
111 f['name'] = str(image.name).replace(":latest", "")
112 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
113 f['container_format'] = "docker"
114 f['disk_format'] = "raw"
115 f['size'] = 1
116 f['created_at'] = "2016-03-15T15:09:07.000000"
117 f['deleted'] = False
118 f['deleted_at'] = None
119 f['is_public'] = True
120 f['min_disk'] = 1
121 f['min_ram'] = 128
122 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
123 f['properties'] = {}
124 f['protected'] = False
125 f['status'] = "active"
126 f['updated_at'] = "2016-03-15T15:09:07.000000"
127 f['virtual_size'] = 1
128 f['marker'] = None
129 resp['images'].append(f)
130 c += 1
131 if c > limit: # ugly hack to stop buggy glance client to do infinite requests
132 break
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")
136
137 except Exception as ex:
138 LOG.exception(u"%s: Could not retrieve the list of images." % __name__)
139 return ex.message, 500
140
141 def post(self):
142 """
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.
146 """
147 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
148 try:
149 body_data = json.loads(request.data)
150 except:
151 body_data = dict()
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
159 if img_name is None:
160 img_name = body_data.get("name")
161 img_size = 1234
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)
166 img_id = None
167 for image in self.api.compute.images.values():
168 if str(img_name) in image.name:
169 img_id = image.id
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
173 resp = dict()
174 f = dict()
175 f['id'] = img_id
176 f['name'] = img_name
177 f['checksum'] = "2dad48f09e2a447a9bf852bcd93548c1"
178 f['container_format'] = img_container_format
179 f['disk_format'] = img_disk_format
180 f['size'] = img_size
181 f['created_at'] = "2016-03-15T15:09:07.000000"
182 f['deleted'] = False
183 f['deleted_at'] = None
184 f['is_public'] = img_is_public
185 f['min_disk'] = 1
186 f['min_ram'] = 128
187 f['owner'] = "3dad48f09e2a447a9bf852bcd93548c1"
188 f['properties'] = {}
189 f['protected'] = False
190 f['status'] = "active"
191 f['updated_at'] = "2016-03-15T15:09:07.000000"
192 f['virtual_size'] = 1
193 resp['image'] = f
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),
197 self.api.port,
198 img_id))
199 return r
200
201
202 class GlanceImageByIdApi(Resource):
203 def __init__(self, api):
204 self.api = api
205
206 def get(self, id):
207 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
208 try:
209 resp = dict()
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
214
215 return Response(json.dumps(resp), status=200, mimetype="application/json")
216
217 response = Response("Image with id or name %s does not exists." % id, status=404)
218 response.headers['Access-Control-Allow-Origin'] = '*'
219 return response
220
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')
224
225 def put(self, id):
226 LOG.debug("API CALL: %s " % str(self.__class__.__name__))
227 LOG.warning("Endpoint not implemented")
228 return None
229
230
231 class GlanceImageByDockerNameApi(Resource):
232 def __init__(self, api):
233 self.api = api
234
235 def get(self, owner, container):
236 logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
237 try:
238 name = "%s/%s" % (owner, container)
239 if name in self.api.compute.images:
240 image = self.api.compute.images[name]
241 resp = dict()
242 resp['id'] = image.id
243 resp['name'] = image.name
244 return Response(json.dumps(resp), status=200, mimetype="application/json")
245
246 response = Response("Image with id or name %s does not exists." % id, status=404)
247 response.headers['Access-Control-Allow-Origin'] = '*'
248 return response
249
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')