blob: 4a63d6029eaada36093979b113a621734d730143 [file] [log] [blame]
Vasyl Saienko4eda4f22018-04-26 19:30:39 +03001import logging
2
3
4def __virtual__():
5 return 'keystonev3' if 'keystonev3.endpoint_list' in __salt__ else False # noqa
6
7
8log = logging.getLogger(__name__)
9
10
11def _keystonev3_call(fname, *args, **kwargs):
12 return __salt__['keystonev3.{}'.format(fname)](*args, **kwargs) # noqa
13
14
15def endpoint_present(name, url, interface, service_id, cloud_name, **kwargs):
16
17 service_id = _keystonev3_call(
18 'service_get_details', service_id,
19 cloud_name=cloud_name)['service']['id']
20
21 endpoints = _keystonev3_call(
22 'endpoint_list', name=name, service_id=service_id, interface=interface,
23 cloud_name=cloud_name)['endpoints']
24
25 if not endpoints:
26 try:
27 resp = _keystonev3_call(
28 'endpoint_create', url=url, interface=interface,
29 service_id=service_id, cloud_name=cloud_name, **kwargs
30 )
31 except Exception as e:
32 log.error('Keystone endpoint create failed with {}'.format(e))
33 return _create_failed(name, 'endpoint')
34 return _created(name, 'endpoint', resp)
35 elif len(endpoints) == 1:
36 exact_endpoint = endpoints[0]
37 endpoint_id = exact_endpoint['id']
38 changable = (
39 'url', 'region', 'interface', 'service_id'
40 )
41 to_update = {}
42 to_check = {'url': url}
43 to_check.update(kwargs)
44
45 for key in to_check:
46 if (key in changable and (key not in exact_endpoint or
47 to_check[key] != exact_endpoint[key])):
48 to_update[key] = to_check[key]
49 if to_update:
50 try:
51 resp = _keystonev3_call(
52 'endpoint_update', endpoint_id=endpoint_id,
53 cloud_name=cloud_name, **to_update
54 )
55 except Exception as e:
56 log.error('Keystone endpoint update failed with {}'.format(e))
57 return _update_failed(name, 'endpoint')
58 return _updated(name, 'endpoint', resp)
59 else:
60 return _no_changes(name, 'endpoint')
61 else:
62 return _find_failed(name, 'endpoint')
63
64
65def endpoint_absent(name, cloud_name):
66 endpoints = _keystonev3_call(
67 'endpoint_list', name=name, cloud_name=cloud_name
68 )['endpoints']
69 if not endpoints:
70 return _absent(name, 'endpoint')
71 elif len(endpoints) == 1:
72 try:
73 _keystonev3_call(
74 'endpoint_delete', endpoints[0]['id'], cloud_name=cloud_name
75 )
76 except Exception as e:
77 log.error('Keystone delete endpoint failed with {}'.format(e))
78 return _delete_failed(name, 'endpoint')
79 return _deleted(name, 'endpoint')
80 else:
81 return _find_failed(name, 'endpoint')
82
83
84def service_present(name, type, cloud_name, **kwargs):
85
86 service_id = ''
87
88 try:
89 exact_service = _keystonev3_call(
90 'service_get_details', name,
91 cloud_name=cloud_name)['service']
92 service_id = exact_service['id']
93 except Exception as e:
94 if 'ResourceNotFound' in repr(e):
95 pass
96 else:
97 log.error('Failed to get service {}'.format(e))
98 return _create_failed(name, 'service')
99
100 if not service_id:
101 try:
102 resp = _keystonev3_call(
103 'service_create', name=name, type=type,
104 cloud_name=cloud_name, **kwargs
105 )
106 except Exception as e:
107 log.error('Keystone service create failed with {}'.format(e))
108 return _create_failed(name, 'service')
109 return _created(name, 'service', resp)
110
111 else:
112 changable = ('type', 'enabled', 'description')
113 to_update = {}
114 to_check = {'type': type}
115 to_check.update(kwargs)
116
117 for key in to_check:
118 if (key in changable and (key not in exact_service or
119 to_check[key] != exact_service[key])):
120 to_update[key] = to_check[key]
121 if to_update:
122 try:
123 resp = _keystonev3_call(
124 'service_update', service_id=service_id,
125 cloud_name=cloud_name, **to_update
126 )
127 except Exception as e:
128 log.error('Keystone service update failed with {}'.format(e))
129 return _update_failed(name, 'service')
130 return _updated(name, 'service', resp)
131 else:
132 return _no_changes(name, 'service')
133 return _find_failed(name, 'service')
134
135
136def project_present(name, cloud_name, **kwargs):
137
138 projects = _keystonev3_call(
139 'project_list', name=name, cloud_name=cloud_name
140 )['projects']
141
142 if not projects:
143 try:
144 resp = _keystonev3_call(
145 'project_create', name=name, cloud_name=cloud_name, **kwargs
146 )
147 except Exception as e:
148 log.error('Keystone project create failed with {}'.format(e))
149 return _create_failed(name, 'project')
150 return _created(name, 'project', resp)
151 elif len(projects) == 1:
152 exact_project = projects[0]
153 project_id = exact_project['id']
154 changable = (
155 'is_domain', 'description', 'domain_id', 'enabled',
156 'parent_id', 'tags'
157 )
158 to_update = {}
159
160 for key in kwargs:
161 if (key in changable and (key not in exact_project or
162 kwargs[key] != exact_project[key])):
163 to_update[key] = kwargs[key]
164
165 if to_update:
166 try:
167 resp = _keystonev3_call(
168 'project_update', project_id=project_id,
169 cloud_name=cloud_name, **to_update
170 )
171 except Exception as e:
172 log.error('Keystone project update failed with {}'.format(e))
173 return _update_failed(name, 'project')
174 return _updated(name, 'project', resp)
175 else:
176 return _no_changes(name, 'project')
177 else:
178 return _find_failed(name, 'project')
179
180
181def user_present(name, cloud_name, password_reset=False, **kwargs):
182
183 users = _keystonev3_call(
184 'user_list', name=name, cloud_name=cloud_name
185 )['users']
186
187 if 'default_project_id' in kwargs:
188 kwargs['default_project_id'] = _keystonev3_call(
189 'project_get_details', kwargs['default_project_id'],
190 cloud_name=cloud_name)['project']['id']
191
192 if not users:
193 try:
194 resp = _keystonev3_call(
195 'user_create', name=name, cloud_name=cloud_name, **kwargs
196 )
197 except Exception as e:
198 log.error('Keystone user create failed with {}'.format(e))
199 return _create_failed(name, 'user')
200 return _created(name, 'user', resp)
201
202 elif len(users) == 1:
203 exact_user = users[0]
204 user_id = exact_user['id']
205 changable = (
206 'default_project_id', 'domain_id', 'enabled', 'email'
207 )
208 if password_reset:
209 changable += ('password',)
210 to_update = {}
211
212 for key in kwargs:
213 if (key in changable and (key not in exact_user or
214 kwargs[key] != exact_user[key])):
215 to_update[key] = kwargs[key]
216
217 if to_update:
218 log.info('Updating keystone user {} with: {}'.format(user_id,
219 to_update))
220 try:
221 resp = _keystonev3_call(
222 'user_update', user_id=user_id,
223 cloud_name=cloud_name, **to_update
224 )
225 except Exception as e:
226 log.error('Keystone user update failed with {}'.format(e))
227 return _update_failed(name, 'user')
228 return _updated(name, 'user', resp)
229 else:
230 return _no_changes(name, 'user')
231 else:
232 return _find_failed(name, 'user')
233
234
235def user_role_assigned(name, role_id, cloud_name, project_id=None,
236 domain_id=None, role_domain_id=None, **kwargs):
237
238 user_id = _keystonev3_call(
239 'user_get_details', name,
240 cloud_name=cloud_name)['user']['id']
241
242 if project_id:
243 project_id = _keystonev3_call(
244 'project_get_details', project_id,
245 cloud_name=cloud_name)['project']['id']
246
247# TODO: Add when domain support is added.
248# if domain_id and not uuidutils.is_uuid_like(domain_id):
249# domain_id = _keystonev3_call(
250# 'domain_get_details', domain_id,
251# cloud_name=cloud_name)['domain']['id']
252
253# if role_domain_id and not uuidutils.is_uuid_like(role_domain_id):
254# role_domain_id = _keystonev3_call(
255# 'domain_get_details', role_domain_id,
256# cloud_name=cloud_name)['domain']['id']
257
258 if role_id:
259 role_id = _keystonev3_call(
260 'role_get_details', role_id, domain_id=role_domain_id,
261 cloud_name=cloud_name)['role']['id']
262
263 req_kwargs = {'role.id': role_id, 'user.id': user_id,
264 'cloud_name': cloud_name}
265 if domain_id:
266 req_kwargs['domain_id'] = domain_id
267 if project_id:
268 req_kwargs['project_id'] = project_id
269
270 role_assignments = _keystonev3_call(
271 'role_assignment_list', **req_kwargs)['role_assignments']
272
273 req_kwargs = {'cloud_name': cloud_name, 'user_id': user_id,
274 'role_id': role_id}
275 if domain_id:
276 req_kwargs['domain_id'] = domain_id
277 if project_id:
278 req_kwargs['project_id'] = project_id
279
280 if not role_assignments:
281 try:
282 resp = _keystonev3_call('role_add', **req_kwargs)
283 except Exception as e:
284 log.error('Keystone user role assignment with {}'.format(e))
285 return _create_failed(name, 'user_role_assignment')
286 # We check for exact assignment when did role_assignment_list
287 # on this stage we already just assigned role if it was missed.
288 return _created(name, 'user_role_assignment', resp)
289 return _no_changes(name, 'user_role_assignment')
290
291
292def role_present(name, cloud_name, **kwargs):
293
294 roles = _keystonev3_call(
295 'role_list', name=name, cloud_name=cloud_name
296 )['roles']
297
298 if 'domain_id' in kwargs:
299 kwargs['domain_id'] = _keystonev3_call(
300 'domain_get_details', kwargs['domain_id'],
301 cloud_name=cloud_name)['domains']
302
303 if not roles:
304 try:
305 resp = _keystonev3_call(
306 'role_create', name=name, cloud_name=cloud_name, **kwargs
307 )
308 except Exception as e:
309 log.error('Keystone role create failed with {}'.format(e))
310 return _create_failed(name, 'role')
311 return _created(name, 'role', resp)
312 elif len(roles) == 1:
313 exact_role = roles[0]
314 role_id = exact_role['id']
315 changable = ('domain_id')
316 to_update = {}
317
318 for key in kwargs:
319 if (key in changable and (key not in exact_role or
320 kwargs[key] != exact_role[key])):
321 to_update[key] = kwargs[key]
322
323 if to_update:
324 try:
325 resp = _keystonev3_call(
326 'role_update', role_id=role_id,
327 cloud_name=cloud_name, **to_update
328 )
329 except Exception as e:
330 log.error('Keystone role update failed with {}'.format(e))
331 return _update_failed(name, 'role')
332 return _updated(name, 'role', resp)
333 else:
334 return _no_changes(name, 'role')
335 else:
336 return _find_failed(name, 'role')
337
338
339def _created(name, resource, resource_definition):
340 changes_dict = {
341 'name': name,
342 'changes': resource_definition,
343 'result': True,
344 'comment': '{}{} created'.format(resource, name)
345 }
346 return changes_dict
347
348
349def _updated(name, resource, resource_definition):
350 changes_dict = {
351 'name': name,
352 'changes': resource_definition,
353 'result': True,
354 'comment': '{}{} updated'.format(resource, name)
355 }
356 return changes_dict
357
358
359def _no_changes(name, resource):
360 changes_dict = {
361 'name': name,
362 'changes': {},
363 'result': True,
364 'comment': '{}{} is in desired state'.format(resource, name)
365 }
366 return changes_dict
367
368
369def _deleted(name, resource):
370 changes_dict = {
371 'name': name,
372 'changes': {},
373 'result': True,
374 'comment': '{}{} removed'.format(resource, name)
375 }
376 return changes_dict
377
378
379def _absent(name, resource):
380 changes_dict = {'name': name,
381 'changes': {},
382 'comment': '{0} {1} not present'.format(resource, name),
383 'result': True}
384 return changes_dict
385
386
387def _delete_failed(name, resource):
388 changes_dict = {'name': name,
389 'changes': {},
390 'comment': '{0} {1} failed to delete'.format(resource,
391 name),
392 'result': False}
393 return changes_dict
394
395
396def _create_failed(name, resource):
397 changes_dict = {'name': name,
398 'changes': {},
399 'comment': '{0} {1} failed to create'.format(resource,
400 name),
401 'result': False}
402 return changes_dict
403
404
405def _update_failed(name, resource):
406 changes_dict = {'name': name,
407 'changes': {},
408 'comment': '{0} {1} failed to update'.format(resource,
409 name),
410 'result': False}
411 return changes_dict
412
413
414def _find_failed(name, resource):
415 changes_dict = {
416 'name': name,
417 'changes': {},
418 'comment': '{0} {1} found multiple {0}'.format(resource, name),
419 'result': False,
420 }
421 return changes_dict