blob: 87e3d755eae5bd365e906d77087e3966fd10e256 [file] [log] [blame]
Vladyslav Drokcb8d0fb2018-06-27 19:28:14 +03001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import six
14import logging
15import uuid
16
Oleksiy Petrenko7fb58f82019-02-06 13:12:43 +020017try:
18 import os_client_config
19except ImportError:
20 os_client_config = None
Vladyslav Drokcb8d0fb2018-06-27 19:28:14 +030021from salt import exceptions
22
23
24log = logging.getLogger(__name__)
25
26SERVICE_KEY = 'compute'
27
28
29def get_raw_client(cloud_name):
Oleksiy Petrenko7fb58f82019-02-06 13:12:43 +020030 if not os_client_config:
31 raise exceptions.SaltInvocationError(
32 "Cannot load os-client-config. Please check your environment "
33 "configuration.")
Vladyslav Drokcb8d0fb2018-06-27 19:28:14 +030034 config = os_client_config.OpenStackConfig()
35 cloud = config.get_one_cloud(cloud_name)
36 adapter = cloud.get_session_client(SERVICE_KEY)
37 adapter.version = '2.1'
38 endpoints = []
39 try:
40 access_info = adapter.session.auth.get_access(adapter.session)
41 endpoints = access_info.service_catalog.get_endpoints()
42 except (AttributeError, ValueError) as exc:
43 six.raise_from(exc, exceptions.SaltInvocationError(
44 "Cannot load keystoneauth plugin. Please check your environment "
45 "configuration."))
46 if SERVICE_KEY not in endpoints:
47 raise exceptions.SaltInvocationError("Cannot find compute endpoint in "
48 "environment endpoint list.")
49 return adapter
50
51
52def send(method):
53 def wrap(func):
54 @six.wraps(func)
55 def wrapped_f(*args, **kwargs):
56 cloud_name = kwargs.pop('cloud_name', None)
57 if not cloud_name:
58 raise exceptions.SaltInvocationError(
59 "No cloud_name specified. Please provide cloud_name "
60 "parameter")
61 adapter = get_raw_client(cloud_name)
62 kwarg_keys = list(kwargs.keys())
63 for k in kwarg_keys:
64 if k.startswith('__'):
65 kwargs.pop(k)
66 url, request_kwargs = func(*args, **kwargs)
67 try:
68 response = getattr(adapter, method.lower())(url,
69 **request_kwargs)
70 except Exception as e:
71 log.exception("Error occurred when executing request")
72 return {"result": False,
73 "comment": six.text_type(e),
74 "status_code": getattr(e, "http_status", 500)}
75 return {"result": True,
76 "body": response.json() if response.content else {},
77 "status_code": response.status_code}
78 return wrapped_f
79 return wrap
80
81
82def _check_uuid(val):
83 try:
84 return str(uuid.UUID(val)) == val
85 except (TypeError, ValueError, AttributeError):
86 return False
87
88
89def get_by_name_or_uuid(resource_list, resp_key):
90 def wrap(func):
91 @six.wraps(func)
92 def wrapped_f(*args, **kwargs):
93 if 'name' in kwargs:
94 ref = kwargs.pop('name', None)
95 start_arg = 0
96 else:
97 start_arg = 1
98 ref = args[0]
99 item_id = None
100 if _check_uuid(ref):
101 item_id = ref
102 else:
103 cloud_name = kwargs['cloud_name']
104 resp = resource_list(cloud_name=cloud_name)["body"][resp_key]
105 for item in resp:
106 if item["name"] == ref:
107 if item_id is not None:
108 return {
109 "name": ref,
110 "changes": {},
111 "result": False,
112 "comment": "Multiple resources ({resource}) "
113 "with requested name found ".format(
114 resource=resp_key)}
115 item_id = item["id"]
116 if not item_id:
117 return {
118 "name": ref,
119 "changes": {},
120 "result": False,
121 "comment": "Resource ({resource}) "
122 "with requested name not found ".format(
123 resource=resp_key)}
124 return func(item_id, *args[start_arg:], **kwargs)
125 return wrapped_f
126 return wrap
127
128
129def function_descriptor(action_type, resource_human_readable_name,
130 body_response_key=None):
131 def decorator(fun):
132 fun._action_type = action_type
133 fun._body_response_key = body_response_key or ''
134 fun._resource_human_readable_name = resource_human_readable_name
135 return fun
136 return decorator