blob: 83e010b1eb938052afe69331ae357315aecaa54b [file] [log] [blame]
Mykyta Karpinfa53b302018-06-13 14:52:16 +03001import logging
Pavlo Shchelokovskyyf65cf0c2019-07-24 22:11:33 +03002import time
Mykyta Karpinfa53b302018-06-13 14:52:16 +03003from uuid import UUID
4
Oleksiy Petrenko24394b32019-02-06 12:58:52 +02005try:
6 import os_client_config
7except ImportError:
8 os_client_config = None
9from salt import exceptions
10
Mykyta Karpinfa53b302018-06-13 14:52:16 +030011log = logging.getLogger(__name__)
12
13
14class GnocchiException(Exception):
15
16 _msg = "Gnocchi module exception occured."
17
18 def __init__(self, message=None, **kwargs):
19 super(GnocchiException, self).__init__(message or self._msg)
20
21
22class NoGnocchiEndpoint(GnocchiException):
23 _msg = "Gnocchi endpoint not found in keystone catalog."
24
25
26class NoAuthPluginConfigured(GnocchiException):
27 _msg = ("You are using keystoneauth auth plugin that does not support "
28 "fetching endpoint list from token (noauth or admin_token).")
29
30
31class NoCredentials(GnocchiException):
32 _msg = "Please provide cloud name present in clouds.yaml."
33
34
35class ResourceNotFound(GnocchiException):
36 _msg = "Uniq resource: {resource} with name: {name} not found."
37
38 def __init__(self, resource, name, **kwargs):
39 super(GnocchiException, self).__init__(
40 self._msg.format(resource=resource, name=name))
41
42
43class MultipleResourcesFound(GnocchiException):
44 _msg = "Multiple resource: {resource} with name: {name} found."
45
46 def __init__(self, resource, name, **kwargs):
47 super(GnocchiException, self).__init__(
48 self._msg.format(resource=resource, name=name))
49
50
51def get_raw_client(cloud_name):
Oleksiy Petrenko24394b32019-02-06 12:58:52 +020052 if not os_client_config:
53 raise exceptions.SaltInvocationError(
54 "Cannot load os-client-config. Please check your environment "
55 "configuration.")
Mykyta Karpinfa53b302018-06-13 14:52:16 +030056 service_type = 'metric'
57 config = os_client_config.OpenStackConfig()
58 cloud = config.get_one_cloud(cloud_name)
Mykyta Karpinfbefb702018-07-10 16:28:22 +030059 api_version = '1'
60 try:
61 # NOTE(pas-ha) for Queens and later,
62 # 'version' kwarg in absent for Pike and older
63 adapter = cloud.get_session_client(service_type, version=api_version)
64 except TypeError:
65 adapter = cloud.get_session_client(service_type)
66 adapter.version = api_version
Mykyta Karpinfa53b302018-06-13 14:52:16 +030067 try:
68 access_info = adapter.session.auth.get_access(adapter.session)
69 endpoints = access_info.service_catalog.get_endpoints()
70 except (AttributeError, ValueError) as exc:
71 log.exception('%s' % exc)
72 e = NoAuthPluginConfigured()
73 log.exception('%s' % e)
74 raise e
75 if service_type not in endpoints:
76 if not service_type:
77 e = NoGnocchiEndpoint()
78 log.error('%s' % e)
79 raise e
80 return adapter
81
82
83def send(method):
84 def wrap(func):
85 def wrapped_f(*args, **kwargs):
Pavlo Shchelokovskyyf65cf0c2019-07-24 22:11:33 +030086 connect_retries = 30
87 connect_retry_delay = 1
Mykyta Karpinfa53b302018-06-13 14:52:16 +030088 cloud_name = kwargs.pop('cloud_name')
89 if not cloud_name:
90 e = NoCredentials()
91 log.error('%s' % e)
92 raise e
93 adapter = get_raw_client(cloud_name)
94 # Remove salt internal kwargs
95 kwarg_keys = list(kwargs.keys())
96 for k in kwarg_keys:
97 if k.startswith('__'):
98 kwargs.pop(k)
99 url, request_kwargs = func(*args, **kwargs)
Pavlo Shchelokovskyyf65cf0c2019-07-24 22:11:33 +0300100 response = None
101 for i in range(connect_retries):
102 try:
103 response = getattr(adapter, method)(
104 url, connect_retries=connect_retries,
105 **request_kwargs)
106 except Exception as e:
107 if not hasattr(e, 'http_status') or (
108 e.http_status >= 500 or e.http_status == 0):
109 msg = ("Got retriable exception when contacting "
110 "Gnocchi API. Sleeping for %s seconds. "
111 "Attepmpts %s of %s")
112 log.error(msg % (connect_retry_delay, i,
113 connect_retries))
114 time.sleep(connect_retry_delay)
115 continue
116 else:
117 raise
118 break
Vasyl Saienko63002242019-07-30 16:48:39 +0300119 try:
120 resp = response.json()
121 except ValueError:
122 resp = response.content
123 return resp
Mykyta Karpinfa53b302018-06-13 14:52:16 +0300124 return wrapped_f
125 return wrap
126
127
128def _check_uuid(val):
129 try:
130 return str(UUID(val)).replace('-', '') == val.replace('-', '')
131 except (TypeError, ValueError, AttributeError):
132 return False
133
134
135def get_by_name_or_uuid(resource_list, resp_key):
136 def wrap(func):
137 def wrapped_f(*args, **kwargs):
138 if 'name' in kwargs:
139 ref = kwargs.pop('name', None)
140 start_arg = 0
141 else:
142 start_arg = 1
143 ref = args[0]
144 if _check_uuid(ref):
145 uuid = ref
146 else:
147 # Then we have name not uuid
148 cloud_name = kwargs['cloud_name']
149 resp = resource_list(
150 name=ref, cloud_name=cloud_name)[resp_key]
151 if len(resp) == 0:
152 raise ResourceNotFound(resp_key, ref)
153 elif len(resp) > 1:
154 raise MultipleResourcesFound(resp_key, ref)
155 uuid = resp[0]['id']
156 return func(uuid, *args[start_arg:], **kwargs)
157 return wrapped_f
158 return wrap