Moving function from glance to glanceng module
The patch moves functions related to operation with images
from glance to glanceng module to work with versionless
endpoint authorization. Because of the fact that function
_auth which supports this kind of auth is located in glanceng
module.
Change-Id: I68bb34d2f2dbc159e170cc4aa77af16b9d6158b5
Related-PROD: PROD-18661
diff --git a/_modules/glanceng.py b/_modules/glanceng.py
index b39871d..5b15944 100644
--- a/_modules/glanceng.py
+++ b/_modules/glanceng.py
@@ -54,6 +54,9 @@
__version__,
SaltStackVersion
)
+
+from salt.utils import warn_until
+
# is there not SaltStackVersion.current() to get
# the version of the salt running this code??
_version_ary = __version__.split('.')
@@ -298,3 +301,342 @@
log.debug('Properties of schema {0}:\n{1}'.format(
name, pformat(schema_props)))
return {name: schema_props}
+
+def image_list(id=None, profile=None, name=None): # pylint: disable=C0103
+ '''
+ Return a list of available images (glance image-list)
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_list
+ '''
+ #try:
+ g_client = _auth(profile)
+ #except kstone_exc.Unauthorized:
+ # return False
+ #
+ # I may want to use this code on Beryllium
+ # until we got 2016.3.0 packages for Ubuntu
+ # so please keep this code until Carbon!
+ warn_until('Carbon', 'Starting in \'2016.3.0\' image_list() '
+ 'will return a list of images instead of a dictionary '
+ 'keyed with the images\' names.')
+ if CUR_VER < BORON:
+ ret = {}
+ else:
+ ret = []
+ for image in g_client.images.list():
+ if id is None and name is None:
+ _add_image(ret, image)
+ else:
+ if id is not None and id == image.id:
+ _add_image(ret, image)
+ return ret
+ if name == image.name:
+ if name in ret and CUR_VER < BORON:
+ # Not really worth an exception
+ return {
+ 'result': False,
+ 'comment':
+ 'More than one image with '
+ 'name "{0}"'.format(name)
+ }
+ _add_image(ret, image)
+ log.debug('Returning images: {0}'.format(ret))
+ return ret
+
+def _add_image(collection, image):
+ '''
+ Add image to given dictionary
+ '''
+ image_prep = {
+ 'id': image.id,
+ 'name': image.name,
+ 'created_at': image.created_at,
+ 'file': image.file,
+ 'min_disk': image.min_disk,
+ 'min_ram': image.min_ram,
+ 'owner': image.owner,
+ 'protected': image.protected,
+ 'status': image.status,
+ 'tags': image.tags,
+ 'updated_at': image.updated_at,
+ 'visibility': image.visibility,
+ }
+ # Those cause AttributeErrors in Icehouse' glanceclient
+ for attr in ['container_format', 'disk_format', 'size']:
+ if attr in image:
+ image_prep[attr] = image[attr]
+ if type(collection) is dict:
+ collection[image.name] = image_prep
+ elif type(collection) is list:
+ collection.append(image_prep)
+ else:
+ msg = '"collection" is {0}'.format(type(collection)) +\
+ 'instead of dict or list.'
+ log.error(msg)
+ raise TypeError(msg)
+ return collection
+
+def image_create(name, location=None, profile=None, visibility=None,
+ container_format='bare', disk_format='raw', protected=None,
+ copy_from=None, is_public=None):
+ '''
+ Create an image (glance image-create)
+
+ CLI Example, old format:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_create name=f16-jeos is_public=true \\
+ disk_format=qcow2 container_format=ovf \\
+ copy_from=http://berrange.fedorapeople.org/\
+ images/2012-02-29/f16-x86_64-openstack-sda.qcow2
+
+ CLI Example, new format resembling Glance API v2:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_create name=f16-jeos visibility=public \\
+ disk_format=qcow2 container_format=ovf \\
+ copy_from=http://berrange.fedorapeople.org/\
+ images/2012-02-29/f16-x86_64-openstack-sda.qcow2
+
+ The parameter 'visibility' defaults to 'public' if neither
+ 'visibility' nor 'is_public' is specified.
+ '''
+ kwargs = {}
+ # valid options for "visibility":
+ v_list = ['public', 'private']
+ # valid options for "container_format":
+ cf_list = ['ami', 'ari', 'aki', 'bare', 'ovf']
+ # valid options for "disk_format":
+ df_list = ['ami', 'ari', 'aki', 'vhd', 'vmdk',
+ 'raw', 'qcow2', 'vdi', 'iso']
+ # 'location' and 'visibility' are the parameters used in
+ # Glance API v2. For now we have to use v1 for now (see below)
+ # but this modules interface will change in Carbon.
+ if copy_from is not None or is_public is not None:
+ warn_until('Carbon', 'The parameters \'copy_from\' and '
+ '\'is_public\' are deprecated and will be removed. '
+ 'Use \'location\' and \'visibility\' instead.')
+ if is_public is not None and visibility is not None:
+ raise SaltInvocationError('Must only specify one of '
+ '\'is_public\' and \'visibility\'')
+ if copy_from is not None and location is not None:
+ raise SaltInvocationError('Must only specify one of '
+ '\'copy_from\' and \'location\'')
+ if copy_from is not None:
+ kwargs['copy_from'] = copy_from
+ else:
+ kwargs['copy_from'] = location
+ if is_public is not None:
+ kwargs['is_public'] = is_public
+ elif visibility is not None:
+ if visibility not in v_list:
+ raise SaltInvocationError('"visibility" needs to be one ' +
+ 'of the following: {0}'.format(', '.join(v_list)))
+ elif visibility == 'public':
+ kwargs['is_public'] = True
+ else:
+ kwargs['is_public'] = False
+ else:
+ kwargs['is_public'] = True
+ if container_format not in cf_list:
+ raise SaltInvocationError('"container_format" needs to be ' +
+ 'one of the following: {0}'.format(', '.join(cf_list)))
+ else:
+ kwargs['container_format'] = container_format
+ if disk_format not in df_list:
+ raise SaltInvocationError('"disk_format" needs to be one ' +
+ 'of the following: {0}'.format(', '.join(df_list)))
+ else:
+ kwargs['disk_format'] = disk_format
+ if protected is not None:
+ kwargs['protected'] = protected
+ # Icehouse's glanceclient doesn't have add_location() and
+ # glanceclient.v2 doesn't implement Client.images.create()
+ # in a usable fashion. Thus we have to use v1 for now.
+ g_client = _auth(profile, api_version=1)
+ image = g_client.images.create(name=name, **kwargs)
+ return image_show(image.id, profile=profile)
+
+def image_delete(id=None, name=None, profile=None): # pylint: disable=C0103
+ '''
+ Delete an image (glance image-delete)
+
+ CLI Examples:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_delete c2eb2eb0-53e1-4a80-b990-8ec887eae7df
+ salt '*' glance.image_delete id=c2eb2eb0-53e1-4a80-b990-8ec887eae7df
+ salt '*' glance.image_delete name=f16-jeos
+ '''
+ g_client = _auth(profile)
+ image = {'id': False, 'name': None}
+ if name:
+ for image in g_client.images.list():
+ if image.name == name:
+ id = image.id # pylint: disable=C0103
+ continue
+ if not id:
+ return {
+ 'result': False,
+ 'comment':
+ 'Unable to resolve image id '
+ 'for name {0}'.format(name)
+ }
+ elif not name:
+ name = image['name']
+ try:
+ g_client.images.delete(id)
+ except exc.HTTPNotFound:
+ return {
+ 'result': False,
+ 'comment': 'No image with ID {0}'.format(id)
+ }
+ except exc.HTTPForbidden as forbidden:
+ log.error(str(forbidden))
+ return {
+ 'result': False,
+ 'comment': str(forbidden)
+ }
+ return {
+ 'result': True,
+ 'comment': 'Deleted image \'{0}\' ({1}).'.format(name, id),
+ }
+
+def image_show(id=None, name=None, profile=None): # pylint: disable=C0103
+ '''
+ Return details about a specific image (glance image-show)
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_show
+ '''
+ g_client = _auth(profile)
+ ret = {}
+ if name:
+ for image in g_client.images.list():
+ if image.name == name:
+ id = image.id # pylint: disable=C0103
+ continue
+ if not id:
+ return {
+ 'result': False,
+ 'comment':
+ 'Unable to resolve image ID '
+ 'for name \'{0}\''.format(name)
+ }
+ try:
+ image = g_client.images.get(id)
+ except exc.HTTPNotFound:
+ return {
+ 'result': False,
+ 'comment': 'No image with ID {0}'.format(id)
+ }
+ pformat = pprint.PrettyPrinter(indent=4).pformat
+ log.debug('Properties of image {0}:\n{1}'.format(
+ image.name, pformat(image)))
+ ret_details = {}
+ # I may want to use this code on Beryllium
+ # until we got 2016.3.0 packages for Ubuntu
+ # so please keep this code until Carbon!
+ warn_until('Carbon', 'Starting with \'2016.3.0\' image_show() '
+ 'will stop wrapping the returned image in another '
+ 'dictionary.')
+ if CUR_VER < BORON:
+ ret[image.name] = ret_details
+ else:
+ ret = ret_details
+ schema = image_schema(profile=profile)
+ if len(schema.keys()) == 1:
+ schema = schema['image']
+ for key in schema.keys():
+ if key in image:
+ ret_details[key] = image[key]
+ return ret
+
+def image_update(id=None, name=None, profile=None, **kwargs): # pylint: disable=C0103
+ '''
+ Update properties of given image.
+ Known to work for:
+ - min_ram (in MB)
+ - protected (bool)
+ - visibility ('public' or 'private')
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' glance.image_update id=c2eb2eb0-53e1-4a80-b990-8ec887eae7df
+ salt '*' glance.image_update name=f16-jeos
+ '''
+ if id:
+ image = image_show(id=id, profile=profile)
+ if 'result' in image and not image['result']:
+ return image
+ elif len(image) == 1:
+ image = image.values()[0]
+ elif name:
+ img_list = image_list(name=name, profile=profile)
+ if img_list is dict and 'result' in img_list:
+ return img_list
+ elif len(img_list) == 0:
+ return {
+ 'result': False,
+ 'comment':
+ 'No image with name \'{0}\' '
+ 'found.'.format(name)
+ }
+ elif len(img_list) == 1:
+ try:
+ image = img_list[0]
+ except KeyError:
+ image = img_list[name]
+ else:
+ raise SaltInvocationError
+ log.debug('Found image:\n{0}'.format(image))
+ to_update = {}
+ for key, value in kwargs.items():
+ if key.startswith('_'):
+ continue
+ if key not in image or image[key] != value:
+ log.debug('add <{0}={1}> to to_update'.format(key, value))
+ to_update[key] = value
+ g_client = _auth(profile)
+ updated = g_client.images.update(image['id'], **to_update)
+ # I may want to use this code on Beryllium
+ # until we got 2016.3.0 packages for Ubuntu
+ # so please keep this code until Carbon!
+ warn_until('Carbon', 'Starting with \'2016.3.0\' image_update() '
+ 'will stop wrapping the returned, updated image in '
+ 'another dictionary.')
+ if CUR_VER < BORON:
+ updated = {updated.name: updated}
+ return updated
+
+def _item_list(profile=None):
+ '''
+ Template for writing list functions
+ Return a list of available items (glance items-list)
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' glance.item_list
+ '''
+ g_client = _auth(profile)
+ ret = []
+ for item in g_client.items.list():
+ ret.append(item.__dict__)
+ #ret[item.name] = {
+ # 'name': item.name,
+ # }
+ return ret