blob: 77c1d5bcac87c6f681d58e869c307c16a323b475 [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 kdanilov3b4da8b2016-10-17 00:17:53 +030017 def __init__(self, root_url:str, headers:Dict[str, str]=None, echo: bool=False):
gstepanov94531b82015-02-11 14:20:34 +020018 """
19 """
20 if root_url.endswith('/'):
21 self.root_url = root_url[:-1]
22 else:
23 self.root_url = root_url
24
25 self.headers = headers if headers is not None else {}
26 self.echo = echo
27
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030028 def do(self, method: str, path: str, params: Dict[str, str]=None) -> Any:
gstepanov94531b82015-02-11 14:20:34 +020029 if path.startswith('/'):
30 url = self.root_url + path
31 else:
32 url = self.root_url + '/' + path
33
34 if method == 'get':
35 assert params == {} or params is None
36 data_json = None
37 else:
38 data_json = json.dumps(params)
39
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030040 request = urllib.request.Request(url,
41 data=data_json,
42 headers=self.headers)
gstepanov94531b82015-02-11 14:20:34 +020043 if data_json is not None:
44 request.add_header('Content-Type', 'application/json')
45
46 request.get_method = lambda: method.upper()
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030047 response = urllib.request.urlopen(request)
gstepanov94531b82015-02-11 14:20:34 +020048
gstepanov94531b82015-02-11 14:20:34 +020049 if response.code < 200 or response.code > 209:
50 raise IndexError(url)
51
52 content = response.read()
53
54 if '' == content:
55 return None
56
57 return json.loads(content)
58
59 def __getattr__(self, name):
60 if name in self.allowed_methods:
61 return partial(self.do, name)
62 raise AttributeError(name)
63
64
65class KeystoneAuth(Urllib2HTTP):
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030066 def __init__(self, root_url: str, creds: Dict[str, str], headers: Dict[str, str]=None, echo: bool=False,
67 admin_node_ip: str=None):
gstepanov94531b82015-02-11 14:20:34 +020068 super(KeystoneAuth, self).__init__(root_url, headers, echo)
69 self.keystone_url = "http://{0}:5000/v2.0".format(admin_node_ip)
70 self.keystone = keystoneclient(
71 auth_url=self.keystone_url, **creds)
72 self.refresh_token()
73
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030074 def refresh_token(self) -> None:
gstepanov94531b82015-02-11 14:20:34 +020075 """Get new token from keystone and update headers"""
76 try:
77 self.keystone.authenticate()
78 self.headers['X-Auth-Token'] = self.keystone.auth_token
79 except exceptions.AuthorizationFailure:
koder aka kdanilov2c473092015-03-29 17:12:13 +030080 raise
gstepanov94531b82015-02-11 14:20:34 +020081
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030082 def do(self, method: str, path: str, params: Dict[str, str]=None) -> Any:
gstepanov94531b82015-02-11 14:20:34 +020083 """Do request. If gets 401 refresh token"""
84 try:
85 return super(KeystoneAuth, self).do(method, path, params)
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030086 except urllib.request.HTTPError as e:
gstepanov94531b82015-02-11 14:20:34 +020087 if e.code == 401:
88 self.refresh_token()
89 return super(KeystoneAuth, self).do(method, path, params)
90 else:
91 raise