blob: 511ec5f28e4892aa62cec22e5fbd8726240525a7 [file] [log] [blame]
kairat_kushaev5c8626d2018-06-09 18:15:15 +04001"""
2Management of Cinder resources
3"""
4
5import ast
6import logging
7
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +02008log = logging.getLogger(__name__)
kairat_kushaev5c8626d2018-06-09 18:15:15 +04009
10
11def __virtual__():
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020012 return 'cinderv3' if 'cinderv3.volume_list' in __salt__ else False # noqa
kairat_kushaev5c8626d2018-06-09 18:15:15 +040013
14
15def _cinder_call(fname, *args, **kwargs):
16 return __salt__['cinderv3.{}'.format(fname)](*args, **kwargs)
17
18
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020019def _resource_present(resource, name, cloud_name, **kwargs):
20 try:
21 method_name = '{}_get_details'.format(resource)
22 exact_resource = _cinder_call(
root08402652018-12-28 15:04:23 +000023 method_name, name, cloud_name=cloud_name, **kwargs
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020024 )[resource]
25 except Exception as e:
26 if 'ResourceNotFound' in repr(e):
27 try:
28 method_name = '{}_create'.format(resource)
29 resp = _cinder_call(
30 method_name, name=name, cloud_name=cloud_name, **kwargs
31 )
32 except Exception as e:
33 log.exception('Cinder {0} create failed with {1}'.
34 format(resource, e))
35 return _failed('create', name, resource)
36 return _succeeded('create', name, resource, resp)
37 elif 'MultipleResourcesFound' in repr(e):
38 return _failed('find', name, resource)
kairat_kushaev5c8626d2018-06-09 18:15:15 +040039 else:
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020040 raise
41
42 to_update = {}
43 if to_update:
44 for key in kwargs:
45 if key not in exact_resource or kwargs[key] != exact_resource[key]:
46 to_update[key] = kwargs[key]
47 try:
48 method_name = '{}_update'.format(resource)
49 resp = _cinder_call(
50 method_name, name, cloud_name=cloud_name, **to_update
51 )
52 except Exception as e:
53 log.exception('Cinder {0} update failed with {1}'.format(resource, e))
54 return _failed('update', name, resource)
55 return _succeeded('update', name, resource, resp)
56 return _succeeded('no_changes', name, resource)
kairat_kushaev5c8626d2018-06-09 18:15:15 +040057
58
root08402652018-12-28 15:04:23 +000059def _resource_absent(resource, name, cloud_name, connection_params=None):
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020060 try:
61 method_name = '{}_get_details'.format(resource)
62 _cinder_call(
root08402652018-12-28 15:04:23 +000063 method_name, name, cloud_name=cloud_name,
64 connection_params=connection_params
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020065 )[resource]
66 except Exception as e:
67 if 'ResourceNotFound' in repr(e):
68 return _succeeded('absent', name, resource)
69 if 'MultipleResourcesFound' in repr(e):
70 return _failed('find', name, resource)
71 try:
72 method_name = '{}_delete'.format(resource)
73 _cinder_call(
root08402652018-12-28 15:04:23 +000074 method_name, name, cloud_name=cloud_name,
75 connection_params=connection_params
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +020076 )
77 except Exception as e:
78 log.error('Cinder delete {0} failed with {1}'.format(resource, e))
79 return _failed('delete', name, resource)
80 return _succeeded('delete', name, resource)
81
82
root08402652018-12-28 15:04:23 +000083def service_enabled(name, binary, cloud_name, connection_params=None):
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +020084 """Ensures that the service is enabled on the host
85
root08402652018-12-28 15:04:23 +000086 :param name: name of a host where service is running
87 :param binary: name of the service have to be run
88 :param connection_params: dictionary with salt internal connection params
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +020089 """
90 changes = {}
Oleksandr Shyshko25513822018-12-07 15:26:56 +000091 ret = []
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +020092
root08402652018-12-28 15:04:23 +000093 services = _cinder_call('service_list', host=name, binary=binary, cloud_name=cloud_name,
94 connection_params=connection_params)['services']
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +020095
Oleksandr Shyshko25513822018-12-07 15:26:56 +000096 disabled_service = [s for s in services if s['status'] == 'disabled']
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +020097
Oleksandr Shyshko25513822018-12-07 15:26:56 +000098 if len(disabled_service):
99 for service in disabled_service:
root08402652018-12-28 15:04:23 +0000100 changes = _cinder_call('service_update', service['host'], binary, 'enable', cloud_name=cloud_name,
101 connection_params=connection_params)
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000102 ret.append(changes)
103 return _succeeded('update', name, binary, {'changes':ret})
104 return _succeeded('no_changes', name, binary)
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200105
106
root08402652018-12-28 15:04:23 +0000107def service_disabled(name, binary, cloud_name, disabled_reason=None, connection_params=None):
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200108 """Ensures that the service is disabled on the host
109
110 :param name: name of a host where service is running
111 :param binary: name of the service have to be disabled
root08402652018-12-28 15:04:23 +0000112 :param connection_params: dictionary with salt internal connection params
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200113 """
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200114 kwargs = {}
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000115 ret = []
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200116
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000117 if disabled_reason:
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200118 kwargs['disabled_reason'] = disabled_reason
119
root08402652018-12-28 15:04:23 +0000120 services = _cinder_call('service_list', host=name, binary=binary, cloud_name=cloud_name,
121 connection_params=connection_params)['services']
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200122
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000123 enabled_services = [s for s in services if s['status'] == 'enabled']
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200124
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000125 if len(enabled_services):
126 for service in enabled_services:
root08402652018-12-28 15:04:23 +0000127 changes = _cinder_call('service_update', service['host'], binary, 'disable',
128 cloud_name=cloud_name, connection_params=connection_params,
129 **kwargs)
Oleksandr Shyshko25513822018-12-07 15:26:56 +0000130 ret.append(changes)
131 return _succeeded('update', name, binary, {'changes':ret})
132 return _succeeded('no_changes', name, binary)
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200133
134
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +0200135def volume_type_present(name, cloud_name, **kwargs):
136 return _resource_present('volume_type', name, cloud_name, **kwargs)
137
138
root08402652018-12-28 15:04:23 +0000139def volume_type_absent(name, cloud_name, connection_params=None):
140 return _resource_absent('volume_type', name, cloud_name, connection_params)
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +0200141
142
143def volume_present(name, cloud_name, size, **kwargs):
144 kwargs.update({
145 'size': size,
146 })
147 return _resource_present('volume', name, cloud_name, **kwargs)
148
149
root08402652018-12-28 15:04:23 +0000150def volume_absent(name, cloud_name, connection_params=None):
151 return _resource_absent('volume', name, cloud_name, connection_params)
kairat_kushaev5c8626d2018-06-09 18:15:15 +0400152
153
root08402652018-12-28 15:04:23 +0000154def volume_type_key_present(name=None, key=None, value=None, cloud_name=None,
155 connection_params=None):
kairat_kushaev5c8626d2018-06-09 18:15:15 +0400156 """
157 Ensures that the extra specs are present on a volume type.
158 """
159 keys = "{u'" + key + "': u'" + value + "'}"
160 keys = ast.literal_eval(keys)
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +0200161 signal_create = _cinder_call('keys_volume_type_set', name, keys=keys,
root08402652018-12-28 15:04:23 +0000162 cloud_name=cloud_name,
163 connection_params=connection_params)
kairat_kushaev5c8626d2018-06-09 18:15:15 +0400164 if signal_create["result"] is True:
165 ret = {
166 'name': name,
167 'changes': keys,
168 'result': True,
169 'comment': 'Volume type "{0}" was updated'.format(name)
170 }
171 else:
172 ret = {
173 'name': name,
174 'changes': {},
175 'result': False,
176 'comment': signal_create.get("comment")
177 }
178 return ret
Oleksiy Petrenkoe38f5a62018-11-21 12:58:07 +0200179
180
181def _succeeded(op, name, resource, changes=None):
182 msg_map = {
183 'create': '{0} {1} created',
184 'delete': '{0} {1} removed',
185 'update': '{0} {1} updated',
186 'no_changes': '{0} {1} is in desired state',
187 'absent': '{0} {1} not present',
188 'resources_moved': '{1} resources were moved from {0}',
189 }
190 changes_dict = {
191 'name': name,
192 'result': True,
193 'comment': msg_map[op].format(resource, name),
194 'changes': changes or {},
195 }
196 return changes_dict
197
198def _failed(op, name, resource):
199 msg_map = {
200 'create': '{0} {1} failed to create',
201 'delete': '{0} {1} failed to delete',
202 'update': '{0} {1} failed to update',
203 'find': '{0} {1} found multiple {0}',
204 'resources_moved': 'failed to move {1} from {0}',
205 }
206 changes_dict = {
207 'name': name,
208 'result': False,
209 'comment': msg_map[op].format(resource, name),
210 'changes': {},
211 }
Oleksandr Shyshko04099ea2018-11-22 16:02:52 +0200212 return changes_dict