OpenStack API: Replaced Flask with WSGI
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / keystone_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 request, Response
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 LOG = logging.getLogger("api.openstack.keystone")
36
37
38 class KeystoneDummyApi(BaseOpenstackDummy):
39 def __init__(self, in_ip, in_port):
40 super(KeystoneDummyApi, self).__init__(in_ip, in_port)
41
42 self.api.add_resource(KeystoneListVersions, "/", resource_class_kwargs={'api': self})
43 self.api.add_resource(KeystoneShowAPIv2, "/v2.0", resource_class_kwargs={'api': self})
44 self.api.add_resource(KeystoneGetToken, "/v2.0/tokens", resource_class_kwargs={'api': self})
45 self.api.add_resource(KeystoneShowAPIv3, "/v3.0", resource_class_kwargs={'api': self})
46 self.api.add_resource(KeystoneGetTokenv3, "/v3.0/auth/tokens", resource_class_kwargs={'api': self})
47
48
49 class KeystoneListVersions(Resource):
50 """
51 List all known keystone versions.
52 Hardcoded for our version!
53 """
54
55 def __init__(self, api):
56 self.api = api
57
58 def get(self):
59 """
60 List API versions.
61
62 :return: Returns the api versions.
63 :rtype: :class:`flask.response` containing a static json encoded dict.
64 """
65 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
66 resp = dict()
67 resp['versions'] = dict()
68
69 version = [{
70 "id": "v2.0",
71 "links": [
72 {
73 "href": "http://%s:%d/v2.0" % (get_host(request), self.api.port),
74 "rel": "self"
75 }
76 ],
77 "media-types": [
78 {
79 "base": "application/json",
80 "type": "application/vnd.openstack.identity-v2.0+json"
81 }
82 ],
83 "status": "stable",
84 "updated": "2014-04-17T00:00:00Z"
85 }]
86 resp['versions']['values'] = version
87
88 return Response(json.dumps(resp), status=200, mimetype='application/json')
89
90
91 class KeystoneShowAPIv2(Resource):
92 """
93 Entrypoint for all openstack clients.
94 This returns all current entrypoints running on son-emu.
95 """
96
97 def __init__(self, api):
98 self.api = api
99
100 def get(self):
101 """
102 List API entrypoints.
103
104 :return: Returns an openstack style response for all entrypoints.
105 :rtype: :class:`flask.response`
106 """
107 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
108
109 neutron_port = self.api.port + 4696
110 heat_port = self.api.port + 3004
111
112 resp = dict()
113 resp['version'] = {
114 "status": "stable",
115 "media-types": [
116 {
117 "base": "application/json",
118 "type": "application/vnd.openstack.identity-v2.0+json"
119 }
120 ],
121 "id": "v2.0",
122 "links": [
123 {
124 "href": "http://%s:%d/v2.0" % (get_host(request), self.api.port),
125 "rel": "self"
126 }
127 ]
128 }
129 LOG.debug(json.dumps(resp))
130 return Response(json.dumps(resp), status=200, mimetype='application/json')
131
132
133 class KeystoneShowAPIv3(Resource):
134 """
135 Entrypoint for all openstack clients.
136 This returns all current entrypoints running on son-emu.
137 """
138
139 def __init__(self, api):
140 self.api = api
141
142 def get(self):
143 """
144 List API entrypoints.
145
146 :return: Returns an openstack style response for all entrypoints.
147 :rtype: :class:`flask.response`
148 """
149 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
150
151 neutron_port = self.api.port + 4696
152 heat_port = self.api.port + 3004
153
154 resp = dict()
155 resp['version'] = {
156 "status": "stable",
157 "media-types": [
158 {
159 "base": "application/json",
160 "type": "application/vnd.openstack.identity-v3.0+json"
161 }
162 ],
163 "id": "v3.0",
164 "links": [
165 {
166 "href": "http://%s:%d/v3.0" % (get_host(request), self.api.port),
167 "rel": "self"
168 }
169 ]
170 }
171
172 return Response(json.dumps(resp), status=200, mimetype='application/json')
173
174
175 class KeystoneGetToken(Resource):
176 """
177 Returns a static keystone token.
178 We don't do any validation so we don't care.
179 """
180
181 def __init__(self, api):
182 self.api = api
183
184 def post(self):
185 """
186 List API entrypoints.
187
188 This is hardcoded. For a working "authentication" use these ENVVARS:
189
190 * OS_AUTH_URL=http://<ip>:<port>/v2.0
191 * OS_IDENTITY_API_VERSION=2.0
192 * OS_TENANT_ID=fc394f2ab2df4114bde39905f800dc57
193 * OS_REGION_NAME=RegionOne
194 * OS_USERNAME=bla
195 * OS_PASSWORD=bla
196
197 :return: Returns an openstack style response for all entrypoints.
198 :rtype: :class:`flask.response`
199 """
200
201 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
202 try:
203 ret = dict()
204 req = json.loads(request.data)
205 ret['access'] = dict()
206 ret['access']['token'] = dict()
207 token = ret['access']['token']
208
209 token['issued_at'] = "2014-01-30T15:30:58.819Z"
210 token['expires'] = "2999-01-30T15:30:58.819Z"
211 token['id'] = req['auth'].get('token', {'id': 'fc394f2ab2df4114bde39905f800dc57'}).get('id')
212 token['tenant'] = dict()
213 token['tenant']['description'] = None
214 token['tenant']['enabled'] = True
215 token['tenant']['id'] = req['auth'].get('tenantId', 'fc394f2ab2df4114bde39905f800dc57')
216 token['tenant']['name'] = "tenantName"
217
218 ret['access']['user'] = dict()
219 user = ret['access']['user']
220 user['username'] = req.get('username', "username")
221 user['name'] = "tenantName"
222 user['roles_links'] = list()
223 user['id'] = token['tenant'].get('id', "fc394f2ab2df4114bde39905f800dc57")
224 user['roles'] = [{'name': 'Member'}]
225
226 ret['access']['region_name'] = "RegionOne"
227
228 ret['access']['serviceCatalog'] = [{
229 "endpoints": [
230 {
231 "adminURL": "http://%s:%s/v2.1/%s" % (get_host(request), self.api.port + 3774, user['id']),
232 "region": "RegionOne",
233 "internalURL": "http://%s:%s/v2.1/%s" % (get_host(request), self.api.port + 3774, user['id']),
234 "id": "2dad48f09e2a447a9bf852bcd93548ef",
235 "publicURL": "http://%s:%s/v2.1/%s" % (get_host(request), self.api.port + 3774, user['id'])
236 }
237 ],
238 "endpoints_links": [],
239 "type": "compute",
240 "name": "nova"
241 },
242 {
243 "endpoints": [
244 {
245 "adminURL": "http://%s:%s/v2.0" % (get_host(request), self.api.port),
246 "region": "RegionOne",
247 "internalURL": "http://%s:%s/v2.0" % (get_host(request), self.api.port),
248 "id": "2dad48f09e2a447a9bf852bcd93543fc",
249 "publicURL": "http://%s:%s/v2" % (get_host(request), self.api.port)
250 }
251 ],
252 "endpoints_links": [],
253 "type": "identity",
254 "name": "keystone"
255 },
256 {
257 "endpoints": [
258 {
259 "adminURL": "http://%s:%s" % (get_host(request), self.api.port + 4696),
260 "region": "RegionOne",
261 "internalURL": "http://%s:%s" % (get_host(request), self.api.port + 4696),
262 "id": "2dad48f09e2a447a9bf852bcd93548cf",
263 "publicURL": "http://%s:%s" % (get_host(request), self.api.port + 4696)
264 }
265 ],
266 "endpoints_links": [],
267 "type": "network",
268 "name": "neutron"
269 },
270 {
271 "endpoints": [
272 {
273 "adminURL": "http://%s:%s" % (get_host(request), self.api.port + 4242),
274 "region": "RegionOne",
275 "internalURL": "http://%s:%s" % (get_host(request), self.api.port + 4242),
276 "id": "2dad48f09e2a447a9bf852bcd93548cf",
277 "publicURL": "http://%s:%s" % (get_host(request), self.api.port + 4242)
278 }
279 ],
280 "endpoints_links": [],
281 "type": "image",
282 "name": "glance"
283 },
284 {
285 "endpoints": [
286 {
287 "adminURL": "http://%s:%s/v1/%s" % (get_host(request), self.api.port + 3004, user['id']),
288 "region": "RegionOne",
289 "internalURL": "http://%s:%s/v1/%s" % (get_host(request), self.api.port + 3004, user['id']),
290 "id": "2dad48f09e2a447a9bf852bcd93548bf",
291 "publicURL": "http://%s:%s/v1/%s" % (get_host(request), self.api.port + 3004, user['id'])
292 }
293 ],
294 "endpoints_links": [],
295 "type": "orchestration",
296 "name": "heat"
297 }
298 ]
299
300 ret['access']["metadata"] = {
301 "is_admin": 0,
302 "roles": [
303 "7598ac3c634d4c3da4b9126a5f67ca2b"
304 ]
305 },
306 ret['access']['trust'] = {
307 "id": "394998fa61f14736b1f0c1f322882949",
308 "trustee_user_id": "269348fdd9374b8885da1418e0730af1",
309 "trustor_user_id": "3ec3164f750146be97f21559ee4d9c51",
310 "impersonation": False
311 }
312 return Response(json.dumps(ret), status=200, mimetype='application/json')
313
314 except Exception as ex:
315 logging.exception("Keystone: Get token failed.")
316 return ex.message, 500
317
318 class KeystoneGetTokenv3(Resource):
319 """
320 Returns a static keystone token.
321 We don't do any validation so we don't care.
322 """
323
324 def __init__(self, api):
325 self.api = api
326
327 def post(self):
328 """
329 List API entrypoints.
330
331 This is hardcoded. For a working "authentication" use these ENVVARS:
332
333 * OS_AUTH_URL=http://<ip>:<port>/v3
334 * OS_IDENTITY_API_VERSION=2.0
335 * OS_TENANT_ID=fc394f2ab2df4114bde39905f800dc57
336 * OS_REGION_NAME=RegionOne
337 * OS_USERNAME=bla
338 * OS_PASSWORD=bla
339
340 :return: Returns an openstack style response for all entrypoints.
341 :rtype: :class:`flask.response`
342 """
343
344 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
345 try:
346 ret = dict()
347 req = json.loads(request.data)
348 ret['token'] = dict()
349 token = ret['token']
350
351 token['issued_at'] = "2014-01-30T15:30:58.819Z"
352 token['expires_at'] = "2999-01-30T15:30:58.819Z"
353 token['methods'] = ["password"]
354 token['extras'] = dict()
355 token['user'] = dict()
356 user = token['user']
357 user['id'] = req['auth'].get('token', {'id': 'fc394f2ab2df4114bde39905f800dc57'}).get('id')
358 user['name'] = "tenantName"
359 user['password_expires_at'] = None
360 user['domain'] = {"id": "default", "name": "Default"}
361 token['audit_ids'] = ["ZzZwkUflQfygX7pdYDBCQQ"]
362
363 # project
364 token['project'] = {
365 "domain": {
366 "id" : "default",
367 "name": "Default"
368 },
369 "id": "8538a3f13f9541b28c2620eb19065e45",
370 "name": "tenantName"
371 }
372
373 # catalog
374 token['catalog'] = [{
375 "endpoints": [
376 {
377 "url": "http://%s:%s/v2.1/%s" % (get_host(request), self.api.port + 3774, user['id']),
378 "region": "RegionOne",
379 "interface": "public",
380 "id": "2dad48f09e2a447a9bf852bcd93548ef"
381 }
382 ],
383 "id": "2dad48f09e2a447a9bf852bcd93548ef",
384 "type": "compute",
385 "name": "nova"
386 },
387 {
388 "endpoints": [
389 {
390 "url": "http://%s:%s/v2.0" % (get_host(request), self.api.port),
391 "region": "RegionOne",
392 "interface": "public",
393 "id": "2dad48f09e2a447a9bf852bcd93543fc"
394 }
395 ],
396 "id": "2dad48f09e2a447a9bf852bcd93543fc",
397 "type": "identity",
398 "name": "keystone"
399 },
400 {
401 "endpoints": [
402 {
403 "url": "http://%s:%s" % (get_host(request), self.api.port + 4696),
404 "region": "RegionOne",
405 "interface": "public",
406 "id": "2dad48f09e2a447a9bf852bcd93548cf"
407 }
408 ],
409 "id": "2dad48f09e2a447a9bf852bcd93548cf",
410 "type": "network",
411 "name": "neutron"
412 },
413 {
414 "endpoints": [
415 {
416 "url": "http://%s:%s" % (get_host(request), self.api.port + 4242),
417 "region": "RegionOne",
418 "interface": "public",
419 "id": "2dad48f09e2a447a9bf852bcd93548cf"
420 }
421 ],
422 "id": "2dad48f09e2a447a9bf852bcd93548cf",
423 "type": "image",
424 "name": "glance"
425 },
426 {
427 "endpoints": [
428 {
429 "url": "http://%s:%s/v1/%s" % (get_host(request), self.api.port + 3004, user['id']),
430 "region": "RegionOne",
431 "interface": "public",
432 "id": "2dad48f09e2a447a9bf852bcd93548bf"
433 }
434 ],
435 "id": "2dad48f09e2a447a9bf852bcd93548bf",
436 "type": "orchestration",
437 "name": "heat"
438 }
439 ]
440 return Response(json.dumps(ret), status=201, mimetype='application/json')
441
442 except Exception as ex:
443 logging.exception("Keystone: Get token failed.")
444 return ex.message, 500