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