blob: 511ec5f28e4892aa62cec22e5fbd8726240525a7 [file] [log] [blame]
"""
Management of Cinder resources
"""
import ast
import logging
log = logging.getLogger(__name__)
def __virtual__():
return 'cinderv3' if 'cinderv3.volume_list' in __salt__ else False # noqa
def _cinder_call(fname, *args, **kwargs):
return __salt__['cinderv3.{}'.format(fname)](*args, **kwargs)
def _resource_present(resource, name, cloud_name, **kwargs):
try:
method_name = '{}_get_details'.format(resource)
exact_resource = _cinder_call(
method_name, name, cloud_name=cloud_name, **kwargs
)[resource]
except Exception as e:
if 'ResourceNotFound' in repr(e):
try:
method_name = '{}_create'.format(resource)
resp = _cinder_call(
method_name, name=name, cloud_name=cloud_name, **kwargs
)
except Exception as e:
log.exception('Cinder {0} create failed with {1}'.
format(resource, e))
return _failed('create', name, resource)
return _succeeded('create', name, resource, resp)
elif 'MultipleResourcesFound' in repr(e):
return _failed('find', name, resource)
else:
raise
to_update = {}
if to_update:
for key in kwargs:
if key not in exact_resource or kwargs[key] != exact_resource[key]:
to_update[key] = kwargs[key]
try:
method_name = '{}_update'.format(resource)
resp = _cinder_call(
method_name, name, cloud_name=cloud_name, **to_update
)
except Exception as e:
log.exception('Cinder {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, connection_params=None):
try:
method_name = '{}_get_details'.format(resource)
_cinder_call(
method_name, name, cloud_name=cloud_name,
connection_params=connection_params
)[resource]
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)
_cinder_call(
method_name, name, cloud_name=cloud_name,
connection_params=connection_params
)
except Exception as e:
log.error('Cinder delete {0} failed with {1}'.format(resource, e))
return _failed('delete', name, resource)
return _succeeded('delete', name, resource)
def service_enabled(name, binary, cloud_name, connection_params=None):
"""Ensures that the service is enabled on the host
:param name: name of a host where service is running
:param binary: name of the service have to be run
:param connection_params: dictionary with salt internal connection params
"""
changes = {}
ret = []
services = _cinder_call('service_list', host=name, binary=binary, cloud_name=cloud_name,
connection_params=connection_params)['services']
disabled_service = [s for s in services if s['status'] == 'disabled']
if len(disabled_service):
for service in disabled_service:
changes = _cinder_call('service_update', service['host'], binary, 'enable', cloud_name=cloud_name,
connection_params=connection_params)
ret.append(changes)
return _succeeded('update', name, binary, {'changes':ret})
return _succeeded('no_changes', name, binary)
def service_disabled(name, binary, cloud_name, disabled_reason=None, connection_params=None):
"""Ensures that the service is disabled on the host
:param name: name of a host where service is running
:param binary: name of the service have to be disabled
:param connection_params: dictionary with salt internal connection params
"""
kwargs = {}
ret = []
if disabled_reason:
kwargs['disabled_reason'] = disabled_reason
services = _cinder_call('service_list', host=name, binary=binary, cloud_name=cloud_name,
connection_params=connection_params)['services']
enabled_services = [s for s in services if s['status'] == 'enabled']
if len(enabled_services):
for service in enabled_services:
changes = _cinder_call('service_update', service['host'], binary, 'disable',
cloud_name=cloud_name, connection_params=connection_params,
**kwargs)
ret.append(changes)
return _succeeded('update', name, binary, {'changes':ret})
return _succeeded('no_changes', name, binary)
def volume_type_present(name, cloud_name, **kwargs):
return _resource_present('volume_type', name, cloud_name, **kwargs)
def volume_type_absent(name, cloud_name, connection_params=None):
return _resource_absent('volume_type', name, cloud_name, connection_params)
def volume_present(name, cloud_name, size, **kwargs):
kwargs.update({
'size': size,
})
return _resource_present('volume', name, cloud_name, **kwargs)
def volume_absent(name, cloud_name, connection_params=None):
return _resource_absent('volume', name, cloud_name, connection_params)
def volume_type_key_present(name=None, key=None, value=None, cloud_name=None,
connection_params=None):
"""
Ensures that the extra specs are present on a volume type.
"""
keys = "{u'" + key + "': u'" + value + "'}"
keys = ast.literal_eval(keys)
signal_create = _cinder_call('keys_volume_type_set', name, keys=keys,
cloud_name=cloud_name,
connection_params=connection_params)
if signal_create["result"] is True:
ret = {
'name': name,
'changes': keys,
'result': True,
'comment': 'Volume type "{0}" was updated'.format(name)
}
else:
ret = {
'name': name,
'changes': {},
'result': False,
'comment': signal_create.get("comment")
}
return ret
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