blob: 1e5282f732160f035cac5d139910708c550cf08f [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
Mykyta Karpinfa53b302018-06-13 14:52:16 +0300119 return response.json()
120 return wrapped_f
121 return wrap
122
123
124def _check_uuid(val):
125 try:
126 return str(UUID(val)).replace('-', '') == val.replace('-', '')
127 except (TypeError, ValueError, AttributeError):
128 return False
129
130
131def get_by_name_or_uuid(resource_list, resp_key):
132 def wrap(func):
133 def wrapped_f(*args, **kwargs):
134 if 'name' in kwargs:
135 ref = kwargs.pop('name', None)
136 start_arg = 0
137 else:
138 start_arg = 1
139 ref = args[0]
140 if _check_uuid(ref):
141 uuid = ref
142 else:
143 # Then we have name not uuid
144 cloud_name = kwargs['cloud_name']
145 resp = resource_list(
146 name=ref, cloud_name=cloud_name)[resp_key]
147 if len(resp) == 0:
148 raise ResourceNotFound(resp_key, ref)
149 elif len(resp) > 1:
150 raise MultipleResourcesFound(resp_key, ref)
151 uuid = resp[0]['id']
152 return func(uuid, *args[start_arg:], **kwargs)
153 return wrapped_f
154 return wrap