blob: 9f2c8b1e0d4cf61f5230e51503075395b6377f66 [file] [log] [blame]
Vasyl Saienko4eda4f22018-04-26 19:30:39 +03001import logging
2import os_client_config
Oleh Hryhorov80691a32019-02-26 13:45:12 +00003import functools
4import time
5
6from keystoneclient import exceptions as ks_exceptions
Vasyl Saienko4eda4f22018-04-26 19:30:39 +03007
8log = logging.getLogger(__name__)
9
10
11class KeystoneException(Exception):
12
13 _msg = "Keystone module exception occured."
14
15 def __init__(self, message=None, **kwargs):
16 super(KeystoneException, self).__init__(message or self._msg)
17
18
19class NoKeystoneEndpoint(KeystoneException):
20 _msg = "Keystone endpoint not found in keystone catalog."
21
22
23class NoAuthPluginConfigured(KeystoneException):
24 _msg = ("You are using keystoneauth auth plugin that does not support "
25 "fetching endpoint list from token (noauth or admin_token).")
26
27
28class NoCredentials(KeystoneException):
29 _msg = "Please provide cloud name present in clouds.yaml."
30
31
32class ResourceNotFound(KeystoneException):
33 _msg = "Uniq resource: {resource} with name: {name} not found."
34
35 def __init__(self, resource, name, **kwargs):
36 super(KeystoneException, self).__init__(
37 self._msg.format(resource=resource, name=name))
38
39
40class MultipleResourcesFound(KeystoneException):
41 _msg = "Multiple resource: {resource} with name: {name} found."
42
43 def __init__(self, resource, name, **kwargs):
44 super(KeystoneException, self).__init__(
45 self._msg.format(resource=resource, name=name))
46
47
48def _get_raw_client(cloud_name):
49 service_type = 'identity'
50 config = os_client_config.OpenStackConfig()
51 cloud = config.get_one_cloud(cloud_name)
52 adapter = cloud.get_session_client(service_type)
53 adapter.version = '3'
54 try:
55 access_info = adapter.session.auth.get_access(adapter.session)
56 endpoints = access_info.service_catalog.get_endpoints()
57 except (AttributeError, ValueError):
58 e = NoAuthPluginConfigured()
59 log.exception('%s' % e)
60 raise e
61 if service_type not in endpoints:
62 if not service_type:
63 e = NoKeystoneEndpoint()
64 log.error('%s' % e)
65 raise e
66 return adapter
67
68
69def send(method, microversion_header=None):
70 def wrap(func):
Oleh Hryhorov80691a32019-02-26 13:45:12 +000071 @functools.wraps(func)
Vasyl Saienko4eda4f22018-04-26 19:30:39 +030072 def wrapped_f(*args, **kwargs):
73 headers = kwargs.pop('headers', {})
74 if kwargs.get('microversion'):
75 headers.setdefault(microversion_header,
76 kwargs.get('microversion'))
77 cloud_name = kwargs.pop('cloud_name')
Oleh Hryhorov80691a32019-02-26 13:45:12 +000078 connect_retries = 30
79 connect_retry_delay = 1
Vasyl Saienko4eda4f22018-04-26 19:30:39 +030080 if not cloud_name:
81 e = NoCredentials()
82 log.error('%s' % e)
83 raise e
Oleh Hryhorov80691a32019-02-26 13:45:12 +000084 adapter = None
85 for i in range(connect_retries):
86 try:
87 adapter = _get_raw_client(cloud_name)
88 except (ks_exceptions.DiscoveryFailure) as e:
89 msg = ("Got exception when determining a suitable "
90 "URL for Keystone plugin. Sleeping for %ss. Attepmpts "
91 "%s of %s")
92 log.error(msg % (connect_retry_delay, i, connect_retries))
93 time.sleep(connect_retry_delay)
94 continue
95 break
96 if not adapter:
97 raise ks_exceptions.DiscoveryFailure("Could not connect to Keystone API to determine a suitable URL for the plugin")
Vasyl Saienko4eda4f22018-04-26 19:30:39 +030098 # Remove salt internal kwargs
99 kwarg_keys = list(kwargs.keys())
100 for k in kwarg_keys:
101 if k.startswith('__'):
102 kwargs.pop(k)
Oleh Hryhorov80691a32019-02-26 13:45:12 +0000103 url, json = func(*args, **kwargs)
104 response = None
105 for i in range(connect_retries):
106 try:
107 response = getattr(adapter, method)(
108 url, connect_retries=connect_retries,
109 json=json)
110 except Exception as e:
111 if not hasattr(e, 'http_status') or (e.http_status >= 500
112 or e.http_status == 0):
113 msg = ("Got retriable exception when contacting "
114 "Keystone API. Sleeping for %ss. Attepmpts "
115 "%s of %s")
116 log.error(msg % (connect_retry_delay, i, connect_retries))
117 time.sleep(connect_retry_delay)
118 continue
119 break
120 if not response or not response.content:
Vasyl Saienko4eda4f22018-04-26 19:30:39 +0300121 return {}
122 try:
123 resp = response.json()
Oleh Hryhorov80691a32019-02-26 13:45:12 +0000124 except ValueError:
Vasyl Saienko4eda4f22018-04-26 19:30:39 +0300125 resp = response.content
126 return resp
127 return wrapped_f
128 return wrap