X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=snaps%2Fopenstack%2Fcreate_image.py;h=a5520e3a9451e087224c031f5e005b8bc66635e3;hb=8c3757c7179cffb86d9889c1744c22a2620bc6a7;hp=6ced052f950ceb60d8b1a7bc66e72559f02af5e1;hpb=becbbabc63b0eff15ed6979947aeb75ddf6819c9;p=snaps.git diff --git a/snaps/openstack/create_image.py b/snaps/openstack/create_image.py index 6ced052..a5520e3 100644 --- a/snaps/openstack/create_image.py +++ b/snaps/openstack/create_image.py @@ -12,12 +12,14 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import logging -import time from glanceclient.exc import HTTPNotFound +import logging +import time +from snaps.openstack.openstack_creator import OpenStackCloudObject from snaps.openstack.utils import glance_utils +from snaps.config import image __author__ = 'spisarski' @@ -28,43 +30,102 @@ POLL_INTERVAL = 3 STATUS_ACTIVE = 'active' -class OpenStackImage: +class OpenStackImage(OpenStackCloudObject): """ - Class responsible for creating an image in OpenStack + Class responsible for managing an image in OpenStack """ def __init__(self, os_creds, image_settings): """ Constructor :param os_creds: The OpenStack connection credentials - :param image_settings: The image settings - :return: + :param image_settings: An snaps.config.image.ImageConfig object """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.image_settings = image_settings self.__image = None - self.__glance = glance_utils.glance_client(os_creds) + self.__kernel_image = None + self.__ramdisk_image = None + self.__glance = None - def create(self, cleanup=False): + def initialize(self): """ - Creates the image in OpenStack if it does not already exist and returns the domain Image object - :param cleanup: Denotes whether or not this is being called for cleanup or not - :return: The OpenStack Image object + Loads the existing Image + :return: The Image domain object or None """ - self.__image = glance_utils.get_image(self.__glance, self.image_settings.name) + self.__glance = glance_utils.glance_client(self._os_creds) + self.__image = glance_utils.get_image( + self.__glance, image_settings=self.image_settings) + if self.__image: logger.info('Found image with name - ' + self.image_settings.name) return self.__image - elif not cleanup: - self.__image = glance_utils.create_image(self.__glance, self.image_settings) - logger.info('Creating image') + elif (self.image_settings.exists and not self.image_settings.url + and not self.image_settings.image_file): + raise ImageCreationError( + 'Image with does not exist with name - ' + + self.image_settings.name) + + if self.image_settings.kernel_image_settings: + self.__kernel_image = glance_utils.get_image( + self.__glance, + image_settings=self.image_settings.kernel_image_settings) + + if self.image_settings.ramdisk_image_settings: + self.__ramdisk_image = glance_utils.get_image( + self.__glance, + image_settings=self.image_settings.ramdisk_image_settings) + + return self.__image + + def create(self): + """ + Creates the image in OpenStack if it does not already exist and returns + the domain Image object + :return: The Image domain object or None + """ + self.initialize() + + if not self.__image: + extra_properties = self.image_settings.extra_properties or dict() + + if self.image_settings.kernel_image_settings: + if not self.__kernel_image: + logger.info( + 'Creating associated kernel image with name - %s', + self.image_settings.kernel_image_settings.name) + self.__kernel_image = glance_utils.create_image( + self.__glance, + self.image_settings.kernel_image_settings) + extra_properties['kernel_id'] = self.__kernel_image.id + + if self.image_settings.ramdisk_image_settings: + if not self.__ramdisk_image: + logger.info( + 'Creating associated ramdisk image with name - %s', + self.image_settings.ramdisk_image_settings.name) + self.__ramdisk_image = glance_utils.create_image( + self.__glance, + self.image_settings.ramdisk_image_settings) + extra_properties['ramdisk_id'] = self.__ramdisk_image.id + + self.image_settings.extra_properties = extra_properties + self.__image = glance_utils.create_image(self.__glance, + self.image_settings) + + logger.info( + 'Created image with name - %s', self.image_settings.name) + if self.__image and self.image_active(block=True): - logger.info('Image is now active with name - ' + self.image_settings.name) + logger.info( + 'Image is now active with name - %s', + self.image_settings.name) return self.__image else: - raise Exception('Image was not created or activated in the alloted amount of time') - else: - logger.info('Did not create image due to cleanup mode') + raise ImageCreationError( + 'Image was not created or activated in the alloted amount' + 'of time') return self.__image @@ -73,35 +134,64 @@ class OpenStackImage: Cleanse environment of all artifacts :return: void """ - if self.__image: - try: - glance_utils.delete_image(self.__glance, self.__image) - except HTTPNotFound: - pass - self.__image = None + for img in [self.__image, self.__kernel_image, self.__ramdisk_image]: + if img: + try: + glance_utils.delete_image(self.__glance, img) + except HTTPNotFound: + pass + + self.__image = None + self.__kernel_image = None + self.__ramdisk_image = None def get_image(self): """ - Returns the domain Image object as it was populated when create() was called + Returns the domain Image object as it was populated when create() was + called :return: the object """ return self.__image - def image_active(self, block=False, timeout=IMAGE_ACTIVE_TIMEOUT, poll_interval=POLL_INTERVAL): + def get_kernel_image(self): + """ + Returns the OpenStack kernel image object as it was populated when + create() was called + :return: the object + """ + return self.__kernel_image + + def get_ramdisk_image(self): """ - Returns true when the image status returns the value of expected_status_code - :param block: When true, thread will block until active or timeout value in seconds has been exceeded (False) + Returns the OpenStack ramdisk image object as it was populated when + create() was called + :return: the object + """ + return self.__ramdisk_image + + def image_active(self, block=False, timeout=IMAGE_ACTIVE_TIMEOUT, + poll_interval=POLL_INTERVAL): + """ + Returns true when the image status returns the value of + expected_status_code + :param block: When true, thread will block until active or timeout + value in seconds has been exceeded (False) :param timeout: The timeout value :param poll_interval: The polling interval in seconds :return: T/F """ - return self._image_status_check(STATUS_ACTIVE, block, timeout, poll_interval) + return self._image_status_check(STATUS_ACTIVE, block, timeout, + poll_interval) - def _image_status_check(self, expected_status_code, block, timeout, poll_interval): + def _image_status_check(self, expected_status_code, block, timeout, + poll_interval): """ - Returns true when the image status returns the value of expected_status_code - :param expected_status_code: instance status evaluated with this string value - :param block: When true, thread will block until active or timeout value in seconds has been exceeded (False) + Returns true when the image status returns the value of + expected_status_code + :param expected_status_code: instance status evaluated with this string + value + :param block: When true, thread will block until active or timeout + value in seconds has been exceeded (False) :param timeout: The timeout value :param poll_interval: The polling interval in seconds :return: T/F @@ -115,73 +205,53 @@ class OpenStackImage: while timeout > time.time() - start: status = self._status(expected_status_code) if status: - logger.info('Image is active with name - ' + self.image_settings.name) + logger.debug( + 'Image is active with name - ' + self.image_settings.name) return True - logger.debug('Retry querying image status in ' + str(poll_interval) + ' seconds') + logger.debug('Retry querying image status in ' + str( + poll_interval) + ' seconds') time.sleep(poll_interval) - logger.debug('Image status query timeout in ' + str(timeout - (time.time() - start))) + logger.debug('Image status query timeout in ' + str( + timeout - (time.time() - start))) - logger.error('Timeout checking for image status for ' + expected_status_code) + logger.error( + 'Timeout checking for image status for ' + expected_status_code) return False def _status(self, expected_status_code): """ Returns True when active else False - :param expected_status_code: instance status evaluated with this string value + :param expected_status_code: instance status evaluated with this string + value :return: T/F """ - # TODO - Place this API call into glance_utils. status = glance_utils.get_image_status(self.__glance, self.__image) if not status: - logger.warn('Cannot image status for image with ID - ' + self.__image.id) + logger.warning( + 'Cannot image status for image with ID - ' + self.__image.id) return False if status == 'ERROR': - raise Exception('Instance had an error during deployment') + raise ImageCreationError('Instance had an error during deployment') logger.debug('Instance status is - ' + status) return status == expected_status_code -class ImageSettings: - def __init__(self, config=None, name=None, image_user=None, img_format=None, url=None, image_file=None, - extra_properties=None, nic_config_pb_loc=None): - """ +class ImageSettings(image.ImageConfig): + """ + Deprecated, use snaps.config.image.ImageSettings instead + """ + def __init__(self, **kwargs): + from warnings import warn + warn('Use snaps.config.image.ImageConfig instead', DeprecationWarning) + super(ImageSettings, self).__init__(**kwargs) - :param config: dict() object containing the configuration settings using the attribute names below as each - member's the key and overrides any of the other parameters. - :param name: the image's name (required) - :param image_user: the image's default sudo user (required) - :param img_format: the image type (required) - :param url: the image download location (requires url or img_file) - :param image_file: the image file location (requires url or img_file) - :param extra_properties: dict() object containing extra parameters to pass when loading the image; - can be ids of kernel and initramfs images for a 3-part image - :param nic_config_pb_loc: the file location to the Ansible Playbook that can configure multiple NICs - """ - if config: - self.name = config.get('name') - self.image_user = config.get('image_user') - self.format = config.get('format') - self.url = config.get('download_url') - self.image_file = config.get('image_file') - self.extra_properties = config.get('extra_properties') - self.nic_config_pb_loc = config.get('nic_config_pb_loc') - else: - self.name = name - self.image_user = image_user - self.format = img_format - self.url = url - self.image_file = image_file - self.extra_properties = extra_properties - self.nic_config_pb_loc = nic_config_pb_loc - - if not self.name or not self.image_user or not self.format: - raise Exception("The attributes name, image_user, format, and url are required for ImageSettings") - - if not self.url and not self.image_file: - raise Exception('URL or image file must be set') - - if self.url and self.image_file: - raise Exception('Please set either URL or image file, not both') +class ImageCreationError(Exception): + """ + Exception to be thrown when an image cannot be created + """ + + def __init__(self, message): + Exception.__init__(self, message)