blob: d08a750fe8ba803934b9e3294fb20ac0fa36b61a [file] [log] [blame]
import functools
import logging
import time
def __virtual__():
return 'designatev2' if 'designatev2.zone_list' in __salt__ else False # noqa
log = logging.getLogger(__name__)
def _designatev2_call(fname, *args, **kwargs):
return __salt__['designatev2.{}'.format(fname)](*args, **kwargs) # noqa
def _resource_present(resource, name, cloud_name, waiter=None, **kwargs):
try:
method_name = '{}_get_details'.format(resource)
exact_resource = _designatev2_call(
method_name, name, cloud_name=cloud_name
)
except Exception as e:
if 'ResourceNotFound' in repr(e):
try:
method_name = '{}_create'.format(resource)
resp = _designatev2_call(
method_name, name=name, cloud_name=cloud_name, **kwargs
)
except Exception as e:
log.exception('Designate {0} create failed with {1}'.
format(resource, e))
return _failed('create', name, resource)
if waiter:
if not waiter(name, cloud_name):
return _failed('create', name, resource)
resp['status'] = 'ACTIVE'
return _succeeded('create', name, resource, resp)
elif 'MultipleResourcesFound' in repr(e):
return _failed('find', name, resource)
else:
raise
to_update = {}
for key in kwargs:
if key not in exact_resource or kwargs[key] != exact_resource[key]:
to_update[key] = kwargs[key]
if to_update:
try:
method_name = '{}_update'.format(resource)
resp = _designatev2_call(
method_name, name, cloud_name=cloud_name, **to_update
)
except Exception as e:
log.exception('Designate {0} update failed with {1}'.format(resource, e))
return _failed('update', name, resource)
return _succeeded('update', name, resource, resp)
return _succeeded('no_changes', name, resource)
def _resource_absent(resource, name, cloud_name, waiter=None):
try:
method_name = '{}_get_details'.format(resource)
_designatev2_call(
method_name, name, cloud_name=cloud_name
)
except Exception as e:
if 'ResourceNotFound' in repr(e):
return _succeeded('absent', name, resource)
if 'MultipleResourcesFound' in repr(e):
return _failed('find', name, resource)
try:
method_name = '{}_delete'.format(resource)
_designatev2_call(
method_name, name, cloud_name=cloud_name
)
except Exception as e:
log.error('Designate delete {0} failed with {1}'.format(resource, e))
return _failed('delete', name, resource)
if waiter:
if not waiter:
return _failed('delete', name, resource)
return _succeeded('delete', name, resource)
def _poll_for_zone(zone_name, cloud_name, checker, retry=18, timeout=10):
while retry:
zones = _designatev2_call('zone_list', name=zone_name,
cloud_name=cloud_name)['zones']
if checker(zones):
return True
time.sleep(timeout)
retry -= 1
return False
def zone_present(name, cloud_name, email, **kwargs):
kwargs.update({'email': email})
return _resource_present(
'zone', name, cloud_name,
functools.partial(
_poll_for_zone,
checker=lambda zones: len(zones) and
zones[0]['status'] == 'ACTIVE',
**kwargs.pop('waiter_config', {})),
**kwargs)
def zone_absent(name, cloud_name, **kwargs):
return _resource_absent(
'zone', name, cloud_name,
waiter=functools.partial(
_poll_for_zone, checker=lambda zones: not len(zones),
**kwargs.pop('waiter_config', {})))
def _succeeded(op, name, resource, changes=None):
msg_map = {
'create': '{0} {1} created',
'delete': '{0} {1} removed',
'update': '{0} {1} updated',
'no_changes': '{0} {1} is in desired state',
'absent': '{0} {1} not present',
'resources_moved': '{1} resources were moved from {0}',
}
changes_dict = {
'name': name,
'result': True,
'comment': msg_map[op].format(resource, name),
'changes': changes or {},
}
return changes_dict
def _failed(op, name, resource):
msg_map = {
'create': '{0} {1} failed to create',
'delete': '{0} {1} failed to delete',
'update': '{0} {1} failed to update',
'find': '{0} {1} found multiple {0}',
'resources_moved': 'failed to move {1} from {0}',
}
changes_dict = {
'name': name,
'result': False,
'comment': msg_map[op].format(resource, name),
'changes': {},
}
return changes_dict