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