import copy
import logging
import os
-import sys
from cinderclient import client as cinderclient
from novaclient import client as novaclient
params.update(os_cloud_config)
return shade.openstack_cloud(**params)
+def get_shade_operator_client(**os_cloud_config):
+ """Get Shade Operator cloud client
+
+ :return: ``shade.OperatorCloud`` object.
+ """
+ params = copy.deepcopy(constants.OS_CLOUD_DEFAULT_CONFIG)
+ params.update(os_cloud_config)
+ return shade.operator_cloud(**params)
+
# *********************************************
# NOVA
# *********************************************
# GLANCE
# *********************************************
-def get_image_id(glance_client, image_name): # pragma: no cover
- images = glance_client.images.list()
- return next((i.id for i in images if i.name == image_name), None)
-
-
-def create_image(glance_client, image_name, file_path, disk_format,
- container_format, min_disk, min_ram, protected, tag,
- public, **kwargs): # pragma: no cover
- if not os.path.isfile(file_path):
- log.error("Error: file %s does not exist.", file_path)
- return None
+def create_image(shade_client, name, filename=None, container='images',
+ md5=None, sha256=None, disk_format=None,
+ container_format=None, disable_vendor_agent=True,
+ wait=False, timeout=3600, allow_duplicates=False, meta=None,
+ volume=None, **kwargs):
+ """Upload an image.
+
+ :param name:(str) Name of the image to create. If it is a pathname of an
+ image, the name will be constructed from the extensionless
+ basename of the path.
+ :param filename:(str) The path to the file to upload, if needed.
+ :param container:(str) Name of the container in swift where images should
+ be uploaded for import if the cloud requires such a thing.
+ :param md5:(str) md5 sum of the image file. If not given, an md5 will
+ be calculated.
+ :param sha256:(str) sha256 sum of the image file. If not given, an md5
+ will be calculated.
+ :param disk_format:(str) The disk format the image is in.
+ :param container_format:(str) The container format the image is in.
+ :param disable_vendor_agent:(bool) Whether or not to append metadata
+ flags to the image to inform the cloud in
+ question to not expect a vendor agent to be running.
+ :param wait:(bool) If true, waits for image to be created.
+ :param timeout:(str) Seconds to wait for image creation.
+ :param allow_duplicates:(bool) If true, skips checks that enforce unique
+ image name.
+ :param meta:(dict) A dict of key/value pairs to use for metadata that
+ bypasses automatic type conversion.
+ :param volume:(str) Name or ID or volume object of a volume to create an
+ image from.
+ Additional kwargs will be passed to the image creation as additional
+ metadata for the image and will have all values converted to string
+ except for min_disk, min_ram, size and virtual_size which will be
+ converted to int.
+ If you are sure you have all of your data types correct or have an
+ advanced need to be explicit, use meta. If you are just a normal
+ consumer, using kwargs is likely the right choice.
+ If a value is in meta and kwargs, meta wins.
+ :returns: Image id
+ """
try:
- image_id = get_image_id(glance_client, image_name)
+ image_id = shade_client.get_image_id(name)
if image_id is not None:
- log.info("Image %s already exists.", image_name)
- else:
- log.info("Creating image '%s' from '%s'...", image_name, file_path)
-
- image = glance_client.images.create(
- name=image_name, visibility=public, disk_format=disk_format,
- container_format=container_format, min_disk=min_disk,
- min_ram=min_ram, tags=tag, protected=protected, **kwargs)
- image_id = image.id
- with open(file_path) as image_data:
- glance_client.images.upload(image_id, image_data)
+ log.info("Image %s already exists.", name)
+ return image_id
+ log.info("Creating image '%s'", name)
+ image = shade_client.create_image(
+ name, filename=filename, container=container, md5=md5, sha256=sha256,
+ disk_format=disk_format, container_format=container_format,
+ disable_vendor_agent=disable_vendor_agent, wait=wait, timeout=timeout,
+ allow_duplicates=allow_duplicates, meta=meta, volume=volume, **kwargs)
+ image_id = image["id"]
return image_id
- except Exception: # pylint: disable=broad-except
- log.error(
- "Error [create_glance_image(glance_client, '%s', '%s', '%s')]",
- image_name, file_path, public)
- return None
+ except exc.OpenStackCloudException as op_exc:
+ log.error("Failed to create_image(shade_client). "
+ "Exception message: %s", op_exc.orig_message)
-def delete_image(glance_client, image_id): # pragma: no cover
+def delete_image(shade_client, name_or_id, wait=False, timeout=3600,
+ delete_objects=True):
try:
- glance_client.images.delete(image_id)
+ return shade_client.delete_image(name_or_id, wait=wait,
+ timeout=timeout,
+ delete_objects=delete_objects)
- except Exception: # pylint: disable=broad-except
- log.exception("Error [delete_flavor(glance_client, %s)]", image_id)
+ except exc.OpenStackCloudException as op_exc:
+ log.error("Failed to delete_image(shade_client). "
+ "Exception message: %s", op_exc.orig_message)
return False
- else:
- return True
def list_images(shade_client=None):
return shade_client.get_volume_id(volume_name)
-def create_volume(cinder_client, volume_name, volume_size,
- volume_image=False): # pragma: no cover
+def get_volume(shade_client, name_or_id, filters=None):
+ """Get a volume by name or ID.
+
+ :param name_or_id: Name or ID of the volume.
+ :param filters: A dictionary of meta data to use for further filtering.
+
+ :returns: A volume ``munch.Munch`` or None if no matching volume is found.
+ """
+ return shade_client.get_volume(name_or_id, filters=filters)
+
+
+def create_volume(shade_client, size, wait=True, timeout=None,
+ image=None, **kwargs):
+ """Create a volume.
+
+ :param size: Size, in GB of the volume to create.
+ :param name: (optional) Name for the volume.
+ :param description: (optional) Name for the volume.
+ :param wait: If true, waits for volume to be created.
+ :param timeout: Seconds to wait for volume creation. None is forever.
+ :param image: (optional) Image name, ID or object from which to create
+ the volume.
+
+ :returns: The created volume object.
+
+ """
try:
- if volume_image:
- volume = cinder_client.volumes.create(name=volume_name,
- size=volume_size,
- imageRef=volume_image)
- else:
- volume = cinder_client.volumes.create(name=volume_name,
- size=volume_size)
- return volume
- except Exception: # pylint: disable=broad-except
- log.exception("Error [create_volume(cinder_client, %s)]",
- (volume_name, volume_size))
- return None
+ return shade_client.create_volume(size, wait=wait, timeout=timeout,
+ image=image, **kwargs)
+ except (exc.OpenStackCloudException, exc.OpenStackCloudTimeout) as op_exc:
+ log.error("Failed to create_volume(shade_client). "
+ "Exception message: %s", op_exc.orig_message)
-def delete_volume(cinder_client, volume_id,
- forced=False): # pragma: no cover
- try:
- if forced:
- try:
- cinder_client.volumes.detach(volume_id)
- except Exception: # pylint: disable=broad-except
- log.error(sys.exc_info()[0])
- cinder_client.volumes.force_delete(volume_id)
- else:
- while True:
- volume = get_cinder_client().volumes.get(volume_id)
- if volume.status.lower() == 'available':
- break
- cinder_client.volumes.delete(volume_id)
- return True
- except Exception: # pylint: disable=broad-except
- log.exception("Error [delete_volume(cinder_client, '%s')]", volume_id)
+def delete_volume(shade_client, name_or_id=None, wait=True, timeout=None):
+ """Delete a volume.
+
+ :param name_or_id:(string) Name or unique ID of the volume.
+ :param wait:(bool) If true, waits for volume to be deleted.
+ :param timeout:(string) Seconds to wait for volume deletion. None is forever.
+
+ :return: True on success, False otherwise.
+ """
+ try:
+ return shade_client.delete_volume(name_or_id=name_or_id,
+ wait=wait, timeout=timeout)
+ except (exc.OpenStackCloudException, exc.OpenStackCloudTimeout) as o_exc:
+ log.error("Error [delete_volume(shade_client,'%s')]. "
+ "Exception message: %s", name_or_id, o_exc.orig_message)
return False
-def detach_volume(server_id, volume_id): # pragma: no cover
+def detach_volume(shade_client, server_name_or_id, volume_name_or_id,
+ wait=True, timeout=None):
+ """Detach a volume from a server.
+
+ :param server_name_or_id: The server name or id to detach from.
+ :param volume_name_or_id: The volume name or id to detach.
+ :param wait: If true, waits for volume to be detached.
+ :param timeout: Seconds to wait for volume detachment. None is forever.
+
+ :return: True on success.
+ """
try:
- get_nova_client().volumes.delete_server_volume(server_id, volume_id)
+ volume = shade_client.get_volume(volume_name_or_id)
+ server = get_server(shade_client, name_or_id=server_name_or_id)
+ shade_client.detach_volume(server, volume, wait=wait, timeout=timeout)
return True
- except Exception: # pylint: disable=broad-except
- log.exception("Error [detach_server_volume(nova_client, '%s', '%s')]",
- server_id, volume_id)
+ except (exc.OpenStackCloudException, exc.OpenStackCloudTimeout) as o_exc:
+ log.error("Error [detach_volume(shade_client)]. "
+ "Exception message: %s", o_exc.orig_message)
return False