blob: 2505f68cb374a2e2d2561f721317386317837d78 [file] [log] [blame]
Oleksiy Petrenkoa5eb0602018-07-26 15:12:25 +03001import logging
2
3log = logging.getLogger(__name__)
4
5
6def __virtual__():
7 return 'ironicv1' if 'ironicv1.node_list' in __salt__ else False
8
9
10def _ironicv1_call(fname, *args, **kwargs):
11 return __salt__['ironicv1.{}'.format(fname)](*args, **kwargs)
12
13
14def node_present(name, cloud_name, driver, **kwargs):
15 resource = 'node'
16 microversion = kwargs.pop('microversion', '1.16')
17 try:
18 method_name = '{}_get_details'.format(resource)
19 exact_resource = _ironicv1_call(
20 method_name, name, cloud_name=cloud_name,
21 microversion=microversion
22 )
23 except Exception as e:
24 if 'Not Found' in str(e):
25 try:
26 method_name = '{}_create'.format(resource)
27 resp = _ironicv1_call(
28 method_name, driver, name=name, cloud_name=cloud_name,
29 microversion=microversion,
30 **kwargs
31 )
32 except Exception as e:
33 log.exception('Ironic {0} create failed with {1}'.
34 format('node', e))
35 return _failed('create', name, resource)
36 return _succeeded('create', name, resource, resp)
Vladyslav Drok0ad5d012018-10-05 17:51:34 +030037 raise
Oleksiy Petrenkoa5eb0602018-07-26 15:12:25 +030038
39 to_change = []
40 for prop in kwargs:
41 path = prop.replace('~', '~0').replace('/', '~1')
42 if prop in exact_resource:
43 if exact_resource[prop] != kwargs[prop]:
44 to_change.append({
45 'op': 'replace',
46 'path': '/{}'.format(path),
47 'value': kwargs[prop],
48 })
49 else:
50 to_change.append({
51 'op': 'add',
52 'path': '/{}'.format(path),
53 'value': kwargs[prop],
54 })
55 if to_change:
56 try:
57 method_name = '{}_update'.format(resource)
58 resp = _ironicv1_call(
59 method_name, name, properties=to_change,
60 microversion=microversion, cloud_name=cloud_name,
61 )
62 except Exception as e:
63 log.exception(
64 'Ironic {0} update failed with {1}'.format(resource, e))
65 return _failed('update', name, resource)
66 return _succeeded('update', name, resource, resp)
67 return _succeeded('no_changes', name, resource)
68
69
70def node_absent(name, cloud_name, **kwargs):
71 resource = 'node'
72 microversion = kwargs.pop('microversion', '1.16')
73 try:
74 method_name = '{}_get_details'.format(resource)
75 _ironicv1_call(
76 method_name, name, cloud_name=cloud_name,
77 microversion=microversion
78 )
79 except Exception as e:
80 if 'Not Found' in str(e):
81 return _succeeded('absent', name, resource)
82 try:
83 method_name = '{}_delete'.format(resource)
84 _ironicv1_call(
85 method_name, name, cloud_name=cloud_name, microversion=microversion
86 )
87 except Exception as e:
88 log.error('Ironic delete {0} failed with {1}'.format(resource, e))
89 return _failed('delete', name, resource)
90 return _succeeded('delete', name, resource)
91
92
93def port_present(name, cloud_name, node, address, **kwargs):
94 resource = 'port'
95 microversion = kwargs.pop('microversion', '1.16')
96 method_name = '{}_list'.format(resource)
97 exact_resource = _ironicv1_call(
98 method_name, node=node, address=address,
99 cloud_name=cloud_name, microversion=microversion
100 )['ports']
101 if len(exact_resource) == 0:
102 try:
103 node_uuid = _ironicv1_call(
104 'node_get_details', node, cloud_name=cloud_name,
105 microversion=microversion
106 )['uuid']
107 except Exception as e:
108 return _failed('create', node, "port's node")
109 try:
110 method_name = '{}_create'.format(resource)
111 resp = _ironicv1_call(
112 method_name, node_uuid, address, cloud_name=cloud_name,
113 microversion=microversion, **kwargs)
114 except Exception as e:
115 log.exception('Ironic {0} create failed with {1}'.
116 format('node', e))
117 return _failed('create', name, resource)
118 return _succeeded('create', name, resource, resp)
119 if len(exact_resource) == 1:
120 exact_resource = exact_resource[0]
121 to_change = []
122 for prop in kwargs:
123 path = prop.replace('~', '~0').replace('/', '~1')
124 if prop in exact_resource:
125 if exact_resource[prop] != kwargs[prop]:
126 to_change.append({
127 'op': 'replace',
128 'path': '/{}'.format(path),
129 'value': kwargs[prop],
130 })
131 else:
132 to_change.append({
133 'op': 'add',
134 'path': '/{}'.format(path),
135 'value': kwargs[prop],
136 })
137 if to_change:
138 try:
139 method_name = '{}_update'.format(resource)
140 resp = _ironicv1_call(
Oleksiy Petrenkobf66fbd2018-12-17 19:04:47 +0200141 method_name, exact_resource['uuid'], properties=to_change,
Oleksiy Petrenkoa5eb0602018-07-26 15:12:25 +0300142 microversion=microversion, cloud_name=cloud_name,
143 )
144 except Exception as e:
145 log.exception(
146 'Ironic {0} update failed with {1}'.format(resource, e))
147 return _failed('update', name, resource)
148 return _succeeded('update', name, resource, resp)
149 return _succeeded('no_changes', name, resource)
150 else:
151 return _failed('find', name, resource)
152
153
154def port_absent(name, cloud_name, node, address, **kwargs):
155 resource = 'port'
156 microversion = kwargs.pop('microversion', '1.16')
157 method_name = '{}_list'.format(resource)
158 exact_resource = _ironicv1_call(
159 method_name, node=node, address=address,
160 cloud_name=cloud_name, microversion=microversion
161 )['ports']
162 if len(exact_resource) == 0:
163 return _succeeded('absent', name, resource)
164 elif len(exact_resource) == 1:
165 port_id = exact_resource[0]['uuid']
166 try:
167 method_name = '{}_delete'.format(resource)
168 _ironicv1_call(
169 method_name, port_id, cloud_name=cloud_name,
170 microversion=microversion
171 )
172 except Exception as e:
173 log.error('Ironic delete {0} failed with {1}'.format(resource, e))
174 return _failed('delete', name, resource)
175 return _succeeded('delete', name, resource)
176 else:
177 return _failed('find', name, resource)
178
179
Oleksiy Petrenkobf66fbd2018-12-17 19:04:47 +0200180def volume_connector_present(name, node, volume_type, cloud_name,
181 **kwargs):
182 """
183
184 :param name: alias for connector_id because of how salt works
185 :param node: node_ident
186 :param volume_type: type of volume
187 """
188 resource = 'volume_connector'
189 microversion = kwargs.pop('microversion', '1.32')
190 method_name = '{}_list'.format(resource)
191 exact_resource = filter(
192 lambda data: data['connector_id'] == name,
193 _ironicv1_call(method_name, node=node,
194 cloud_name=cloud_name,
195 microversion=microversion)['connectors'])
196 if len(exact_resource) == 0:
197 try:
198 method_name = 'node_get_details'
199 node_uuid = _ironicv1_call(
200 method_name, node, cloud_name=cloud_name,
201 microversion=microversion
202 )['uuid']
203 except Exception as e:
204 if 'Not Found' in str(e):
205 return _failed('not_found', node, 'node')
206 raise
207 try:
208 method_name = '{}_create'.format(resource)
209 resp = _ironicv1_call(
210 method_name, node_uuid, volume_type, name,
211 cloud_name=cloud_name, microversion=microversion, **kwargs)
212 except Exception as e:
213 log.exception('Ironic {0} create failed with {1}'.
214 format('node', e))
215 return _failed('create', name, resource)
216 return _succeeded('create', name, resource, resp)
217 elif len(exact_resource) == 1:
218 exact_resource = exact_resource[0]
219 to_change = []
220 for prop in kwargs:
221 path = prop.replace('~', '~0').replace('/', '~1')
222 if prop in exact_resource:
223 if exact_resource[prop] != kwargs[prop]:
224 to_change.append({
225 'op': 'replace',
226 'path': '/{}'.format(path),
227 'value': kwargs[prop],
228 })
229 else:
230 to_change.append({
231 'op': 'add',
232 'path': '/{}'.format(path),
233 'value': kwargs[prop],
234 })
235 if to_change:
236 try:
237 method_name = '{}_update'.format(resource)
238 resp = _ironicv1_call(
239 method_name, exact_resource['uuid'], properties=to_change,
240 microversion=microversion, cloud_name=cloud_name,
241 )
242 except Exception as e:
243 log.exception(
244 'Ironic {0} update failed with {1}'.format(resource,
245 e))
246 return _failed('update', name, resource)
247 return _succeeded('update', name, resource, resp)
248 return _succeeded('no_changes', name, resource)
249 else:
250 return _failed('find', name, resource)
251
252
253def volume_connector_absent(name, cloud_name, node, **kwargs):
254 """
255
256 :param name: alias for connector_id because of how salt works
257 :param node: node ident
258 """
259 resource = 'volume_connector'
260 microversion = kwargs.pop('microversion', '1.32')
261 method_name = '{}_list'.format(resource)
262 exact_resource = filter(
263 lambda data: data['connector_id'] == name,
264 _ironicv1_call(method_name, node=node,
265 cloud_name=cloud_name,
266 microversion=microversion)['connectors'])
267 if len(exact_resource) == 0:
268 return _succeeded('absent', name, resource)
269 elif len(exact_resource) == 1:
270 connector_uuid = exact_resource[0]['uuid']
271 try:
272 method_name = '{}_delete'.format(resource)
273 _ironicv1_call(
274 method_name, connector_uuid, cloud_name=cloud_name,
275 microversion=microversion
276 )
277 except Exception as e:
278 log.error('Ironic delete {0} failed with {1}'.format(resource, e))
279 return _failed('delete', name, resource)
280 return _succeeded('delete', name, resource)
281 else:
282 return _failed('find', name, resource)
283
284
Oleksiy Petrenkoa5eb0602018-07-26 15:12:25 +0300285def _succeeded(op, name, resource, changes=None):
286 msg_map = {
287 'create': '{0} {1} created',
288 'delete': '{0} {1} removed',
289 'update': '{0} {1} updated',
290 'no_changes': '{0} {1} is in desired state',
291 'absent': '{0} {1} not present'
292 }
293 changes_dict = {
294 'name': name,
295 'result': True,
296 'comment': msg_map[op].format(resource, name),
297 'changes': changes or {},
298 }
299 return changes_dict
300
301
302def _failed(op, name, resource):
303 msg_map = {
304 'create': '{0} {1} failed to create',
305 'delete': '{0} {1} failed to delete',
306 'update': '{0} {1} failed to update',
Oleksiy Petrenkobf66fbd2018-12-17 19:04:47 +0200307 'find': '{0} {1} found multiple {0}',
308 'not found': '{0} {1} not found',
Oleksiy Petrenkoa5eb0602018-07-26 15:12:25 +0300309 }
310 changes_dict = {
311 'name': name,
312 'result': False,
313 'comment': msg_map[op].format(resource, name),
314 'changes': {},
315 }
316 return changes_dict