blob: 358d128662e42200cfc27e98fb9fefb3f0c2d3a7 [file] [log] [blame]
gstepanov94531b82015-02-11 14:20:34 +02001import json
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03002import urllib.request
koder aka kdanilov652cd802015-04-13 12:21:07 +03003from functools import partial
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03004from typing import Dict, Any
koder aka kdanilov652cd802015-04-13 12:21:07 +03005
gstepanov94531b82015-02-11 14:20:34 +02006from keystoneclient import exceptions
koder aka kdanilov652cd802015-04-13 12:21:07 +03007from keystoneclient.v2_0 import Client as keystoneclient
gstepanov94531b82015-02-11 14:20:34 +02008
koder aka kdanilov0f0546c2015-02-17 20:42:05 -08009
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030010class Urllib2HTTP:
gstepanov94531b82015-02-11 14:20:34 +020011 """
12 class for making HTTP requests
13 """
14
15 allowed_methods = ('get', 'put', 'post', 'delete', 'patch', 'head')
16
koder aka kdanilov22d134e2016-11-08 11:33:19 +020017 def __init__(self, root_url:str, headers:Dict[str, str]=None, echo: bool=False) -> None:
18 """"""
gstepanov94531b82015-02-11 14:20:34 +020019 if root_url.endswith('/'):
20 self.root_url = root_url[:-1]
21 else:
22 self.root_url = root_url
23
24 self.headers = headers if headers is not None else {}
25 self.echo = echo
26
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030027 def do(self, method: str, path: str, params: Dict[str, str]=None) -> Any:
gstepanov94531b82015-02-11 14:20:34 +020028 if path.startswith('/'):
29 url = self.root_url + path
30 else:
31 url = self.root_url + '/' + path
32
33 if method == 'get':
34 assert params == {} or params is None
35 data_json = None
36 else:
37 data_json = json.dumps(params)
38
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030039 request = urllib.request.Request(url,
40 data=data_json,
41 headers=self.headers)
gstepanov94531b82015-02-11 14:20:34 +020042 if data_json is not None:
43 request.add_header('Content-Type', 'application/json')
44
45 request.get_method = lambda: method.upper()
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030046 response = urllib.request.urlopen(request)
gstepanov94531b82015-02-11 14:20:34 +020047
gstepanov94531b82015-02-11 14:20:34 +020048 if response.code < 200 or response.code > 209:
49 raise IndexError(url)
50
51 content = response.read()
52
53 if '' == content:
54 return None
55
56 return json.loads(content)
57
58 def __getattr__(self, name):
59 if name in self.allowed_methods:
60 return partial(self.do, name)
61 raise AttributeError(name)
62
63
64class KeystoneAuth(Urllib2HTTP):
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030065 def __init__(self, root_url: str, creds: Dict[str, str], headers: Dict[str, str]=None, echo: bool=False,
66 admin_node_ip: str=None):
gstepanov94531b82015-02-11 14:20:34 +020067 super(KeystoneAuth, self).__init__(root_url, headers, echo)
68 self.keystone_url = "http://{0}:5000/v2.0".format(admin_node_ip)
69 self.keystone = keystoneclient(
70 auth_url=self.keystone_url, **creds)
71 self.refresh_token()
72
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030073 def refresh_token(self) -> None:
gstepanov94531b82015-02-11 14:20:34 +020074 """Get new token from keystone and update headers"""
75 try:
76 self.keystone.authenticate()
77 self.headers['X-Auth-Token'] = self.keystone.auth_token
78 except exceptions.AuthorizationFailure:
koder aka kdanilov2c473092015-03-29 17:12:13 +030079 raise
gstepanov94531b82015-02-11 14:20:34 +020080
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030081 def do(self, method: str, path: str, params: Dict[str, str]=None) -> Any:
gstepanov94531b82015-02-11 14:20:34 +020082 """Do request. If gets 401 refresh token"""
83 try:
84 return super(KeystoneAuth, self).do(method, path, params)
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030085 except urllib.request.HTTPError as e:
gstepanov94531b82015-02-11 14:20:34 +020086 if e.code == 401:
87 self.refresh_token()
88 return super(KeystoneAuth, self).do(method, path, params)
89 else:
90 raise