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