mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #25505 from 0xf10e/glance_state_module_boron
Glance state module for 2015.8 "Beryllium"
This commit is contained in:
commit
f06dd05a31
@ -40,10 +40,23 @@ from __future__ import absolute_import
|
||||
|
||||
# Import third party libs
|
||||
#import salt.ext.six as six
|
||||
|
||||
# Import salt libs
|
||||
from salt.exceptions import (
|
||||
#CommandExecutionError,
|
||||
SaltInvocationError
|
||||
)
|
||||
from salt.utils import warn_until
|
||||
|
||||
from salt.version import (
|
||||
__version__,
|
||||
SaltStackVersion
|
||||
)
|
||||
# is there not SaltStackVersion.current() to get
|
||||
# the version of the salt running this code??
|
||||
CUR_VER = SaltStackVersion(__version__[0], __version__[1])
|
||||
BORON = SaltStackVersion.from_name('Boron')
|
||||
|
||||
# pylint: disable=import-error
|
||||
HAS_GLANCE = False
|
||||
try:
|
||||
@ -77,6 +90,7 @@ def __virtual__():
|
||||
return 'glance'
|
||||
return False
|
||||
|
||||
|
||||
__opts__ = {}
|
||||
|
||||
|
||||
@ -143,12 +157,14 @@ def _auth(profile=None, api_version=2, **connection_args):
|
||||
'get a new one using username and password.')
|
||||
|
||||
if HAS_KEYSTONE:
|
||||
# TODO: redact kwargs['password']
|
||||
log.debug('Calling keystoneclient.v2_0.client.Client(' +
|
||||
'{0}, **{1})'.format(endpoint, kwargs))
|
||||
keystone = kstone.Client(**kwargs)
|
||||
log.debug(help(keystone.get_token))
|
||||
kwargs['token'] = keystone.get_token(keystone.session)
|
||||
# This doesn't realy prevent the password to show up
|
||||
# in the minion log as keystoneclient.session is
|
||||
# logging it anyway when in debug-mode
|
||||
kwargs.pop('password')
|
||||
log.debug('Calling glanceclient.client.Client(' +
|
||||
'{0}, {1}, **{2})'.format(api_version, endpoint, kwargs))
|
||||
@ -158,22 +174,65 @@ def _auth(profile=None, api_version=2, **connection_args):
|
||||
"Can't retrieve a auth_token without keystone")
|
||||
|
||||
|
||||
def image_create(name, location, profile=None, visibility='public',
|
||||
container_format='bare', disk_format='raw'):
|
||||
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:
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
For all possible values, run ``glance help image-create`` on the minion.
|
||||
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":
|
||||
@ -181,20 +240,52 @@ def image_create(name, location, profile=None, visibility='public',
|
||||
# valid options for "disk_format":
|
||||
df_list = ['ami', 'ari', 'aki', 'vhd', 'vmdk',
|
||||
'raw', 'qcow2', 'vdi', 'iso']
|
||||
if visibility not in v_list:
|
||||
raise SaltInvocationError('"visibility" needs to be one ' +
|
||||
'of the following: {0}'.format(', '.join(v_list)))
|
||||
# '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 Boron.
|
||||
if copy_from is not None or is_public is not None:
|
||||
warn_until('Boron', '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, copy_from=location)
|
||||
image = g_client.images.create(name=name, **kwargs)
|
||||
return image_show(image.id)
|
||||
|
||||
|
||||
@ -217,8 +308,15 @@ def image_delete(id=None, name=None, profile=None): # pylint: disable=C0103
|
||||
id = image.id # pylint: disable=C0103
|
||||
continue
|
||||
if not id:
|
||||
return {'Error': 'Unable to resolve image id'}
|
||||
g_client.images.delete(id)
|
||||
return {'Error': 'Unable to resolve '
|
||||
'image id for name {0}'.format(name)}
|
||||
try:
|
||||
g_client.images.delete(id)
|
||||
except exc.HTTPNotFound:
|
||||
return {'Error': 'No image with ID {0}'.format(id)}
|
||||
except exc.HTTPForbidden as forbidden:
|
||||
log.error(str(forbidden))
|
||||
return {'Error': str(forbidden)}
|
||||
ret = 'Deleted image with ID {0}'.format(id)
|
||||
if name:
|
||||
ret += ' ({0})'.format(name)
|
||||
@ -248,18 +346,27 @@ def image_show(id=None, name=None, profile=None): # pylint: disable=C0103
|
||||
pformat = pprint.PrettyPrinter(indent=4).pformat
|
||||
log.debug('Properties of image {0}:\n{1}'.format(
|
||||
image.name, pformat(image)))
|
||||
# TODO: Get rid of the wrapping dict, see #24568
|
||||
ret[image.name] = {}
|
||||
ret_details = {}
|
||||
# I may want to use this code on Beryllium
|
||||
# until we got Boron packages for Ubuntu
|
||||
# so please keep this code until Carbon!
|
||||
warn_until('Carbon', 'Starting with \'Boron\' 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[image.name][key] = image[key]
|
||||
ret_details[key] = image[key]
|
||||
return ret
|
||||
|
||||
|
||||
def image_list(id=None, profile=None): # pylint: disable=C0103
|
||||
def image_list(id=None, profile=None, name=None): # pylint: disable=C0103
|
||||
'''
|
||||
Return a list of available images (glance image-list)
|
||||
|
||||
@ -270,29 +377,30 @@ def image_list(id=None, profile=None): # pylint: disable=C0103
|
||||
salt '*' glance.image_list
|
||||
'''
|
||||
g_client = _auth(profile)
|
||||
ret = {}
|
||||
# TODO: Get rid of the wrapping dict, see #24568
|
||||
# I may want to use this code on Beryllium
|
||||
# until we got Boron packages for Ubuntu
|
||||
# so please keep this code until Carbon!
|
||||
warn_until('Carbon', 'Starting in \'Boron\' 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():
|
||||
ret[image.name] = {
|
||||
'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:
|
||||
ret[image.name][attr] = image[attr]
|
||||
if id == image.id:
|
||||
return ret[image.name]
|
||||
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 {'Error': 'More than one image '
|
||||
'with name "{0}"'.format(name)}
|
||||
_add_image(ret, image)
|
||||
log.debug('Returning images: {0}'.format(ret))
|
||||
return ret
|
||||
|
||||
|
||||
@ -304,6 +412,52 @@ def image_schema(profile=None):
|
||||
return schema_get('image', profile)
|
||||
|
||||
|
||||
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')
|
||||
'''
|
||||
if id:
|
||||
image = image_show(id=id)
|
||||
# TODO: This unwrapping should get a warn_until
|
||||
if len(image) == 1:
|
||||
image = image.values()[0]
|
||||
elif name:
|
||||
img_list = image_list(name=name)
|
||||
if img_list is not list and 'Error' 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:
|
||||
image = img_list[0]
|
||||
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 Boron packages for Ubuntu
|
||||
# so please keep this code until Carbon!
|
||||
warn_until('Carbon', 'Starting with \'Boron\' image_update() '
|
||||
'will stop wrapping the returned, updated image in '
|
||||
'another dictionary.')
|
||||
if CUR_VER < BORON:
|
||||
updated = {updated.name: updated}
|
||||
return updated
|
||||
|
||||
|
||||
def schema_get(name, profile=None):
|
||||
'''
|
||||
Known valid names of schemas are:
|
||||
@ -343,11 +497,10 @@ def _item_list(profile=None):
|
||||
return ret
|
||||
|
||||
|
||||
#The following is a list of functions that need to be incorporated in the
|
||||
#glance module. This list should be updated as functions are added.
|
||||
# The following is a list of functions that need to be incorporated in the
|
||||
# glance module. This list should be updated as functions are added.
|
||||
|
||||
# image-download Download a specific image.
|
||||
# image-update Update a specific image.
|
||||
# member-create Share a specific image with a tenant.
|
||||
# member-delete Remove a shared image from a tenant.
|
||||
# member-list Describe sharing permissions by image or tenant.
|
||||
|
250
salt/states/glance.py
Normal file
250
salt/states/glance.py
Normal file
@ -0,0 +1,250 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Managing Images in OpenStack Glance
|
||||
===================================
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
import time
|
||||
|
||||
# Import salt libs
|
||||
from salt.utils import warn_until
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _find_image(name):
|
||||
'''
|
||||
Tries to find image with given name, returns
|
||||
- image, 'Found image <name>'
|
||||
- None, 'No such image found'
|
||||
- False, 'Found more than one image with given name'
|
||||
'''
|
||||
images_dict = __salt__['glance.image_list'](name=name)
|
||||
log.debug('Got images_dict: {0}'.format(images_dict))
|
||||
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'glance.image_list\' is not supposed to return '
|
||||
'the images wrapped in a separate dict anymore.')
|
||||
if len(images_dict) == 1 and 'images' in images_dict:
|
||||
images_dict = images_dict['images']
|
||||
|
||||
# I /think/ this will still work when glance.image_list
|
||||
# starts returning a list instead of a dictionary...
|
||||
if len(images_dict) == 0:
|
||||
return None, 'No image with name "{0}"'.format(name)
|
||||
elif len(images_dict) == 1:
|
||||
return images_dict.values()[0], 'Found image {0}'.format(name)
|
||||
elif len(images_dict) > 1:
|
||||
return False, 'Found more than one image with given name'
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def image_present(name, visibility='public', protected=None,
|
||||
checksum=None, location=None, wait_for=None, timeout=30):
|
||||
'''
|
||||
Checks if given image is present with properties
|
||||
set as specified.
|
||||
|
||||
An image should got through the stages 'queued', 'saving'
|
||||
before becoming 'active'. The attribute 'checksum' can
|
||||
only be checked once the image is active.
|
||||
If you don't specify 'wait_for' but 'checksum' the function
|
||||
will wait for the image to become active before comparing
|
||||
checksums. If you don't specify checksum either the function
|
||||
will return when the image reached 'saving'.
|
||||
The default timeout for both is 30 seconds.
|
||||
|
||||
Supported properties:
|
||||
- visibility ('public' or 'private')
|
||||
- protected (bool)
|
||||
- checksum (string, md5sum)
|
||||
- location (URL, to copy from)
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': '',
|
||||
}
|
||||
acceptable = ['queued', 'saving', 'active']
|
||||
if wait_for is None and checksum is None:
|
||||
wait_for = 'saving'
|
||||
elif wait_for is None and checksum is not None:
|
||||
wait_for = 'active'
|
||||
|
||||
# Just pop states until we reach the
|
||||
# first acceptable one:
|
||||
while len(acceptable) > 1:
|
||||
if acceptable[0] == wait_for:
|
||||
break
|
||||
else:
|
||||
acceptable.pop(0)
|
||||
|
||||
image, msg = _find_image(name)
|
||||
if image is False:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
else:
|
||||
ret['result'] = False
|
||||
ret['comment'] = msg
|
||||
return ret
|
||||
log.debug(msg)
|
||||
# No image yet and we know where to get one
|
||||
if image is None and location is not None:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'glance.image_present would ' \
|
||||
'create an image from {0}'.format(location)
|
||||
return ret
|
||||
image = __salt__['glance.image_create'](name=name,
|
||||
protected=protected, visibility=visibility,
|
||||
location=location)
|
||||
# See Salt issue #24568
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'glance.image_create\' is not supposed to return '
|
||||
'the image wrapped in a dict anymore.')
|
||||
if len(image.keys()) == 1:
|
||||
image = image.values()[0]
|
||||
log.debug('Created new image:\n{0}'.format(image))
|
||||
ret['changes'] = {
|
||||
name:
|
||||
{
|
||||
'new':
|
||||
{
|
||||
'id': image['id']
|
||||
},
|
||||
'old': None
|
||||
}
|
||||
}
|
||||
timer = timeout
|
||||
# Kinda busy-loopy but I don't think the Glance
|
||||
# API has events we can listen for
|
||||
while timer > 0:
|
||||
if 'status' in image and \
|
||||
image['status'] in acceptable:
|
||||
log.debug('Image {0} has reached status {1}'.format(
|
||||
image['name'], image['status']))
|
||||
break
|
||||
else:
|
||||
timer -= 5
|
||||
time.sleep(5)
|
||||
image, msg = _find_image(name)
|
||||
if not image:
|
||||
ret['result'] = False
|
||||
ret['comment'] += 'Created image {0} '.format(
|
||||
name) + ' vanished:\n' + msg
|
||||
return ret
|
||||
elif len(image.keys()) == 1:
|
||||
# See Salt issue #24568
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'_find_image()\' is not supposed to return '
|
||||
'the image wrapped in a dict anymore.')
|
||||
image = image.values()[0]
|
||||
if timer <= 0 and image['status'] not in acceptable:
|
||||
ret['result'] = False
|
||||
ret['comment'] += 'Image didn\'t reach an acceptable '+\
|
||||
'state ({0}) before timeout:\n'.format(acceptable)+\
|
||||
'\tLast status was "{0}".\n'.format(image['status'])
|
||||
|
||||
# See Salt issue #24568
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'_find_image()\' is not supposed to return '
|
||||
'the image wrapped in a dict anymore.')
|
||||
if len(image.keys()) == 1:
|
||||
image = image.values()[0]
|
||||
# ret[comment] +=
|
||||
|
||||
# There's no image but where would I get one??
|
||||
elif location is None:
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'No location to copy image from specified,\n' +\
|
||||
'glance.image_present would not create one'
|
||||
else:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'No location to copy image from specified,\n' +\
|
||||
'not creating a new image.'
|
||||
return ret
|
||||
|
||||
# If we've created a new image also return its last status:
|
||||
if name in ret['changes']:
|
||||
ret['changes'][name]['new']['status'] = image['status']
|
||||
|
||||
if visibility:
|
||||
if image['visibility'] != visibility:
|
||||
old_value = image['visibility']
|
||||
if not __opts__['test']:
|
||||
image = __salt__['glance.image_update'](
|
||||
id=image['id'], visibility=visibility)
|
||||
# See Salt issue #24568
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'glance.image_update\' is not supposed to return '
|
||||
'the image wrapped in a dict anymore.')
|
||||
if len(image.keys()) == 1:
|
||||
image = image.values()[0]
|
||||
# Check if image_update() worked:
|
||||
if image['visibility'] != visibility:
|
||||
if not __opts__['test']:
|
||||
ret['result'] = False
|
||||
elif __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] += '"visibility" is {0}, '\
|
||||
'should be {1}.\n'.format(image['visibility'],
|
||||
visibility)
|
||||
else:
|
||||
if 'new' in ret['changes']:
|
||||
ret['changes']['new']['visibility'] = visibility
|
||||
else:
|
||||
ret['changes']['new'] = {'visibility': visibility}
|
||||
if 'old' in ret['changes']:
|
||||
ret['changes']['old']['visibility'] = old_value
|
||||
else:
|
||||
ret['changes']['old'] = {'visibility': old_value}
|
||||
else:
|
||||
ret['comment'] += '"visibility" is correct ({0}).\n'.format(
|
||||
visibility)
|
||||
if protected is not None:
|
||||
if not isinstance(protected, bool) or image['protected'] ^ protected:
|
||||
if not __opts__['test']:
|
||||
ret['result'] = False
|
||||
else:
|
||||
ret['result'] = None
|
||||
ret['comment'] += '"protected" is {0}, should be {1}.\n'.format(
|
||||
image['protected'], protected)
|
||||
else:
|
||||
ret['comment'] += '"protected" is correct ({0}).\n'.format(
|
||||
protected)
|
||||
if 'status' in image and checksum:
|
||||
if image['status'] == 'active':
|
||||
if 'checksum' not in image:
|
||||
# Refresh our info about the image
|
||||
image = __salt__['glance.image_show'](image['id'])
|
||||
warn_until('Boron', 'Starting with Boron '
|
||||
'\'glance.image_show\' is not supposed to return '
|
||||
'the image wrapped in a dict anymore.')
|
||||
if len(image.keys()) == 1:
|
||||
image = image.values()[0]
|
||||
if 'checksum' not in image:
|
||||
if not __opts__['test']:
|
||||
ret['result'] = False
|
||||
else:
|
||||
ret['result'] = None
|
||||
ret['comment'] += 'No checksum available for this image:\n' +\
|
||||
'\tImage has status "{0}".'.format(image['status'])
|
||||
elif image['checksum'] != checksum:
|
||||
if not __opts__['test']:
|
||||
ret['result'] = False
|
||||
else:
|
||||
ret['result'] = None
|
||||
ret['comment'] += '"checksum" is {0}, should be {1}.\n'.format(
|
||||
image['checksum'], checksum)
|
||||
else:
|
||||
ret['comment'] += '"checksum" is correct ({0}).\n'.format(
|
||||
checksum)
|
||||
elif image['status'] in ['saving', 'queued']:
|
||||
ret['comment'] += 'Checksum won\'t be verified as image ' +\
|
||||
'hasn\'t reached\n\t "status=active" yet.\n'
|
||||
log.debug('glance.image_present will return: {0}'.format(ret))
|
||||
return ret
|
Loading…
Reference in New Issue
Block a user