Add state to upload image to volume and rework result creation
Change-Id: Ic30af6a0211a4fb3dd8993c80e25c6b00d632ba0
Related-Issue: PROD-25393(PROD:25393)
diff --git a/_states/glancev2.py b/_states/glancev2.py
index 2250e25..5b149f2 100644
--- a/_states/glancev2.py
+++ b/_states/glancev2.py
@@ -20,9 +20,14 @@
return __salt__['glancev2.{}'.format(fname)](*args, **kwargs)
-def image_present(name, cloud_name, location, image_properties,
+def _cinderv3_call(fname, *args, **kwargs):
+ return __salt__['cinderv3.{}'.format(fname)](*args, **kwargs)
+
+
+def image_present(name, cloud_name, location=None, image_properties=None,
import_from_format='raw', timeout=30,
- sleep_time=5, checksum=None):
+ sleep_time=5, checksum=None,
+ volume_name=None, volume_kwargs=None):
"""
Creates a task to import an image
@@ -50,6 +55,10 @@
:param timeout: (optional) Time for task to download image
:param sleep_time: (optional) Timer countdown
:param checksum: (optional) checksum of the image to verify it
+ :param volume_name: (optional) name of the volume if specified the command
+ works like openstack image create --volume
+ :param volume_kwargs: (optional) if volume_name is specified, this will be
+ used as arguments to image_upload_volume
"""
try:
exact_image = _glancev2_call(
@@ -57,86 +66,134 @@
)
except Exception as e:
if 'ResourceNotFound' in repr(e):
- image_properties['name'] = name
- task_params = {"import_from": location,
- "import_from_format": import_from_format,
- "image_properties": image_properties
- }
- # Try create task
- try:
- task = _glancev2_call(
- 'task_create', task_type='import', task_input=task_params,
- cloud_name=cloud_name
- )
- except Exception as e:
- log.error(
- 'Glance image create failed on create task with {}'.format(
- e)
- )
- return _create_failed(name, 'image_task')
- while timeout > 0:
- if task['status'] == 'success':
- break
- elif task['status'] == 'failure':
- log.error('Glance task failed to complete')
- return _create_failed(name, 'image')
- else:
- timeout -= sleep_time
- time.sleep(sleep_time)
- # Check task status again
+ if volume_name:
+ try:
+ _cinderv3_call(
+ 'volume_get_details', volume_name,
+ cloud_name=cloud_name
+ )
+ except Exception as e:
+ if 'ResourceNotFound' in repr(e):
+ return _failed('none', volume_name, 'volume')
+ elif 'MultipleResourcesFound' in repr(e):
+ return _failed('find', volume_name, 'volume')
+ else:
+ raise
+ if not volume_kwargs:
+ volume_kwargs = {}
+ try:
+ resp = _cinderv3_call(
+ 'image_upload_volume', volume_name, image_name=name,
+ cloud_name=cloud_name, **volume_kwargs)
+ except Exception as e:
+ log.error(
+ 'Glance create image with '
+ 'volume failed with {}'.format(e))
+ return _failed('create', name, 'image')
+ image_status = resp['os-volume_upload_image']['status']
+ while timeout > 0 and image_status != 'active':
try:
- task = _glancev2_call(
- 'task_show', task_id=task['id'],
- cloud_name=cloud_name
- )
+ image = _glancev2_call('image_get_details', name=name,
+ cloud_name=cloud_name)
except Exception as e:
- log.error(
- 'Glance failed to check '
- 'task status with {}'.format(e)
- )
- return _create_failed(name, 'image_task')
- if timeout <= 0 and task['status'] != 'success':
- log.error(
- 'Glance task failed to import '
- 'image for given amount of time'
- )
- return _create_failed(name, 'image')
- # Task successfully finished
- # and now check that is created the image
+ if 'ResourceNotFound' in repr(e):
+ timeout -= sleep_time
+ time.sleep(sleep_time)
+ continue
+ else:
+ raise
+ image_status = image['status']
+ if image_status != 'active':
+ log.error(
+ 'Glance upload image to volume failed '
+ 'for given amount of time'
+ )
+ return _failed('create', name, 'image')
+ return _succeeded('create', name, 'image', image)
- image = _glancev2_call(
- 'image_list', name=name, cloud_name=cloud_name
- )['images'][0]
+ else:
+ if not (location and image_properties):
+ return _failed('create', name, 'image')
+ image_properties['name'] = name
+ task_params = {"import_from": location,
+ "import_from_format": import_from_format,
+ "image_properties": image_properties
+ }
+ # Try create task
+ try:
+ task = _glancev2_call(
+ 'task_create', task_type='import',
+ task_input=task_params, cloud_name=cloud_name)
+ except Exception as e:
+ log.error(
+ 'Glance image create failed on '
+ 'create task with {}'.format(
+ e)
+ )
+ return _failed('create', name, 'image_task')
+ while timeout > 0:
+ if task['status'] == 'success':
+ break
+ elif task['status'] == 'failure':
+ log.error('Glance task failed to complete')
+ return _failed('create', name, 'image')
+ else:
+ timeout -= sleep_time
+ time.sleep(sleep_time)
+ # Check task status again
+ try:
+ task = _glancev2_call(
+ 'task_show', task_id=task['id'],
+ cloud_name=cloud_name
+ )
+ except Exception as e:
+ log.error(
+ 'Glance failed to check '
+ 'task status with {}'.format(e)
+ )
+ return _failed('create', name, 'image_task')
+ if timeout <= 0 and task['status'] != 'success':
+ log.error(
+ 'Glance task failed to import '
+ 'image for given amount of time'
+ )
+ return _failed('create', name, 'image')
+ # Task successfully finished
+ # and now check that is created the image
- if not image:
- return _create_failed(name, 'image')
+ images = _glancev2_call(
+ 'image_list', name=name, cloud_name=cloud_name
+ )['images']
- resp = _created(name, 'image', image)
+ if not len(images):
+ return _failed('create', name, 'image')
+ image = images[0]
+ resp = _succeeded('create', name, 'image', image)
- if checksum:
- if image['status'] == 'active':
- if 'checksum' not in image:
- log.error(
- 'Glance image. No checksum for image.'
- 'Image status is active'
- )
- return _create_failed(name, 'image')
- if image['checksum'] != checksum:
- log.error(
- 'Glance image create failed since '
- 'image_checksum should be '
- '{} but it is {}'.format(checksum,
- image['checksum'])
- )
- return _create_failed(name, 'image')
+ if checksum:
+ if image['status'] == 'active':
+ if 'checksum' not in image:
+ log.error(
+ 'Glance image. No checksum for image.'
+ 'Image status is active'
+ )
+ return _failed('create', name, 'image')
+ if image['checksum'] != checksum:
+ log.error(
+ 'Glance image create failed since '
+ 'image_checksum should be '
+ '{} but it is {}'.format(checksum,
+ image['checksum'])
+ )
+ return _failed('create', name, 'image')
- elif image['status'] in ['saving', 'queued']:
- resp['comment'] = resp['comment'] \
- + " checksum couldn't be verified, " \
- "since status is not active"
- return resp
+ elif image['status'] in ['saving', 'queued']:
+ resp['comment'] = resp['comment'] \
+ + " checksum couldn't be verified, " \
+ "since status is not active"
+ return resp
elif 'MultipleResourcesFound' in repr(e):
- return _find_failed(name, 'image')
+ return _failed('find', name, 'image')
else:
raise
@@ -164,111 +221,57 @@
)
except Exception as e:
log.error('Glance image update failed with {}'.format(e))
- return _update_failed(name, 'image')
- return _updated(name, 'image', resp)
- return _no_changes(name, 'image')
+ return _failed('update', name, 'image')
+ return _succeeded('update', name, 'image', resp)
+ return _succeeded('no_changes', name, 'image')
def image_absent(name, cloud_name):
try:
- image = _glancev2_call(
- 'image_get_details', name=name, cloud_name=cloud_name
- )
+ _glancev2_call('image_get_details', name=name, cloud_name=cloud_name)
except Exception as e:
if 'ResourceNotFound' in repr(e):
- return _absent(name, 'image')
+ return _succeeded('absent', name, 'image')
if 'MultipleResourcesFound' in repr(e):
- return _find_failed(name, 'image')
+ return _failed('find', name, 'image')
try:
- _glancev2_call(
- 'image_delete', name=name, cloud_name=cloud_name
- )
+ _glancev2_call('image_delete', name=name, cloud_name=cloud_name)
except Exception as e:
log.error('Glance image delete failed with {}'.format(e))
- return _delete_failed(name, 'image')
- return _deleted(name, 'image')
+ return _failed('delete', name, 'image')
+ return _succeeded('delete', name, 'image')
-def _created(name, resource, resource_definition):
+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,
- 'changes': resource_definition,
'result': True,
- 'comment': '{}{} created'.format(resource, name)
+ 'comment': msg_map[op].format(resource, name),
+ 'changes': changes or {},
}
return changes_dict
-
-def _updated(name, resource, resource_definition):
- changes_dict = {
- 'name': name,
- 'changes': resource_definition,
- 'result': True,
- 'comment': '{}{} updated'.format(resource, name)
+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}',
+ 'none': '{0} {1} found no {0}',
+ 'resources_moved': 'failed to move {1} from {0}',
}
- return changes_dict
-
-
-def _no_changes(name, resource):
changes_dict = {
'name': name,
- 'changes': {},
- 'result': True,
- 'comment': '{}{} is in desired state'.format(resource, name)
- }
- return changes_dict
-
-
-def _deleted(name, resource):
- changes_dict = {
- 'name': name,
- 'changes': {},
- 'result': True,
- 'comment': '{}{} removed'.format(resource, name)
- }
- return changes_dict
-
-
-def _absent(name, resource):
- changes_dict = {'name': name,
- 'changes': {},
- 'comment': '{0} {1} not present'.format(resource, name),
- 'result': True}
- return changes_dict
-
-
-def _delete_failed(name, resource):
- changes_dict = {'name': name,
- 'changes': {},
- 'comment': '{0} {1} failed to delete'.format(resource,
- name),
- 'result': False}
- return changes_dict
-
-
-def _create_failed(name, resource):
- changes_dict = {'name': name,
- 'changes': {},
- 'comment': '{0} {1} failed to create'.format(resource,
- name),
- 'result': False}
- return changes_dict
-
-
-def _update_failed(name, resource):
- changes_dict = {'name': name,
- 'changes': {},
- 'comment': '{0} {1} failed to update'.format(resource,
- name),
- 'result': False}
- return changes_dict
-
-
-def _find_failed(name, resource):
- changes_dict = {
- 'name': name,
- 'changes': {},
- 'comment': '{0} {1} found multiple {0}'.format(resource, name),
'result': False,
+ 'comment': msg_map[op].format(resource, name),
+ 'changes': {},
}
- return changes_dict
+ return changes_dict
\ No newline at end of file