blob: d403862f32436a3595c8c0bb5e5bb47a5b69e157 [file] [log] [blame]
Oleksiy Petrenko62330b62018-11-20 16:54:02 +02001import functools
Oleksiy Petrenko777d7822018-11-06 13:32:44 +02002import logging
Oleksiy Petrenko62330b62018-11-20 16:54:02 +02003import time
Oleksiy Petrenko777d7822018-11-06 13:32:44 +02004
5
6def __virtual__():
7 return 'designatev2' if 'designatev2.zone_list' in __salt__ else False # noqa
8
9
10log = logging.getLogger(__name__)
11
12
13def _designatev2_call(fname, *args, **kwargs):
14 return __salt__['designatev2.{}'.format(fname)](*args, **kwargs) # noqa
15
16
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020017def _resource_present(resource, name, cloud_name, waiter=None, **kwargs):
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020018 try:
19 method_name = '{}_get_details'.format(resource)
20 exact_resource = _designatev2_call(
21 method_name, name, cloud_name=cloud_name
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020022 )
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020023 except Exception as e:
24 if 'ResourceNotFound' in repr(e):
25 try:
26 method_name = '{}_create'.format(resource)
27 resp = _designatev2_call(
28 method_name, name=name, cloud_name=cloud_name, **kwargs
29 )
30 except Exception as e:
31 log.exception('Designate {0} create failed with {1}'.
Oleksiy Petrenko414b38d2018-11-30 13:36:00 +020032 format(resource, e))
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020033 return _failed('create', name, resource)
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020034 if waiter:
35 if not waiter(name, cloud_name):
36 return _failed('create', name, resource)
37 resp['status'] = 'ACTIVE'
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020038 return _succeeded('create', name, resource, resp)
39 elif 'MultipleResourcesFound' in repr(e):
40 return _failed('find', name, resource)
41 else:
42 raise
43
44 to_update = {}
45 for key in kwargs:
46 if key not in exact_resource or kwargs[key] != exact_resource[key]:
47 to_update[key] = kwargs[key]
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020048 if to_update:
49 try:
50 method_name = '{}_update'.format(resource)
51 resp = _designatev2_call(
52 method_name, name, cloud_name=cloud_name, **to_update
53 )
54 except Exception as e:
55 log.exception('Designate {0} update failed with {1}'.format(resource, e))
56 return _failed('update', name, resource)
57 return _succeeded('update', name, resource, resp)
58 return _succeeded('no_changes', name, resource)
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020059
60
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020061def _resource_absent(resource, name, cloud_name, waiter=None):
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020062 try:
63 method_name = '{}_get_details'.format(resource)
64 _designatev2_call(
65 method_name, name, cloud_name=cloud_name
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020066 )
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020067 except Exception as e:
68 if 'ResourceNotFound' in repr(e):
69 return _succeeded('absent', name, resource)
70 if 'MultipleResourcesFound' in repr(e):
71 return _failed('find', name, resource)
72 try:
73 method_name = '{}_delete'.format(resource)
74 _designatev2_call(
75 method_name, name, cloud_name=cloud_name
76 )
77 except Exception as e:
78 log.error('Designate delete {0} failed with {1}'.format(resource, e))
79 return _failed('delete', name, resource)
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020080 if waiter:
Oleksiy Petrenko414b38d2018-11-30 13:36:00 +020081 if not waiter(name, cloud_name):
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020082 return _failed('delete', name, resource)
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020083 return _succeeded('delete', name, resource)
84
85
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020086def _poll_for_zone(zone_name, cloud_name, checker, retry=5, timeout=2):
87 while retry:
88 zones = _designatev2_call('zone_list', name=zone_name,
89 cloud_name=cloud_name)['zones']
90 if checker(zones):
91 return True
92 time.sleep(timeout)
93 retry -= 1
94 return False
95
96
Oleksiy Petrenko777d7822018-11-06 13:32:44 +020097def zone_present(name, cloud_name, email, **kwargs):
98 kwargs.update({'email': email})
Oleksiy Petrenko62330b62018-11-20 16:54:02 +020099 return _resource_present(
100 'zone', name, cloud_name,
101 functools.partial(
102 _poll_for_zone,
103 checker=lambda zones: len(zones) and
104 zones[0]['status'] == 'ACTIVE',
105 **kwargs.pop('waiter_config', {})),
106 **kwargs)
Oleksiy Petrenko777d7822018-11-06 13:32:44 +0200107
108
Oleksiy Petrenko62330b62018-11-20 16:54:02 +0200109def zone_absent(name, cloud_name, **kwargs):
110 return _resource_absent(
111 'zone', name, cloud_name,
112 waiter=functools.partial(
113 _poll_for_zone, checker=lambda zones: not len(zones),
114 **kwargs.pop('waiter_config', {})))
Oleksiy Petrenko777d7822018-11-06 13:32:44 +0200115
116
117def _succeeded(op, name, resource, changes=None):
118 msg_map = {
119 'create': '{0} {1} created',
120 'delete': '{0} {1} removed',
121 'update': '{0} {1} updated',
122 'no_changes': '{0} {1} is in desired state',
123 'absent': '{0} {1} not present',
124 'resources_moved': '{1} resources were moved from {0}',
125 }
126 changes_dict = {
127 'name': name,
128 'result': True,
129 'comment': msg_map[op].format(resource, name),
130 'changes': changes or {},
131 }
132 return changes_dict
133
134
135def _failed(op, name, resource):
136 msg_map = {
137 'create': '{0} {1} failed to create',
138 'delete': '{0} {1} failed to delete',
139 'update': '{0} {1} failed to update',
140 'find': '{0} {1} found multiple {0}',
141 'resources_moved': 'failed to move {1} from {0}',
142 }
143 changes_dict = {
144 'name': name,
145 'result': False,
146 'comment': msg_map[op].format(resource, name),
147 'changes': {},
148 }
149 return changes_dict