Esempio n. 1
0
 def __init__(self, images_client, images_config):
     super(ImagesBehaviors, self).__init__()
     self.config = images_config
     self.client = images_client
     self.resources = ResourcePool()
     self.error_msg = Messages.ERROR_MSG
     self.id_regex = re.compile(ImageProperties.ID_REGEX)
Esempio n. 2
0
 def __init__(self, images_client, images_config):
     super(ImagesBehaviors, self).__init__()
     self.config = images_config
     self.client = images_client
     self.resources = ResourcePool()
     self.error_msg = Messages.ERROR_MSG
     self.id_regex = re.compile(ImageProperties.ID_REGEX)
Esempio n. 3
0
 def __init__(self, bobby_config, bobby_client):
     """
     Instantiate config and client
     """
     super(BobbyBehaviors, self).__init__()
     self.bobby_config = bobby_config
     self.bobby_client = bobby_client
     self.resources = ResourcePool()
Esempio n. 4
0
    def setUpClass(cls):
        super(ComputeFixture, cls).setUpClass()
        cls.flavors_config = FlavorsConfig()
        cls.images_config = ImagesConfig()
        cls.servers_config = ServersConfig()
        cls.compute_endpoint = ComputeEndpointConfig()
        cls.marshalling = MarshallingConfig()
        cls.config_drive_config = ConfigDriveConfig()

        cls.flavor_ref = cls.flavors_config.primary_flavor
        cls.flavor_ref_alt = cls.flavors_config.secondary_flavor
        cls.image_ref = cls.images_config.primary_image
        cls.image_ref_alt = cls.images_config.secondary_image
        cls.disk_path = cls.servers_config.instance_disk_path

        cls.endpoint_config = UserAuthConfig()
        cls.user_config = UserConfig()
        access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                   cls.user_config)
        # If authentication fails, halt
        if access_data is None:
            cls.assertClassSetupFailure('Authentication failed.')

        compute_service = access_data.get_service(
            cls.compute_endpoint.compute_endpoint_name)
        url = compute_service.get_endpoint(
            cls.compute_endpoint.region).public_url
        # If a url override was provided, use that value instead
        if cls.compute_endpoint.compute_endpoint_url:
            url = '{0}/{1}'.format(cls.compute_endpoint.compute_endpoint_url,
                                   cls.user_config.tenant_id)

        client_args = {'url': url, 'auth_token': access_data.token.id_,
                       'serialize_format': cls.marshalling.serializer,
                       'deserialize_format': cls.marshalling.deserializer}

        cls.flavors_client = FlavorsClient(**client_args)
        cls.servers_client = ServersClient(**client_args)
        cls.images_client = ImagesClient(**client_args)
        cls.keypairs_client = KeypairsClient(**client_args)
        cls.security_groups_client = SecurityGroupsClient(**client_args)
        cls.security_group_rule_client = SecurityGroupRulesClient(
            **client_args)
        cls.rescue_client = RescueClient(**client_args)
        cls.vnc_client = VncConsoleClient(**client_args)
        cls.console_output_client = ConsoleOutputClient(**client_args)
        cls.server_behaviors = ServerBehaviors(cls.servers_client,
                                               cls.servers_config,
                                               cls.images_config,
                                               cls.flavors_config)
        cls.image_behaviors = ImageBehaviors(cls.images_client,
                                             cls.servers_client,
                                             cls.images_config)
        cls.config_drive_behaviors = ConfigDriveBehaviors(cls.servers_client,
                                                          cls.servers_config,
                                                          cls.server_behaviors)
        cls.flavors_client.add_exception_handler(ExceptionHandler())
        cls.resources = ResourcePool()
Esempio n. 5
0
    def setUpClass(cls):
        super(ComputeFixture, cls).setUpClass()
        cls.compute = ComputeComposite()

        # Configs
        cls.flavors_config = cls.compute.flavors.config
        cls.images_config = cls.compute.images.config
        cls.servers_config = cls.compute.servers.config
        cls.volumes_config = VolumesAPIConfig()
        cls.compute_endpoint = ComputeEndpointConfig()
        cls.marshalling = MarshallingConfig()
        cls.config_drive_config = cls.compute.config_drive.config
        cls.cloud_init_config = cls.compute.config_drive.cloud_init_config
        cls.user_config = cls.compute.user
        cls.security_groups_config = cls.compute.security_groups.config

        # Common config values
        cls.flavor_ref = cls.flavors_config.primary_flavor
        cls.flavor_ref_alt = cls.flavors_config.secondary_flavor
        cls.image_ref = cls.images_config.primary_image
        cls.image_ref_alt = cls.images_config.secondary_image
        cls.bootable_volume_ref = cls.volumes_config.primary_bootable_volume

        cls.disk_path = cls.servers_config.instance_disk_path
        cls.split_ephemeral_disk_enabled = \
            cls.servers_config.split_ephemeral_disk_enabled
        cls.ephemeral_disk_max_size = \
            cls.servers_config.ephemeral_disk_max_size
        cls.disk_format_type = cls.servers_config.disk_format_type
        cls.expected_networks = cls.servers_config.expected_networks
        cls.file_injection_enabled = \
            cls.servers_config.personality_file_injection_enabled
        cls.keep_resources_on_failure =\
            cls.servers_config.keep_resources_on_failure
        cls.compute_exception_handler = ExceptionHandler()

        # Clients
        cls.flavors_client = cls.compute.flavors.client
        cls.servers_client = cls.compute.servers.client
        cls.boot_from_volume_client = cls.compute.boot_from_volume.client
        cls.images_client = cls.compute.images.client
        cls.keypairs_client = cls.compute.keypairs.client
        cls.security_groups_client = cls.compute.security_groups.client
        cls.security_group_rule_client = \
            cls.compute.security_groups.rules_client
        cls.volume_attachments_client = cls.compute.volume_attachments.client
        cls.rescue_client = cls.compute.rescue.client
        cls.vnc_client = cls.compute.vnc_console.client
        cls.console_output_client = cls.compute.console_output.client
        cls.limits_client = cls.compute.limits.client
        cls.server_behaviors = cls.compute.servers.behaviors
        cls.volume_server_behaviors = cls.compute.boot_from_volume.behaviors
        cls.image_behaviors = cls.compute.images.behaviors
        cls.config_drive_behaviors = cls.compute.config_drive.behaviors
        cls.flavors_client.add_exception_handler(cls.compute_exception_handler)
        cls.resources = ResourcePool()
        cls.addClassCleanup(cls.resources.release)
Esempio n. 6
0
class ImagesV2Behaviors(BaseBehavior):
    """
    @summary: Base Behaviors class for Images V2 API tests
    """

    def __init__(self, images_client, images_config):
        super(ImagesV2Behaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()

    def register_basic_image(self):
        """Register a basic image and return its id."""
        response = self.client.create_image(
            name=rand_name('basic_image_'),
            container_format=ImageContainerFormat.BARE,
            disk_format=ImageDiskFormat.RAW)

        image = response.entity

        self.resources.add(self.client.delete_image, image.id_)

        return image.id_

    def register_private_image(self):
        """Register a private image and return its id."""
        response = self.client.create_image(
            name=rand_name('private_image_'),
            visibility=ImageVisibility.PRIVATE,
            container_format=ImageContainerFormat.BARE,
            disk_format=ImageDiskFormat.RAW)

        image = response.entity

        self.resources.add(self.client.delete_image, image.id_)

        return image.id_

    def get_member_ids(self, image_id):
        """Return the list of ids for all available members for an image."""
        response = self.client.list_members(image_id)

        return [member.member_id for member in response.entity]
Esempio n. 7
0
    def setUpClass(cls):
        super(BareMetalFixture, cls).setUpClass()
        cls.bare_metal = BareMetalComposite()

        cls.chassis_client = cls.bare_metal.chassis.client
        cls.drivers_client = cls.bare_metal.drivers.client
        cls.nodes_client = cls.bare_metal.nodes.client
        cls.ports_client = cls.bare_metal.ports.client

        cls.resources = ResourcePool()
        cls.addClassCleanup(cls.resources.release)
Esempio n. 8
0
    def setUpClass(cls):
        super(ImagesV2Fixture, cls).setUpClass()
        cls.config = ImagesConfig()
        cls.resources = ResourcePool()

        access_data = AuthProvider.get_access_data()

        cls.images_endpoint = '{base_url}/v2'.format(
            base_url=cls.config.base_url)

        cls.api_client = ImagesV2Client(cls.images_endpoint,
                                        access_data.token.id_,
                                        'json', 'json')
Esempio n. 9
0
    def setUpClass(cls):
        super(ImagesFixture, cls).setUpClass()
        cls.resources = ResourcePool()

        cls.user_one = ImagesAuthComposite()
        cls.user_two = ImagesAuthCompositeAltOne()
        cls.user_three = ImagesAuthCompositeAltTwo()

        cls.images = ImagesComposite(cls.user_one)
        cls.images_alt_one = ImagesComposite(cls.user_two)
        cls.images_alt_two = ImagesComposite(cls.user_three)

        cls.addClassCleanup(cls.resources.release)
Esempio n. 10
0
    def setUpClass(cls):
        super(ImagesFixture, cls).setUpClass()
        cls.images_config = ImagesConfig()
        cls.marshalling = MarshallingConfig()
        cls.endpoint_config = UserAuthConfig()
        cls.user_config = UserConfig()
        cls.alt_user_config = AltUserConfig()
        cls.third_user_config = ThirdUserConfig()
        cls.resources = ResourcePool()
        cls.serialize_format = cls.marshalling.serializer
        cls.deserialize_format = cls.marshalling.deserializer

        cls.user_list = cls.generate_user_list(cls.images_config.account_list)

        cls.access_data = cls.user_list['user'][cls.ACCESS_DATA]
        cls.images_client = cls.user_list['user'][cls.CLIENT]
        cls.images_behavior = cls.user_list['user'][cls.BEHAVIOR]
        cls.tenant_id = cls.access_data.token.tenant.id_
        cls.addClassCleanup(cls.images_behavior.resources.release)

        if cls.user_list.get('alt_user'):
            cls.alt_access_data = cls.user_list['alt_user'][cls.ACCESS_DATA]
            cls.alt_images_client = cls.user_list['alt_user'][cls.CLIENT]
            cls.alt_images_behavior = cls.user_list['alt_user'][cls.BEHAVIOR]
            cls.alt_tenant_id = cls.alt_access_data.token.tenant.id_
            cls.addClassCleanup(cls.alt_images_behavior.resources.release)

        if cls.user_list.get('third_user'):
            cls.third_access_data = (
                cls.user_list['third_user'][cls.ACCESS_DATA])
            cls.third_images_client = cls.user_list['third_user'][cls.CLIENT]
            cls.third_images_behavior = (
                cls.user_list['third_user'][cls.BEHAVIOR])
            cls.third_tenant_id = cls.third_access_data.token.tenant.id_
            cls.addClassCleanup(cls.third_images_behavior.resources.release)

        cls.error_msg = Messages.ERROR_MSG
        cls.id_regex = re.compile(ImageProperties.ID_REGEX)
        cls.import_from = cls.images_config.import_from
        cls.import_from_bootable = cls.images_config.import_from_bootable
        cls.import_from_format = cls.images_config.import_from_format
        cls.export_to = cls.images_config.export_to
        cls.max_created_at_delta = cls.images_config.max_created_at_delta
        cls.max_expires_at_delta = cls.images_config.max_expires_at_delta
        cls.max_updated_at_delta = cls.images_config.max_updated_at_delta
        cls.test_file = cls.read_data_file(cls.images_config.test_file)

        cls.addClassCleanup(cls.resources.release)

        cls.exception_handler = ExceptionHandler()
        cls.images_client.add_exception_handler(cls.exception_handler)
Esempio n. 11
0
    def setUpClass(cls):
        super(NetworkingFixture, cls).setUpClass()
        cls.net = NetworkingComposite()

        # base config from networking/networks/common/config.py
        cls.config = cls.net.config

        # sub-composites
        cls.networks = cls.net.networks
        cls.subnets = cls.net.subnets
        cls.ports = cls.net.ports

        # base behavior from networking/networks/common/behaviors.py to be
        # used by child behaviors mainly, still, it can be accessed in the
        # composite at cls.net.common.behaviors

        # Integrated API behavior methods for networks, subnets and ports
        # from /networking/networks/behaviors.py
        cls.behaviors = cls.net.behaviors

        # Other reusable values (service_network_id aka Private Network)
        cls.public_network_id = cls.net.networks.config.public_network_id
        cls.service_network_id = cls.net.networks.config.service_network_id

        # Lists to add networks, subnets and ports IDs for resource deletes
        # by the networkingCleanUp method
        cls.delete_networks = []
        cls.failed_networks = []
        cls.delete_subnets = []
        cls.failed_subnets = []
        cls.delete_ports = []
        cls.failed_ports = []
        cls.delete_secgroups = []
        cls.failed_secgroups = []
        cls.delete_secgroups_rules = []
        cls.failed_secgroups_rules = []

        # Getting user data for testing
        cls.user = cls.net.networking_auth_composite()
        cls.alt_user = NetworkingSecondUserConfig()

        # Using the networkingCleanup method
        cls.addClassCleanup(cls.networkingCleanUp)

        # For resources delete management like Compute, Images or alternative
        # to the networkingCleanUp
        cls.resources = ResourcePool()
        cls.addClassCleanup(cls.resources.release_lifo)
Esempio n. 12
0
    def setUpClass(cls):
        super(ComputeFixture, cls).setUpClass()
        cls.flavors_config = FlavorsConfig()
        cls.images_config = ImagesConfig()
        cls.servers_config = ServersConfig()
        cls.compute_endpoint = ComputeEndpointConfig()

        cls.flavor_ref = cls.flavors_config.primary_flavor
        cls.flavor_ref_alt = cls.flavors_config.secondary_flavor
        cls.image_ref = cls.images_config.primary_image
        cls.image_ref_alt = cls.images_config.secondary_image
        cls.disk_path = cls.servers_config.instance_disk_path

        cls.endpoint_config = UserAuthConfig()
        user_config = UserConfig()
        access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                   user_config)

        compute_service = access_data.get_service(
            cls.compute_endpoint.compute_endpoint_name)
        url = compute_service.get_endpoint(
            cls.compute_endpoint.region).public_url
        cls.flavors_client = FlavorsClient(url, access_data.token.id_, 'json',
                                           'json')
        cls.servers_client = ServersClient(url, access_data.token.id_, 'json',
                                           'json')
        cls.images_client = ImagesClient(url, access_data.token.id_, 'json',
                                         'json')
        cls.keypairs_client = KeypairsClient(url, access_data.token.id_,
                                             'json', 'json')
        cls.sec_groups_client = SecurityGroupsClient(url,
                                                     access_data.token.id_,
                                                     'json', 'json')
        cls.rescue_client = RescueClient(url, access_data.token.id_, 'json',
                                         'json')
        cls.server_behaviors = ServerBehaviors(cls.servers_client,
                                               cls.servers_config,
                                               cls.images_config,
                                               cls.flavors_config)
        cls.image_behaviors = ImageBehaviors(cls.images_client,
                                             cls.servers_client,
                                             cls.images_config)
        cls.flavors_client.add_exception_handler(ExceptionHandler())
        cls.resources = ResourcePool()
Esempio n. 13
0
    def setUpClass(cls):
        super(BareMetalFixture, cls).setUpClass()
        cls.marshalling = MarshallingConfig()
        cls.bare_metal_endpoint = BareMetalEndpointConfig()

        cls.endpoint_config = UserAuthConfig()
        cls.user_config = UserConfig()
        cls.access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                       cls.user_config)

        # If authentication fails, halt
        if cls.access_data is None:
            cls.assertClassSetupFailure('Authentication failed.')

        bare_metal_service = cls.access_data.get_service(
            cls.bare_metal_endpoint.bare_metal_endpoint_name)
        url = bare_metal_service.get_endpoint(
            cls.bare_metal_endpoint.region).public_url

        # If a url override was provided, use that value instead
        if cls.bare_metal_endpoint.bare_metal_endpoint_url:
            url = cls.bare_metal_endpoint.bare_metal_endpoint_url

        client_args = {
            'url': url,
            'auth_token': cls.access_data.token.id_,
            'serialize_format': cls.marshalling.serializer,
            'deserialize_format': cls.marshalling.deserializer
        }

        cls.chassis_client = ChassisClient(**client_args)
        cls.drivers_client = DriversClient(**client_args)
        cls.nodes_client = NodesClient(**client_args)
        cls.ports_client = PortsClient(**client_args)

        cls.resources = ResourcePool()
        cls.addClassCleanup(cls.resources.release)
Esempio n. 14
0
    def setUpClass(cls):
        super(ImagesFixture, cls).setUpClass()
        cls.images_config = ImagesConfig()
        cls.marshalling = MarshallingConfig()
        cls.endpoint_config = UserAuthConfig()
        cls.user_config = UserConfig()
        cls.alt_user_config = AltUserConfig()
        cls.third_user_config = ThirdUserConfig()
        cls.resources = ResourcePool()
        cls.serialize_format = cls.marshalling.serializer
        cls.deserialize_format = cls.marshalling.deserializer

        cls.access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                       cls.user_config)
        # If authentication fails, fail immediately
        if cls.access_data is None:
            cls.assertClassSetupFailure('Authentication failed')

        cls.alt_access_data = AuthProvider.get_access_data(
            cls.endpoint_config, cls.alt_user_config)
        # If authentication fails, fail immediately
        if cls.alt_access_data is None:
            cls.assertClassSetupFailure('Authentication failed')
        cls.third_access_data = AuthProvider.get_access_data(
            cls.endpoint_config, cls.third_user_config)
        # If authentication fails, fail immediately
        if cls.third_access_data is None:
            cls.assertClassSetupFailure('Authentication failed')

        images_service = cls.access_data.get_service(
            cls.images_config.endpoint_name)

        images_url_check = images_service.get_endpoint(
            cls.images_config.region)
        # If endpoint validation fails, fail immediately
        if images_url_check is None:
            cls.assertClassSetupFailure('Endpoint validation failed')

        cls.url = (images_service.get_endpoint(
            cls.images_config.region).public_url)
        # If a url override was provided, use it instead
        if cls.images_config.override_url:
            cls.url = cls.images_config.override_url

        cls.images_client = cls.generate_images_client(cls.access_data)
        cls.alt_images_client = cls.generate_images_client(cls.alt_access_data)
        cls.third_images_client = cls.generate_images_client(
            cls.third_access_data)

        cls.images_behavior = ImagesBehaviors(images_client=cls.images_client,
                                              images_config=cls.images_config)
        cls.alt_images_behavior = ImagesBehaviors(
            images_client=cls.alt_images_client,
            images_config=cls.images_config)
        cls.third_images_behavior = ImagesBehaviors(
            images_client=cls.third_images_client,
            images_config=cls.images_config)

        cls.alt_tenant_id = cls.alt_access_data.token.tenant.id_
        cls.error_msg = Messages.ERROR_MSG
        cls.export_to = cls.images_config.export_to
        cls.id_regex = re.compile(ImageProperties.ID_REGEX)
        cls.import_from = cls.images_config.import_from
        cls.import_from_bootable = cls.images_config.import_from_bootable
        cls.import_from_format = cls.images_config.import_from_format
        cls.max_created_at_delta = cls.images_config.max_created_at_delta
        cls.max_expires_at_delta = cls.images_config.max_expires_at_delta
        cls.max_updated_at_delta = cls.images_config.max_updated_at_delta
        cls.tenant_id = cls.access_data.token.tenant.id_
        cls.third_tenant_id = cls.third_access_data.token.tenant.id_

        cls.test_file = cls.read_data_file(cls.images_config.test_file)
        cls.image_schema_json = cls.read_data_file(
            cls.images_config.image_schema_json)
        cls.images_schema_json = cls.read_data_file(
            cls.images_config.images_schema_json)
        cls.image_member_schema_json = cls.read_data_file(
            cls.images_config.image_member_schema_json)
        cls.image_members_schema_json = cls.read_data_file(
            cls.images_config.image_members_schema_json)
        cls.task_schema_json = cls.read_data_file(
            cls.images_config.task_schema_json)
        cls.tasks_schema_json = cls.read_data_file(
            cls.images_config.tasks_schema_json)

        cls.addClassCleanup(cls.resources.release)
        cls.addClassCleanup(cls.images_behavior.resources.release)
        cls.addClassCleanup(cls.alt_images_behavior.resources.release)
        cls.addClassCleanup(cls.third_images_behavior.resources.release)
Esempio n. 15
0
class BobbyBehaviors(BaseBehavior):

    """
    :summary: Behavior Module for the Bobby REST API
    :note: Should be the primary interface to a test case or external tool
    """

    def __init__(self, bobby_config, bobby_client):
        """
        Instantiate config and client
        """
        super(BobbyBehaviors, self).__init__()
        self.bobby_config = bobby_config
        self.bobby_client = bobby_client
        self.resources = ResourcePool()

    def create_bobby_group_given(self, group_id=None, notification=None, notification_plan=None):
        """
        Creates a bobby group with the given values
        """
        group_id = group_id or rand_name("012345DIFF-78f3-4543-85bc1-")
        notification = notification or self.bobby_config.notification
        notification_plan = notification_plan or self.bobby_config.notification_plan
        bobby_group = self.bobby_client.create_group(
            group_id=group_id, notification=notification, notification_plan=notification_plan
        )
        self.resources.add(group_id, self.bobby_client.delete_group)
        return bobby_group.entity

    def create_bobby_server_group_given(self, group_id=None, server_id=None, entity_id=None):
        """
        Creates a bobby group with the given values
        """
        group_id = group_id or self.bobby_config.group_id
        server_id = server_id or rand_name("0123SERVER-78f3-4543-85bc1-")
        entity_id = entity_id or rand_name("0123ENTITY-78f3-4543-85bc1-")
        bobby_server_group = self.bobby_client.create_server_group(
            group_id=group_id, entity_id=entity_id, server_id=server_id
        )
        self.resources.add(group_id, self.bobby_client.delete_group)
        return bobby_server_group

    def create_bobby_policy_given(self, group_id=None, policy_id=None, alarm_template=None, check_template=None):
        """
        Creates a policy in bobby with the given values
        """
        group_id = group_id or self.bobby_config.group_id
        policy_id = policy_id or rand_name("0123POLICY-78f3-4543-85bc1-")
        check_template = (
            check_template
            or "7867"
            or {
                "label": "Website check 1",
                "type": "remote.http",
                "details": {"url": "http://www.foo.com", "method": "GET"},
                "monitoring_zones_poll": ["mzA"],
                "timeout": 30,
                "period": 100,
                "target_alias": "default",
            }
        )
        alarm_template = (
            alarm_template
            or "8787"
            or {
                "criteria": 'if (metric["duration"] >= 2) { return new AlarmStatus(OK); }'
                " return new AlarmStatus(CRITICAL);"
            }
        )
        bobby_policy = self.bobby_client.create_bobby_policy(
            group_id=group_id, policy_id=policy_id, check_template=check_template, alarm_template=alarm_template
        )
        self.resources.add(group_id, self.bobby_client.delete_group)
        return bobby_policy
Esempio n. 16
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors for Images"""

    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()

    @staticmethod
    def get_comparison_data(data_file):
        """
        @summary: Create comparison dictionary based on a given set of data

        @param data_file: File containing data to compare
        @param data_file: String

        @return: Comparison_dict
        @rtype: Dictionary
        """

        comparison_dict = dict()
        data_columns = []

        with open(data_file, "r") as DATA:
            all_data = DATA.readlines()

        for line in all_data:
            # Skip any comments or short lines
            if line.startswith("#") or len(line) < 5:
                continue

            # Get the defined data
            if line.startswith("+"):
                line = line.replace("+", "")
                data_columns = [x.strip().lower() for x in line.split("|")]
                continue

            # Process the data
            each_data = dict()
            data = [x.strip() for x in line.split("|")]
            for x, y in zip(data_columns[1:], data[1:]):
                each_data[x] = y

            comparison_dict[data[0]] = each_data

        return comparison_dict

    def create_image_via_task(self, image_properties=None, import_from=None):
        """
        @summary: Create new image via task

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String

        @return: Image
        @rtype: Object
        """

        image_properties = image_properties or {"name": rand_name("image")}
        import_from = import_from or self.config.import_from

        input_ = {"image_properties": image_properties, "import_from": import_from}
        task = self.create_new_task(input_=input_, type_=TaskTypes.IMPORT)
        image_id = task.result.image_id

        self.client.add_image_tag(image_id=image_id, tag=rand_name("tag"))

        resp = self.client.get_image_details(image_id=image_id)
        image = self.verify_resp(resp, "get image details", image_id)

        return image

    def create_images_via_task(self, image_properties=None, import_from=None, count=2):
        """
        @summary: Create new images via tasks

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String
        @param count: Number of images to create
        @type count: Integer

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.create_image_via_task(image_properties=image_properties, import_from=import_from)
            image_list.append(image)

        return image_list

    def register_new_image(
        self,
        auto_disk_config=None,
        checksum=None,
        container_format=None,
        created_at=None,
        disk_format=None,
        file_=None,
        id_=None,
        image_type=None,
        min_disk=None,
        min_ram=None,
        name=None,
        os_type=None,
        owner=None,
        protected=None,
        schema=None,
        self_=None,
        size=None,
        status=None,
        tags=None,
        updated_at=None,
        user_id=None,
        visibility=None,
        additional_properties=None,
    ):
        """
        @summary: Register new image and add it for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image
        @rtype: Object
        """

        container_format = container_format or ImageContainerFormat.BARE
        disk_format = disk_format or ImageDiskFormat.RAW
        name = name or rand_name("image")

        resp = self.client.register_image(
            auto_disk_config=auto_disk_config,
            checksum=checksum,
            container_format=container_format,
            created_at=created_at,
            disk_format=disk_format,
            file_=file_,
            id_=id_,
            image_type=image_type,
            min_disk=min_disk,
            min_ram=min_ram,
            name=name,
            os_type=os_type,
            owner=owner,
            protected=protected,
            schema=schema,
            self_=self_,
            size=size,
            status=status,
            tags=tags,
            updated_at=updated_at,
            user_id=user_id,
            visibility=visibility,
            additional_properties=additional_properties,
        )
        image = self.verify_resp(resp, "register image")

        self.resources.add(image.id_, self.client.delete_image)

        return image

    def register_new_images(
        self,
        auto_disk_config=None,
        checksum=None,
        container_format=None,
        created_at=None,
        disk_format=None,
        file_=None,
        id_=None,
        image_type=None,
        min_disk=None,
        min_ram=None,
        name=None,
        os_type=None,
        owner=None,
        protected=None,
        schema=None,
        self_=None,
        size=None,
        status=None,
        tags=None,
        updated_at=None,
        user_id=None,
        visibility=None,
        additional_properties=None,
        count=2,
    ):
        """
        @summary: Register new images and add them for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.register_new_image(
                auto_disk_config=auto_disk_config,
                checksum=checksum,
                container_format=container_format,
                created_at=created_at,
                disk_format=disk_format,
                file_=file_,
                id_=id_,
                image_type=image_type,
                min_disk=min_disk,
                min_ram=min_ram,
                name=name,
                os_type=os_type,
                owner=owner,
                protected=protected,
                schema=schema,
                self_=self_,
                size=size,
                status=status,
                tags=tags,
                updated_at=updated_at,
                user_id=user_id,
                visibility=visibility,
                additional_properties=additional_properties,
            )
            image_list.append(image)

        return image_list

    def list_all_images(self, url_addition=None, **params):
        """
        @summary: Retrieve a complete list of images accounting for any
        query parameters

        @param url_addition: Additional text to be added to the end of the url
        to account for duplicate sort parameters
        @type url_addition: String
        @param params: Parameters to alter the returned list of images
        @type params: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []
        results_limit = self.config.results_limit
        params.update({"limit": results_limit})

        resp = self.client.list_images(params, url_addition)
        images = self.verify_resp(resp, "list images")

        while len(images) == results_limit:
            image_list += images

            marker = images[results_limit - 1].id_
            params.update({"marker": marker})

            resp = self.client.list_images(params, url_addition)
            images = self.verify_resp(resp, "list images")

        image_list += images

        return image_list

    @staticmethod
    def get_time_delta(time_in_sec, time_property):
        """
        @summary: Calculate the difference between an image attribute's time
        value and a time_property

        @param time_in_sec: Current time in seconds
        @type time_in_sec: Integer
        @param time_property: Image property containing a time
        @type time_property: Datetime

        @return: Time_delta
        @rtype: Integer
        """

        time_property_in_sec = calendar.timegm(time_property.timetuple())

        return abs(time_property_in_sec - time_in_sec)

    @staticmethod
    def validate_image(image):
        """
        @summary: Generically validate an image contains crucial expected
        data

        @param image: Image to be validated
        @type image: Object

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        # The following properties do not always have values:
        # checksum, container_format, disk_format, name, tags

        if image.auto_disk_config is None:
            errors.append(Messages.PROPERTY_MSG.format("auto_disk_config", "not None", image.auto_disk_config))
        if image.created_at is None:
            errors.append(Messages.PROPERTY_MSG.format("created_at", "not None", image.created_at))
        if image.file_ != "/v2/images/{0}/file".format(image.id_):
            errors.append(Messages.PROPERTY_MSG.format("file", "/v2/images/{0}/file".format(image.id_), image.file_))
        if id_regex.match(image.id_) is None:
            errors.append(Messages.PROPERTY_MSG.format("id", "not None", id_regex))
        if image.image_type is None:
            errors.append(Messages.PROPERTY_MSG.format("image_type", "not None", image.image_type))
        if image.min_disk is None:
            errors.append(Messages.PROPERTY_MSG.format("min_disk", "not None", image.min_disk))
        if image.min_ram is None:
            errors.append(Messages.PROPERTY_MSG.format("min_ram", "not None", image.min_ram))
        if image.os_type is None:
            errors.append(Messages.PROPERTY_MSG.format("os_type", "not None", image.os_type))
        if image.owner is None:
            errors.append(Messages.PROPERTY_MSG.format("owner", "not None", image.owner))
        if image.protected is None:
            errors.append(Messages.PROPERTY_MSG.format("protected", "not None", image.protected))
        if image.schema != Schemas.IMAGE_SCHEMA:
            errors.append(Messages.PROPERTY_MSG.format("schema", Schemas.IMAGE_SCHEMA, image.schema))
        if image.self_ != "/v2/images/{0}".format(image.id_):
            errors.append(Messages.PROPERTY_MSG.format("self", "/v2/images/{0}".format(image.id_), image.self_))
        if image.status is None:
            errors.append(Messages.PROPERTY_MSG.format("status", "not None", image.status))
        if image.updated_at is None:
            errors.append(Messages.PROPERTY_MSG.format("updated_at", "not None", image.updated_at))
        if image.user_id is None:
            errors.append(Messages.PROPERTY_MSG.format("user_id", "not None", image.user_id))
        if image.virtual_size is not None:
            errors.append(Messages.PROPERTY_MSG.format("virtual_size", "None", image.virtual_size))
        if image.visibility is None:
            errors.append(Messages.PROPERTY_MSG.format("visibility", "not None", image.visibility))

        return errors

    @staticmethod
    def validate_image_member(image_member):
        """
        @summary: Generically validate an image member contains crucial
        expected data

        @param image_member: Image member to be validated
        @type image_member: Object

        @return: Errors
        @rtype: List
        """

        errors = []

        if image_member.created_at is None:
            errors.append(Messages.PROPERTY_MSG.format("created_at", "not None", image_member.created_at))
        if image_member.image_id is None:
            errors.append(Messages.PROPERTY_MSG.format("image_id", "not None", image_member.image_id))
        if image_member.member_id is None:
            errors.append(Messages.PROPERTY_MSG.format("member_id", "not None", image_member.member_id))
        if image_member.schema != Schemas.IMAGE_MEMBER_SCHEMA:
            errors.append(Messages.PROPERTY_MSG.format("schema", Schemas.IMAGE_MEMBER_SCHEMA, image_member.schema))
        if image_member.status is None:
            errors.append(Messages.PROPERTY_MSG.format("status", "not None", image_member.status))
        if image_member.updated_at is None:
            errors.append(Messages.PROPERTY_MSG.format("updated_at", "not None", image_member.updated_at))

        return errors

    def wait_for_image_status(self, image_id, desired_status, interval_time=15, timeout=900):
        """
        @summary: Wait for a image to reach a desired status

        @param image_id: Image id to evaluate
        @type image_id: UUID
        @param desired_status: Expected final status of image
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer

        @return: Resp
        @rtype: Object
        """

        interval_time = interval_time or self.config.image_status_interval
        timeout = timeout or self.config.snapshot_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_image_details(image_id)
            image = self.verify_resp(resp, "get image details", image_id)

            if image.status.lower() == ImageStatus.ERROR.lower():
                raise BuildErrorException("Image with the uuid {0} entered ERROR " "status.".format(image_id))

            if image.status == desired_status:
                break

            time.sleep(interval_time)
        else:
            raise TimeoutException(
                "Image with the uuid {0} did not reach the {1} status within "
                "{2} seconds.".format(image_id, desired_status, timeout)
            )

        return resp

    def create_new_task(self, input_=None, type_=None):
        """
        @summary: Create new task and wait for success status

        @param input_: Image properties and location data
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String

        @return: Task
        @rtype: Object
        """

        import_from = self.config.import_from
        input_ = input_ or {"image_properties": {}, "import_from": import_from}
        type_ = type_ or TaskTypes.IMPORT
        failures = []
        attempts = self.config.resource_creation_attempts

        for attempt in range(attempts):
            try:
                if type_ == TaskTypes.IMPORT:
                    resp = self.client.task_to_import_image(input_=input_, type_=type_)
                else:
                    resp = self.client.task_to_export_image(input_=input_, type_=type_)
                task = resp.entity

                task = self.wait_for_task_status(task.id_, TaskStatus.SUCCESS)

                return task

            except (BuildErrorException, TimeoutException) as ex:
                failure = "Attempt {0}: Failed to create task with " "the message {1}".format(attempt + 1, ex.message)
                self._log.error(failure)
                failures.append(failure)

        raise RequiredResourceException(
            "Failed to successfully create a task after {0} attempts: " "{1}".format(attempts, failures)
        )

    def create_new_tasks(self, input_=None, type_=None, count=2):
        """
        @summary: Create new tasks and wait for success status for each

        @param input_: Image properties and image location
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String
        @param count: Number of tasks to create
        @type count: Integer

        @return: Task_list
        @rtype: List
        """

        task_list = []

        for i in range(count):
            task = self.create_new_task(input_=input_, type_=type_)
            task_list.append(task)

        return task_list

    def list_all_tasks(self, **params):
        """
        @summary: Retrieve a complete list of tasks accounting for query
        parameters

        @param params: Parameters to alter the returned list of images
        @type params: Dictionary

        @return: Task_list
        @rtype: List
        """

        task_list = []
        results_limit = self.config.results_limit
        params.update({"limit": results_limit})

        resp = self.client.list_tasks(params)
        tasks = self.verify_resp(resp, "list tasks")

        while len(tasks) == results_limit:
            task_list += tasks

            marker = tasks[results_limit - 1].id_
            params.update({"marker": marker})

            resp = self.client.list_tasks(params)
            tasks = self.verify_resp(resp, "list tasks")

        task_list += tasks

        return task_list

    @staticmethod
    def validate_task(task):
        """
        @summary: Generically validate a task contains crucial expected
        data

        @param task: Task to be validated
        @type task: UUID

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        if task.status is None:
            errors.append(Messages.PROPERTY_MSG.format("status", "not None", task.status))
        if id_regex.match(task.id_) is None:
            errors.append(Messages.PROPERTY_MSG.format("id_", "not None", id_regex.match(task.id_)))
        if task.created_at is None:
            errors.append(Messages.PROPERTY_MSG.format("created_at", "not None", task.created_at))
        if task.type_ == TaskTypes.IMPORT:
            if task.input_.import_from is None:
                errors.append(Messages.PROPERTY_MSG.format("import_from", "not None", task.input_.import_from))
            if task.result is not None and id_regex.match(task.result.image_id) is None:
                errors.append(
                    Messages.PROPERTY_MSG.format("image_id", "not None", id_regex.match(task.result.image_id))
                )
        elif task.type_ == TaskTypes.EXPORT:
            if task.input_.image_uuid is None:
                errors.append(Messages.PROPERTY_MSG.format("image_uuid", "not None", task.input_.image_uuid))
            if task.input_.receiving_swift_container is None:
                errors.append(
                    Messages.PROPERTY_MSG.format(
                        "receiving_swift_container", "not None", task.input_.receiving_swift_container
                    )
                )
            if task.result is not None and task.result.export_location is None:
                errors.append(Messages.PROPERTY_MSG.format("export_location", "not None", task.result.export_location))
        elif task.type_ is None:
            errors.append(Messages.PROPERTY_MSG.format("type_", "not None", task.type_))
        if task.updated_at is None:
            errors.append(Messages.PROPERTY_MSG.format("updated_at", "not None", task.updated_at))
        if task.self_ != "/v2/tasks/{0}".format(task.id_):
            errors.append(Messages.PROPERTY_MSG.format("self_", "/v2/tasks/{0}".format(task.id_), task.self_))
        if task.owner is None:
            errors.append(Messages.PROPERTY_MSG.format("owner", "not None", task.owner))
        if task.message != "":
            errors.append(Messages.PROPERTY_MSG.format("message", "Empty message", task.message))
        if task.schema != "/v2/schemas/task":
            errors.append(Messages.PROPERTY_MSG.format("schema", "/v2/schemas/task", task.schema))

        return errors

    @staticmethod
    def validate_exported_files(expect_success, files, image_id):
        """
        @summary: Validate that a given storage location contains a
        given file or not

        @param expect_success: Flag to determine if task completed successfully
        @type expect_success: Boolean
        @param files: File objects to be validated
        @type files: List
        @param image_id: Image id to validate against
        @type image_id: UUID

        @return: Errors, file_names
        @rtype: List, list
        """

        errors = []
        file_names = [file_.name for file_ in files]

        if expect_success:
            if "{0}.vhd".format(image_id) not in file_names:
                errors.append(
                    "Expected VHD file not listed. Expected: "
                    "{0}.vhd to be listed Received: File was not "
                    "listed".format(image_id)
                )
        else:
            if "{0}.vhd".format(image_id) in file_names:
                errors.append(
                    "Unexpected VHD file listed. Expected: {0}.vhd "
                    "to not be listed Received: File was "
                    "listed".format(image_id)
                )

        return errors, file_names

    def wait_for_task_status(self, task_id, desired_status, interval_time=10, timeout=1200):
        """
        @summary: Waits for a task to reach a desired status and if the import
        task is successful, adds the created image to the resource pool for
        tear down

        @param task_id: Task id to evaluate
        @type task_id: UUID
        @param desired_status: Expected final status of task
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer

        @return: Task
        @rtype: Object
        """

        interval_time = interval_time or self.config.task_status_interval
        timeout = timeout or self.config.task_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_task_details(task_id)
            task = self.verify_resp(resp, "get task details", task_id)

            if (task.status.lower() == TaskStatus.FAILURE and desired_status != TaskStatus.FAILURE) or (
                task.status.lower() == TaskStatus.SUCCESS and desired_status != TaskStatus.SUCCESS
            ):
                raise BuildErrorException(
                    "Task with the uuid {0} entered the {1} status. Task "
                    "responded with the message {2}".format(task.id_, task.status, task.message.replace("\\", ""))
                )

            if task.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                "Task with the uuid {0} did not reach the {1} status within "
                "{2} seconds.".format(task_id, desired_status, timeout)
            )

        if task is not None and task.type_ == TaskTypes.IMPORT and task.status.lower() == TaskStatus.SUCCESS:
            self.resources.add(task.result.image_id, self.client.delete_image)

        return task

    def create_task_with_transitions(self, input_, task_type, final_status=None):
        """
        @summary: Create a task and verify that it transitions through the
        expected statuses

        @param input_: Image properties and location data
        @type input_: Dictionary
        @param task_type: Type of task
        @type task_type: String
        @param final_status: Flag to determine success or failure
        @type final_status: String

        @return: Task
        @rtype: Object
        """

        if task_type == TaskTypes.IMPORT:
            resp = self.client.task_to_import_image(input_, TaskTypes.IMPORT)
        else:
            resp = self.client.task_to_export_image(input_, TaskTypes.EXPORT)

        task = self.verify_resp(resp, "create task")

        # Verify task progresses as expected
        verifier = StatusProgressionVerifier("task", task.id_, self.get_task_status, task.id_)

        if final_status == TaskStatus.SUCCESS:
            error_statuses = [TaskStatus.FAILURE]
        else:
            error_statuses = [TaskStatus.SUCCESS]

        verifier.add_state(
            expected_statuses=[TaskStatus.PENDING],
            acceptable_statuses=[TaskStatus.PROCESSING, final_status],
            error_statuses=error_statuses,
            timeout=self.config.task_timeout,
            poll_rate=1,
        )

        if final_status == TaskStatus.SUCCESS:
            error_statuses = [TaskStatus.PENDING, TaskStatus.FAILURE]
        else:
            error_statuses = [TaskStatus.PENDING, TaskStatus.SUCCESS]

        verifier.add_state(
            expected_statuses=[TaskStatus.PROCESSING],
            acceptable_statuses=[final_status],
            error_statuses=error_statuses,
            timeout=self.config.task_timeout,
            poll_rate=1,
        )

        if final_status == TaskStatus.SUCCESS:
            verifier.add_state(
                expected_statuses=[TaskStatus.SUCCESS],
                error_statuses=[TaskStatus.PENDING, TaskStatus.FAILURE],
                timeout=self.config.task_timeout,
                poll_rate=1,
            )
        else:
            verifier.add_state(
                expected_statuses=[TaskStatus.FAILURE],
                error_statuses=[TaskStatus.PENDING, TaskStatus.SUCCESS],
                timeout=self.config.task_timeout,
                poll_rate=1,
            )

        verifier.start()

        return self.client.get_task_details(task.id_).entity

    def get_task_status(self, task_id):
        """
        @summary: Retrieve task status for the status progression verifier in
        the create_task_with_transitions method

        @param task_id: Task id
        @type task_id: UUID

        @return: Status
        @rtype: String
        """

        resp = self.client.get_task_details(task_id)
        task = self.verify_resp(resp, "get task details", task_id)

        return task.status.lower()

    @staticmethod
    def verify_resp(resp, req, obj_id=None):
        """
        @summary: Verify that a request was successful and that an entity was
        properly deserialized

        @param resp: Response object to verify
        @type resp: Object

        @return: Resp.entity
        @rtype: Object
        """

        if not resp.ok:
            msg = "Request for {0} failed with the status code " "{1}.".format(req, resp.status_code)
            raise Exception(msg)

        if resp.entity is None:
            if obj_id is None:
                msg = "Response body for {0} did not deserialize as " "expected.".format(req)
            else:
                msg = "Response body for {0} with the uuid {1} did not " "deserialize as expected.".format(req, obj_id)
            raise Exception(msg)

        return resp.entity
Esempio n. 17
0
    def setUpClass(cls):
        """
        Initialize autoscale configs, behaviors and client
        """
        super(AutoscaleFixture, cls).setUpClass()
        cls.resources = ResourcePool()
        cls.autoscale_config = autoscale_config
        cls.endpoint_config = endpoint_config

        cls.tenant_id = cls.autoscale_config.tenant_id

        cls.gc_name = cls.autoscale_config.gc_name
        cls.gc_cooldown = int(cls.autoscale_config.gc_cooldown)
        cls.gc_min_entities = int(cls.autoscale_config.gc_min_entities)
        cls.gc_min_entities_alt = int(cls.autoscale_config.gc_min_entities_alt)
        cls.gc_max_entities = int(cls.autoscale_config.gc_max_entities)
        cls.lc_name = cls.autoscale_config.lc_name
        cls.lc_flavor_ref = cls.autoscale_config.lc_flavor_ref
        cls.sp_name = rand_name(cls.autoscale_config.sp_name)
        cls.sp_cooldown = int(cls.autoscale_config.sp_cooldown)
        cls.sp_change = int(cls.autoscale_config.sp_change)
        cls.sp_change_percent = int(cls.autoscale_config.sp_change_percent)
        cls.sp_desired_capacity = int(cls.autoscale_config.sp_desired_capacity)
        cls.sp_policy_type = cls.autoscale_config.sp_policy_type
        cls.upd_sp_change = int(cls.autoscale_config.upd_sp_change)
        cls.lc_load_balancers = cls.autoscale_config.lc_load_balancers
        cls.sp_list = cls.autoscale_config.sp_list
        cls.wb_name = rand_name(cls.autoscale_config.wb_name)
        cls.interval_time = int(cls.autoscale_config.interval_time)
        cls.timeout = int(cls.autoscale_config.timeout)
        cls.scheduler_interval = OtterConstants.SCHEDULER_INTERVAL
        cls.cron_wait_timeout = 60 + cls.scheduler_interval + 5
        cls.scheduler_batch = OtterConstants.SCHEDULER_BATCH
        cls.max_maxentities = OtterConstants.MAX_MAXENTITIES
        cls.max_cooldown = OtterConstants.MAX_COOLDOWN
        cls.max_groups = OtterConstants.MAX_GROUPS
        cls.max_policies = OtterConstants.MAX_POLICIES
        cls.max_webhooks = OtterConstants.MAX_WEBHOOKS
        cls.limit_value_all = OtterConstants.LIMIT_VALUE_ALL
        cls.limit_unit_all = OtterConstants.LIMIT_UNIT_ALL
        cls.limit_value_webhook = OtterConstants.LIMIT_VALUE_WEBHOOK
        cls.limit_unit_webhook = OtterConstants.LIMIT_UNIT_WEBHOOK
        cls.pagination_limit = OtterConstants.PAGINATION_LIMIT
        cls.personality_maxlength = OtterConstants.PERSONALITY_MAXLENGTH
        cls.max_personalities = OtterConstants.PERSONALITIES_PER_SERVER
        cls.personality_max_file_size = OtterConstants.PERSONAITY_FILE_SIZE
        cls.non_autoscale_username = (
            cls.autoscale_config.non_autoscale_username)
        cls.non_autoscale_password = (
            cls.autoscale_config.non_autoscale_password)
        cls.non_autoscale_tenant = cls.autoscale_config.non_autoscale_tenant

        cls.autoscale_client = autoscale_client
        cls.server_client = server_client
        cls.lbaas_client = lbaas_client
        cls.rcv3_client = rcv3_client

        # ImageRefs of ununtu and non-ubuntu images that will be used
        # when creating groups
        image_refs = image_ids_with_and_without_name(images_client)
        cls.lc_image_ref, cls.lc_image_ref_alt = image_refs
        # Unfortunately some of the tests use imageRef from config instead of
        # this class. So, storing the same in config too
        autoscale_config.lc_image_ref = cls.lc_image_ref
        autoscale_config.lc_image_ref_alt = cls.lc_image_ref_alt

        cls.rcv3_load_balancer_pool = _rcv3_load_balancer_pool
        cls.rcv3_cloud_network = _rcv3_cloud_network

        cls.url = autoscale_client.url

        cls.autoscale_behaviors = AutoscaleBehaviors(
            autoscale_config, autoscale_client,
            rcv3_client=rcv3_client
        )
Esempio n. 18
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors for Images"""
    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()

    @staticmethod
    def get_comparison_data(data_file):
        """
        @summary: Create comparison dictionary based on a given set of data

        @param data_file: File containing data to compare
        @type data_file: String

        @return: Comparison_dict
        @rtype: Dictionary
        """

        comparison_dict = dict()
        data_columns = []

        with open(data_file, 'r') as DATA:
            all_data = DATA.readlines()

        for line in all_data:
            # Skip any comments or short lines
            if line.startswith('#') or len(line) < 5:
                continue

            # Get the defined data
            if line.startswith('+'):
                line = line.replace('+', '')
                data_columns = [x.strip().lower() for x in line.split('|')]
                continue

            # Process the data
            each_data = dict()
            data = [x.strip() for x in line.split('|')]
            for x, y in zip(data_columns[1:], data[1:]):
                each_data[x] = y

            comparison_dict[data[0]] = each_data

        return comparison_dict

    def create_image_via_task(self, image_properties=None, import_from=None):
        """
        @summary: Create new image via task

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String

        @return: Image
        @rtype: Object
        """

        image_properties = image_properties or {'name': rand_name('image')}
        import_from = import_from or self.config.import_from

        input_ = {
            'image_properties': image_properties,
            'import_from': import_from
        }
        task = self.create_new_task(input_=input_, type_=TaskTypes.IMPORT)
        image_id = task.result.image_id

        self.client.add_image_tag(image_id=image_id, tag=rand_name('tag'))

        resp = self.client.get_image_details(image_id=image_id)
        image = self.verify_resp(resp, 'get image details', image_id)

        return image

    def create_images_via_task(self,
                               image_properties=None,
                               import_from=None,
                               count=2):
        """
        @summary: Create new images via tasks

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String
        @param count: Number of images to create
        @type count: Integer

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.create_image_via_task(
                image_properties=image_properties, import_from=import_from)
            image_list.append(image)

        return image_list

    def register_new_image(self,
                           auto_disk_config=None,
                           checksum=None,
                           container_format=None,
                           created_at=None,
                           disk_format=None,
                           file_=None,
                           id_=None,
                           image_type=None,
                           min_disk=None,
                           min_ram=None,
                           name=None,
                           os_type=None,
                           owner=None,
                           protected=None,
                           schema=None,
                           self_=None,
                           size=None,
                           status=None,
                           tags=None,
                           updated_at=None,
                           user_id=None,
                           visibility=None,
                           additional_properties=None):
        """
        @summary: Register new image and add it for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image
        @rtype: Object
        """

        container_format = container_format or ImageContainerFormat.BARE
        disk_format = disk_format or ImageDiskFormat.RAW
        name = name or rand_name('image')

        resp = self.client.register_image(
            auto_disk_config=auto_disk_config,
            checksum=checksum,
            container_format=container_format,
            created_at=created_at,
            disk_format=disk_format,
            file_=file_,
            id_=id_,
            image_type=image_type,
            min_disk=min_disk,
            min_ram=min_ram,
            name=name,
            os_type=os_type,
            owner=owner,
            protected=protected,
            schema=schema,
            self_=self_,
            size=size,
            status=status,
            tags=tags,
            updated_at=updated_at,
            user_id=user_id,
            visibility=visibility,
            additional_properties=additional_properties)
        image = self.verify_resp(resp, 'register image')

        self.resources.add(image.id_, self.client.delete_image)

        return image

    def register_new_images(self,
                            auto_disk_config=None,
                            checksum=None,
                            container_format=None,
                            created_at=None,
                            disk_format=None,
                            file_=None,
                            id_=None,
                            image_type=None,
                            min_disk=None,
                            min_ram=None,
                            name=None,
                            os_type=None,
                            owner=None,
                            protected=None,
                            schema=None,
                            self_=None,
                            size=None,
                            status=None,
                            tags=None,
                            updated_at=None,
                            user_id=None,
                            visibility=None,
                            additional_properties=None,
                            count=2):
        """
        @summary: Register new images and add them for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.register_new_image(
                auto_disk_config=auto_disk_config,
                checksum=checksum,
                container_format=container_format,
                created_at=created_at,
                disk_format=disk_format,
                file_=file_,
                id_=id_,
                image_type=image_type,
                min_disk=min_disk,
                min_ram=min_ram,
                name=name,
                os_type=os_type,
                owner=owner,
                protected=protected,
                schema=schema,
                self_=self_,
                size=size,
                status=status,
                tags=tags,
                updated_at=updated_at,
                user_id=user_id,
                visibility=visibility,
                additional_properties=additional_properties)
            image_list.append(image)

        return image_list

    def list_all_images(self, url_addition=None, **params):
        """
        @summary: Retrieve a complete list of images accounting for any
        query parameters

        @param url_addition: Additional text to be added to the end of the url
        to account for duplicate sort parameters
        @type url_addition: String
        @param params: Parameters to alter the returned list of images
        @type params: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []
        results_limit = self.config.results_limit
        params.update({'limit': results_limit})

        resp = self.client.list_images(params, url_addition)
        images = self.verify_resp(resp, 'list images')

        while len(images) == results_limit:
            image_list += images

            marker = images[results_limit - 1].id_
            params.update({'marker': marker})

            resp = self.client.list_images(params, url_addition)
            images = self.verify_resp(resp, 'list images')

        image_list += images

        return image_list

    @staticmethod
    def get_time_delta(time_in_sec, time_property):
        """
        @summary: Calculate the difference between an image attribute's time
        value and a time_property

        @param time_in_sec: Current time in seconds
        @type time_in_sec: Integer
        @param time_property: Image property containing a time
        @type time_property: Datetime

        @return: Time_delta
        @rtype: Integer
        """

        time_property_in_sec = calendar.timegm(time_property.timetuple())

        return abs(time_property_in_sec - time_in_sec)

    @staticmethod
    def validate_image(image):
        """
        @summary: Generically validate an image contains crucial expected
        data

        @param image: Image to be validated
        @type image: Object

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        # The following properties do not always have values:
        # checksum, container_format, disk_format, name, tags

        if image.auto_disk_config is None:
            errors.append(
                Messages.PROPERTY_MSG.format('auto_disk_config', 'not None',
                                             image.auto_disk_config))
        if image.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             image.created_at))
        if image.file_ != '/v2/images/{0}/file'.format(image.id_):
            errors.append(
                Messages.PROPERTY_MSG.format(
                    'file', '/v2/images/{0}/file'.format(image.id_),
                    image.file_))
        if id_regex.match(image.id_) is None:
            errors.append(
                Messages.PROPERTY_MSG.format('id', 'not None', id_regex))
        if image.image_type is None:
            errors.append(
                Messages.PROPERTY_MSG.format('image_type', 'not None',
                                             image.image_type))
        if image.min_disk is None:
            errors.append(
                Messages.PROPERTY_MSG.format('min_disk', 'not None',
                                             image.min_disk))
        if image.min_ram is None:
            errors.append(
                Messages.PROPERTY_MSG.format('min_ram', 'not None',
                                             image.min_ram))
        if image.os_type is None:
            errors.append(
                Messages.PROPERTY_MSG.format('os_type', 'not None',
                                             image.os_type))
        if image.owner is None:
            errors.append(
                Messages.PROPERTY_MSG.format('owner', 'not None', image.owner))
        if image.protected is None:
            errors.append(
                Messages.PROPERTY_MSG.format('protected', 'not None',
                                             image.protected))
        if image.schema != Schemas.IMAGE_SCHEMA:
            errors.append(
                Messages.PROPERTY_MSG.format('schema', Schemas.IMAGE_SCHEMA,
                                             image.schema))
        if image.self_ != '/v2/images/{0}'.format(image.id_):
            errors.append(
                Messages.PROPERTY_MSG.format(
                    'self', '/v2/images/{0}'.format(image.id_), image.self_))
        if image.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             image.status))
        if image.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             image.updated_at))
        if image.user_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('user_id', 'not None',
                                             image.user_id))
        if image.virtual_size is not None:
            errors.append(
                Messages.PROPERTY_MSG.format('virtual_size', 'None',
                                             image.virtual_size))
        if image.visibility is None:
            errors.append(
                Messages.PROPERTY_MSG.format('visibility', 'not None',
                                             image.visibility))

        return errors

    @staticmethod
    def validate_image_member(image_member):
        """
        @summary: Generically validate an image member contains crucial
        expected data

        @param image_member: Image member to be validated
        @type image_member: Object

        @return: Errors
        @rtype: List
        """

        errors = []

        if image_member.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             image_member.created_at))
        if image_member.image_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('image_id', 'not None',
                                             image_member.image_id))
        if image_member.member_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('member_id', 'not None',
                                             image_member.member_id))
        if image_member.schema != Schemas.IMAGE_MEMBER_SCHEMA:
            errors.append(
                Messages.PROPERTY_MSG.format('schema',
                                             Schemas.IMAGE_MEMBER_SCHEMA,
                                             image_member.schema))
        if image_member.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             image_member.status))
        if image_member.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             image_member.updated_at))

        return errors

    def wait_for_image_status(self,
                              image_id,
                              desired_status,
                              interval_time=15,
                              timeout=900):
        """
        @summary: Wait for a image to reach a desired status

        @param image_id: Image id to evaluate
        @type image_id: UUID
        @param desired_status: Expected final status of image
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer

        @return: Resp
        @rtype: Object
        """

        interval_time = interval_time or self.config.image_status_interval
        timeout = timeout or self.config.snapshot_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_image_details(image_id)
            image = self.verify_resp(resp, 'get image details', image_id)

            if image.status.lower() == ImageStatus.ERROR.lower():
                raise BuildErrorException(
                    'Image with the uuid {0} entered ERROR '
                    'status.'.format(image_id))

            if image.status == desired_status:
                break

            time.sleep(interval_time)
        else:
            raise TimeoutException(
                'Image with the uuid {0} did not reach the {1} status within '
                '{2} seconds.'.format(image_id, desired_status, timeout))

        return resp

    def create_new_task(self, input_=None, type_=None):
        """
        @summary: Create new task and wait for success status

        @param input_: Image properties and location data
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String

        @return: Task
        @rtype: Object
        """

        import_from = self.config.import_from
        input_ = input_ or {'image_properties': {}, 'import_from': import_from}
        type_ = type_ or TaskTypes.IMPORT
        failures = []
        attempts = self.config.resource_creation_attempts

        for attempt in range(attempts):
            try:
                resp = self.client.task_to_import_image(input_=input_,
                                                        type_=type_)
                task = resp.entity

                task = self.wait_for_task_status(task.id_, TaskStatus.SUCCESS)

                return task

            except (BuildErrorException, TimeoutException) as ex:
                failure = ('Attempt {0}: Failed to create task with '
                           'the message {1}'.format(attempt + 1, ex.message))
                self._log.error(failure)
                failures.append(failure)

        raise RequiredResourceException(
            'Failed to successfully create a task after {0} attempts: '
            '{1}'.format(attempts, failures))

    def create_new_tasks(self, input_=None, type_=None, count=2):
        """
        @summary: Create new tasks and wait for success status for each

        @param input_: Image properties and image location
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String
        @param count: Number of tasks to create
        @type count: Integer

        @return: Task_list
        @rtype: List
        """

        task_list = []

        for i in range(count):
            task = self.create_new_task(input_=input_, type_=type_)
            task_list.append(task)

        return task_list

    def list_all_tasks(self, **params):
        """
        @summary: Retrieve a complete list of tasks accounting for query
        parameters

        @param params: Parameters to alter the returned list of images
        @type params: Dictionary

        @return: Task_list
        @rtype: List
        """

        task_list = []
        results_limit = self.config.results_limit
        params.update({'limit': results_limit})

        resp = self.client.list_tasks(params)
        tasks = self.verify_resp(resp, 'list tasks')

        while len(tasks) == results_limit:
            task_list += tasks

            marker = tasks[results_limit - 1].id_
            params.update({'marker': marker})

            resp = self.client.list_tasks(params)
            tasks = self.verify_resp(resp, 'list tasks')

        task_list += tasks

        return task_list

    @staticmethod
    def validate_task(task):
        """
        @summary: Generically validate a task contains crucial expected
        data

        @param task: Task to be validated
        @type task: UUID

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        if task.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             task.status))
        if id_regex.match(task.id_) is None:
            errors.append(
                Messages.PROPERTY_MSG.format('id_', 'not None',
                                             id_regex.match(task.id_)))
        if task.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             task.created_at))
        if task.input_ is not None and task.input_.import_from is None:
            errors.append(
                Messages.PROPERTY_MSG.format('import_from', 'not None',
                                             task.input_.import_from))
        if (task.result is not None
                and id_regex.match(task.result.image_id) is None):
            errors.append(
                Messages.PROPERTY_MSG.format(
                    'image_id', 'not None',
                    id_regex.match(task.result.image_id)))
        elif task.type_ is None:
            errors.append(
                Messages.PROPERTY_MSG.format('type_', 'not None', task.type_))
        if task.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             task.updated_at))
        if task.self_ != '/v2/tasks/{0}'.format(task.id_):
            errors.append(
                Messages.PROPERTY_MSG.format('self_',
                                             '/v2/tasks/{0}'.format(task.id_),
                                             task.self_))
        if task.owner is None:
            errors.append(
                Messages.PROPERTY_MSG.format('owner', 'not None', task.owner))
        if task.status == TaskStatus.SUCCESS and task.message != '':
            errors.append(
                Messages.PROPERTY_MSG.format('message', 'Empty message',
                                             task.message))
        if task.schema != '/v2/schemas/task':
            errors.append(
                Messages.PROPERTY_MSG.format('schema', '/v2/schemas/task',
                                             task.schema))

        return errors

    def wait_for_task_status(self,
                             task_id,
                             desired_status,
                             interval_time=10,
                             timeout=1200,
                             response_entity_type=None):
        """
        @summary: Waits for a task to reach a desired status and if the import
        task is successful, adds the created image to the resource pool for
        tear down

        @param task_id: Task id to evaluate
        @type task_id: UUID
        @param desired_status: Expected final status of task
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer
        @param response_entity_type: Response entity type to be passed on to
        python requests
        @type response_entity_type: Type

        @return: Task
        @rtype: Object
        """

        interval_time = interval_time or self.config.task_status_interval
        timeout = timeout or self.config.task_timeout
        end_time = time.time() + timeout
        if not response_entity_type:
            response_entity_type = Task

        while time.time() < end_time:
            resp = self.client.get_task_details(
                task_id, response_entity_type=response_entity_type)
            task = self.verify_resp(resp, 'get task details', task_id)

            if ((task.status.lower() == TaskStatus.FAILURE
                 and desired_status != TaskStatus.FAILURE)
                    or (task.status.lower() == TaskStatus.SUCCESS
                        and desired_status != TaskStatus.SUCCESS)):
                raise BuildErrorException(
                    'Task with the uuid {0} entered the {1} status. Task '
                    'responded with the message {2}'.format(
                        task.id_, task.status, task.message.replace('\\', '')))

            if task.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                'Task with the uuid {0} did not reach the {1} status within '
                '{2} seconds.'.format(task_id, desired_status, timeout))

        if (task is not None and task.type_ == TaskTypes.IMPORT
                and task.status.lower() == TaskStatus.SUCCESS):
            self.resources.add(task.result.image_id, self.client.delete_image)

        return task

    def create_task_with_transitions(self,
                                     create_task_resp,
                                     final_status=None,
                                     response_entity_type=None):
        """
        @summary: Create a task and verify that it transitions through the
        expected statuses

        @param create_task_resp: Create task api response
        @type create_task_resp: Object
        @param final_status: Flag to determine success or failure
        @type final_status: String
        @param response_entity_type: Response entity type to be passed on to
        python requests
        @type response_entity_type: Type

        @return: Task
        @rtype: Object
        """

        if not response_entity_type:
            response_entity_type = Task

        task = self.verify_resp(create_task_resp, 'create task')

        # Verify task progresses as expected
        verifier = StatusProgressionVerifier(
            'task',
            task.id_,
            self.get_task_status,
            task.id_,
            response_entity_type=response_entity_type)

        if final_status == TaskStatus.SUCCESS:
            error_statuses = [TaskStatus.FAILURE]
        else:
            error_statuses = [TaskStatus.SUCCESS]

        verifier.add_state(
            expected_statuses=[TaskStatus.PENDING],
            acceptable_statuses=[TaskStatus.PROCESSING, final_status],
            error_statuses=error_statuses,
            timeout=self.config.task_timeout,
            poll_rate=1)

        if final_status == TaskStatus.SUCCESS:
            error_statuses = [TaskStatus.PENDING, TaskStatus.FAILURE]
        else:
            error_statuses = [TaskStatus.PENDING, TaskStatus.SUCCESS]

        verifier.add_state(expected_statuses=[TaskStatus.PROCESSING],
                           acceptable_statuses=[final_status],
                           error_statuses=error_statuses,
                           timeout=self.config.task_timeout,
                           poll_rate=1)

        if final_status == TaskStatus.SUCCESS:
            verifier.add_state(
                expected_statuses=[TaskStatus.SUCCESS],
                error_statuses=[TaskStatus.PENDING, TaskStatus.FAILURE],
                timeout=self.config.task_timeout,
                poll_rate=1)
        else:
            verifier.add_state(
                expected_statuses=[TaskStatus.FAILURE],
                error_statuses=[TaskStatus.PENDING, TaskStatus.SUCCESS],
                timeout=self.config.task_timeout,
                poll_rate=1)

        verifier.start()

        return self.client.get_task_details(
            task.id_, response_entity_type=response_entity_type).entity

    def get_task_status(self, task_id, response_entity_type=None):
        """
        @summary: Retrieve task status for the status progression verifier in
        the create_task_with_transitions method

        @param task_id: Task id
        @type task_id: UUID
        @param response_entity_type: Response entity type to be passed on to
        python requests
        @type response_entity_type: Type

        @return: Status
        @rtype: String
        """

        if not response_entity_type:
            response_entity_type = Task

        resp = self.client.get_task_details(
            task_id, response_entity_type=response_entity_type)
        task = self.verify_resp(resp, 'get task details', task_id)

        return task.status.lower()

    @staticmethod
    def verify_resp(resp, req, obj_id=None):
        """
        @summary: Verify that a request was successful and that an entity was
        properly deserialized

        @param resp: Response object to verify
        @type resp: Object

        @return: Resp.entity
        @rtype: Object
        """

        if not resp.ok:
            msg = ('Request for {0} failed with the status code '
                   '{1}.'.format(req, resp.status_code))
            raise Exception(msg)

        if resp.entity is None:
            if obj_id is None:
                msg = ('Response body for {0} did not deserialize as '
                       'expected.'.format(req))
            else:
                msg = ('Response body for {0} with the uuid {1} did not '
                       'deserialize as expected.'.format(req, obj_id))
            raise Exception(msg)

        return resp.entity
Esempio n. 19
0
    def setUpClass(cls):
        super(ComputeFixture, cls).setUpClass()
        cls.flavors_config = FlavorsConfig()
        cls.images_config = ImagesConfig()
        cls.servers_config = ServersConfig()
        cls.compute_endpoint = ComputeEndpointConfig()
        cls.marshalling = MarshallingConfig()
        cls.config_drive_config = ConfigDriveConfig()
        cls.cloud_init_config = CloudInitConfig()

        cls.flavor_ref = cls.flavors_config.primary_flavor
        cls.flavor_ref_alt = cls.flavors_config.secondary_flavor
        cls.image_ref = cls.images_config.primary_image
        cls.image_ref_alt = cls.images_config.secondary_image
        cls.disk_path = cls.servers_config.instance_disk_path
        cls.split_ephemeral_disk_enabled = \
            cls.servers_config.split_ephemeral_disk_enabled
        cls.ephemeral_disk_max_size = \
            cls.servers_config.ephemeral_disk_max_size
        cls.disk_format_type = cls.servers_config.disk_format_type
        cls.expected_networks = cls.servers_config.expected_networks
        cls.file_injection_enabled = \
            cls.servers_config.personality_file_injection_enabled

        cls.endpoint_config = UserAuthConfig()
        cls.user_config = UserConfig()
        cls.access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                       cls.user_config)
        # If authentication fails, halt
        if cls.access_data is None:
            cls.assertClassSetupFailure('Authentication failed.')

        compute_service = cls.access_data.get_service(
            cls.compute_endpoint.compute_endpoint_name)
        url = compute_service.get_endpoint(
            cls.compute_endpoint.region).public_url
        # If a url override was provided, use that value instead
        if cls.compute_endpoint.compute_endpoint_url:
            url = '{0}/{1}'.format(cls.compute_endpoint.compute_endpoint_url,
                                   cls.user_config.tenant_id)

        client_args = {'url': url, 'auth_token': cls.access_data.token.id_,
                       'serialize_format': cls.marshalling.serializer,
                       'deserialize_format': cls.marshalling.deserializer}

        cls.flavors_client = FlavorsClient(**client_args)
        cls.servers_client = ServersClient(**client_args)
        cls.boot_from_volume_client = VolumesBootClient(**client_args)
        cls.images_client = ImagesClient(**client_args)
        cls.keypairs_client = KeypairsClient(**client_args)
        cls.security_groups_client = SecurityGroupsClient(**client_args)
        cls.security_group_rule_client = SecurityGroupRulesClient(
            **client_args)
        cls.volume_attachments_client = VolumeAttachmentsAPIClient(
            url=url, auth_token=cls.access_data.token.id_,
            serialize_format=cls.marshalling.serializer,
            deserialize_format=cls.marshalling.deserializer)
        cls.rescue_client = RescueClient(**client_args)
        cls.vnc_client = VncConsoleClient(**client_args)
        cls.console_output_client = ConsoleOutputClient(**client_args)
        cls.limits_client = LimitsClient(**client_args)
        cls.server_behaviors = ServerBehaviors(
            servers_client=cls.servers_client,
            images_client=cls.images_client,
            servers_config=cls.servers_config,
            images_config=cls.images_config,
            flavors_config=cls.flavors_config)
        cls.volume_server_behaviors = VolumeServerBehaviors(
            servers_client=cls.servers_client,
            images_client=cls.images_client,
            servers_config=cls.servers_config,
            images_config=cls.images_config,
            flavors_config=cls.flavors_config,
            server_behaviors=cls.server_behaviors,
            boot_from_volume_client=cls.boot_from_volume_client)
        cls.image_behaviors = ImageBehaviors(cls.images_client,
                                             cls.servers_client,
                                             cls.images_config)
        cls.config_drive_behaviors = ConfigDriveBehaviors(cls.servers_client,
                                                          cls.servers_config,
                                                          cls.server_behaviors)
        cls.flavors_client.add_exception_handler(ExceptionHandler())
        cls.resources = ResourcePool()
        cls.addClassCleanup(cls.resources.release)
Esempio n. 20
0
    def setUpClass(cls):
        """
        Initialize autoscale configs, behaviors and client
        """
        super(AutoscaleFixture, cls).setUpClass()
        cls.resources = ResourcePool()
        cls.autoscale_config = AutoscaleConfig()
        cls.endpoint_config = UserAuthConfig()
        user_config = UserConfig()
        access_data = AuthProvider.get_access_data(cls.endpoint_config,
                                                   user_config)
        server_service = access_data.get_service(
            cls.autoscale_config.server_endpoint_name)
        load_balancer_service = access_data.get_service(
            cls.autoscale_config.load_balancer_endpoint_name)
        server_url = server_service.get_endpoint(
            cls.autoscale_config.region).public_url
        lbaas_url = load_balancer_service.get_endpoint(
            cls.autoscale_config.region).public_url

        cls.tenant_id = cls.autoscale_config.tenant_id

        env = os.environ['OSTNG_CONFIG_FILE']
        if ('preprod' in env.lower()) or ('dev' in env.lower()):
            cls.url = str(cls.autoscale_config.server_endpoint) + '/' + str(
                cls.tenant_id)
        else:
            autoscale_service = access_data.get_service(
                cls.autoscale_config.autoscale_endpoint_name)
            cls.url = autoscale_service.get_endpoint(
                cls.autoscale_config.region).public_url

        cls.autoscale_client = AutoscalingAPIClient(cls.url,
                                                    access_data.token.id_,
                                                    'json', 'json')
        cls.server_client = ServersClient(server_url, access_data.token.id_,
                                          'json', 'json')
        cls.lbaas_client = LbaasAPIClient(lbaas_url, access_data.token.id_,
                                          'json', 'json')
        cls.autoscale_behaviors = AutoscaleBehaviors(cls.autoscale_config,
                                                     cls.autoscale_client)
        cls.gc_name = cls.autoscale_config.gc_name
        cls.gc_cooldown = int(cls.autoscale_config.gc_cooldown)
        cls.gc_min_entities = int(cls.autoscale_config.gc_min_entities)
        cls.gc_min_entities_alt = int(cls.autoscale_config.gc_min_entities_alt)
        cls.gc_max_entities = int(cls.autoscale_config.gc_max_entities)
        cls.lc_name = cls.autoscale_config.lc_name
        cls.lc_flavor_ref = cls.autoscale_config.lc_flavor_ref
        cls.lc_image_ref = cls.autoscale_config.lc_image_ref
        cls.lc_image_ref_alt = cls.autoscale_config.lc_image_ref_alt
        cls.sp_name = rand_name(cls.autoscale_config.sp_name)
        cls.sp_cooldown = int(cls.autoscale_config.sp_cooldown)
        cls.sp_change = int(cls.autoscale_config.sp_change)
        cls.sp_change_percent = int(cls.autoscale_config.sp_change_percent)
        cls.sp_desired_capacity = int(cls.autoscale_config.sp_desired_capacity)
        cls.sp_policy_type = cls.autoscale_config.sp_policy_type
        cls.upd_sp_change = int(cls.autoscale_config.upd_sp_change)
        cls.lc_load_balancers = cls.autoscale_config.lc_load_balancers
        cls.sp_list = cls.autoscale_config.sp_list
        cls.wb_name = rand_name(cls.autoscale_config.wb_name)
        cls.load_balancer_1 = int(cls.autoscale_config.load_balancer_1)
        cls.load_balancer_2 = int(cls.autoscale_config.load_balancer_2)
        cls.load_balancer_3 = int(cls.autoscale_config.load_balancer_3)
        cls.lb_other_region = int(cls.autoscale_config.lb_other_region)
        cls.interval_time = int(cls.autoscale_config.interval_time)
        cls.timeout = int(cls.autoscale_config.timeout)
        cls.scheduler_interval = OtterConstants.SCHEDULER_INTERVAL
        cls.scheduler_batch = OtterConstants.SCHEDULER_BATCH
        cls.max_maxentities = OtterConstants.MAX_MAXENTITIES
        cls.max_cooldown = OtterConstants.MAX_COOLDOWN
        cls.max_groups = OtterConstants.MAX_GROUPS
        cls.max_policies = OtterConstants.MAX_POLICIES
        cls.max_webhooks = OtterConstants.MAX_WEBHOOKS
        cls.limit_value_all = OtterConstants.LIMIT_VALUE_ALL
        cls.limit_unit_all = OtterConstants.LIMIT_UNIT_ALL
        cls.limit_value_webhook = OtterConstants.LIMIT_VALUE_WEBHOOK
        cls.limit_unit_webhook = OtterConstants.LIMIT_UNIT_WEBHOOK
        cls.non_autoscale_username = cls.autoscale_config.non_autoscale_username
        cls.non_autoscale_password = cls.autoscale_config.non_autoscale_password
        cls.non_autoscale_tenant = cls.autoscale_config.non_autoscale_tenant
Esempio n. 21
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors class for images v2"""

    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()

    def create_new_image(self, container_format=None, disk_format=None,
                         name=None, protected=None, tags=None,
                         visibility=None):
        """@summary: Create new image and add it for deletion"""

        if container_format is None:
            container_format = ImageContainerFormat.BARE
        if disk_format is None:
            disk_format = ImageDiskFormat.RAW
        if name is None:
            name = rand_name('image')
        if protected is None:
            protected = False
        if tags is None:
            tags = []
        if visibility is None:
            visibility = ImageVisibility.PRIVATE
        response = self.client.create_image(
            container_format=container_format, disk_format=disk_format,
            name=name, protected=protected, tags=tags, visibility=visibility)
        image = response.entity
        if image is not None:
            self.resources.add(image.id_, self.client.delete_image)
        return image

    def create_new_images(self, container_format=None, disk_format=None,
                          name=None, protected=None, tags=None,
                          visibility=None, count=1):
        """@summary: Create new images and add them for deletion"""

        image_list = []
        for i in range(count):
            image = self.create_new_image(
                container_format=container_format, disk_format=disk_format,
                name=name, protected=protected, tags=tags,
                visibility=visibility)
            image_list.append(image)
        return image_list

    def list_images_pagination(self, name=None, disk_format=None,
                               container_format=None, visibility=None,
                               status=None, checksum=None, owner=None,
                               min_ram=None, min_disk=None, changes_since=None,
                               protected=None, size_min=None, size_max=None,
                               sort_key=None, sort_dir=None, marker=None,
                               limit=None):
        """@summary: Get images accounting for pagination as needed"""

        image_list = []
        results_limit = self.config.results_limit
        response = self.client.list_images(
            name=name, disk_format=disk_format,
            container_format=container_format, visibility=visibility,
            status=status, checksum=checksum, owner=owner, min_ram=min_ram,
            min_disk=min_disk, changes_since=changes_since,
            protected=protected, size_min=size_min, size_max=size_max,
            sort_key=sort_key, sort_dir=sort_dir, marker=marker, limit=limit)
        images = response.entity
        while len(images) == results_limit:
            image_list += images
            marker = images[results_limit - 1].id_
            response = self.client.list_images(
                name=name, disk_format=disk_format,
                container_format=container_format, visibility=visibility,
                status=status, checksum=checksum, owner=owner, min_ram=min_ram,
                min_disk=min_disk, changes_since=changes_since,
                protected=protected, size_min=size_min, size_max=size_max,
                sort_key=sort_key, sort_dir=sort_dir, marker=marker,
                limit=limit)
            images = response.entity
        image_list += images
        return image_list

    def get_member_ids(self, image_id):
        """
        @summary: Return a complete list of ids for all members for a given
        image id
        """

        response = self.client.list_members(image_id)
        members = response.entity
        return [member.member_id for member in members]
Esempio n. 22
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors class for images v2"""

    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()
        self.error_msg = Messages.ERROR_MSG
        self.id_regex = re.compile(ImageProperties.ID_REGEX)

    def create_new_image(self, container_format=None, disk_format=None,
                         name=None, protected=None, tags=None,
                         visibility=None):
        """@summary: Create new image and add it for deletion"""

        if container_format is None:
            container_format = ImageContainerFormat.BARE
        if disk_format is None:
            disk_format = ImageDiskFormat.RAW
        if name is None:
            name = rand_name('image')

        response = self.client.create_image(
            container_format=container_format, disk_format=disk_format,
            name=name, protected=protected, tags=tags, visibility=visibility)
        image = response.entity
        if image is not None:
            self.resources.add(image.id_, self.client.delete_image)
        return image

    def create_new_images(self, container_format=None, disk_format=None,
                          name=None, protected=None, tags=None,
                          visibility=None, count=1):
        """@summary: Create new images and add them for deletion"""

        image_list = []
        for i in range(count):
            image = self.create_new_image(
                container_format=container_format, disk_format=disk_format,
                name=name, protected=protected, tags=tags,
                visibility=visibility)
            image_list.append(image)
        return image_list

    def list_images_pagination(self, changes_since=None, checksum=None,
                               container_format=None, disk_format=None,
                               limit=None, marker=None, member_status=None,
                               min_disk=None, min_ram=None, name=None,
                               owner=None, protected=None, size_max=None,
                               size_min=None, sort_dir=None, sort_key=None,
                               status=None, visibility=None):
        """@summary: Get images accounting for pagination as needed"""

        image_list = []
        results_limit = self.config.results_limit
        response = self.client.list_images(
            changes_since=changes_since, checksum=checksum,
            container_format=container_format, disk_format=disk_format,
            limit=limit, marker=marker, member_status=member_status,
            min_disk=min_disk, min_ram=min_ram, name=name, owner=owner,
            protected=protected, size_max=size_max, size_min=size_min,
            sort_dir=sort_dir, sort_key=sort_key, status=status,
            visibility=visibility)
        images = response.entity
        while len(images) == results_limit:
            image_list += images
            marker = images[results_limit - 1].id_
            response = self.client.list_images(
                changes_since=changes_since, checksum=checksum,
                container_format=container_format, disk_format=disk_format,
                limit=limit, marker=marker, member_status=member_status,
                min_disk=min_disk, min_ram=min_ram, name=name, owner=owner,
                protected=protected, size_max=size_max, size_min=size_min,
                sort_dir=sort_dir, sort_key=sort_key, status=status,
                visibility=visibility)
            images = response.entity
        image_list += images
        return image_list

    def get_member_ids(self, image_id):
        """
        @summary: Return a complete list of ids for all members for a given
        image id
        """

        response = self.client.list_members(image_id)
        members = response.entity
        return [member.member_id for member in members]

    @staticmethod
    def get_creation_offset(image_creation_time_in_sec, time_property):
        """
        @summary: Calculate and return the difference between the image
        creation time and a given image time_property
        """

        time_property_in_sec = calendar.timegm(time_property.timetuple())
        return abs(time_property_in_sec - image_creation_time_in_sec)

    def validate_image(self, image):
        """@summary: Generically validate an image contains crucial expected
        data
        """

        errors = []
        if image.created_at is None:
            errors.append(self.error_msg.format('created_at', not None, None))
        if image.file_ != '/v2/images/{0}/file'.format(image.id_):
            errors.append(self.error_msg.format(
                'file_', '/v2/images/{0}/file'.format(image.id_), image.file_))
        if self.id_regex.match(image.id_) is None:
            errors.append(self.error_msg.format('id_', not None, None))
        if image.min_disk is None:
            errors.append(self.error_msg.format('min_disk', not None, None))
        if image.min_ram is None:
            errors.append(self.error_msg.format('min_ram', not None, None))
        if image.protected is None:
            errors.append(self.error_msg.format('protected', not None, None))
        if image.schema != Schemas.IMAGE_SCHEMA:
            errors.append(self.error_msg.format(
                'schema', Schemas.IMAGE_SCHEMA, image.schema))
        if image.self_ != '/v2/images/{0}'.format(image.id_):
            errors.append(self.error_msg.format(
                'schema', '/v2/images/{0}'.format(image.id_), image.self_))
        if image.status is None:
            errors.append(self.error_msg.format('status', not None, None))
        if image.updated_at is None:
            errors.append(self.error_msg.format('updated_at', not None, None))
        return errors

    def validate_image_member(self, image_id, image_member, member_id):
        """@summary: Generically validate an image member contains crucial
        expected data
        """

        errors = []
        if image_member.created_at is None:
            errors.append(self.error_msg.format('created_at', not None, None))
        if image_member.image_id != image_id:
            errors.append(self.error_msg.format(
                'image_id', image_id, image_member.image_id))
        if image_member.member_id != member_id:
            errors.append(self.error_msg.format(
                'member_id', member_id, image_member.member_id))
        if image_member.schema != Schemas.IMAGE_MEMBER_SCHEMA:
            errors.append(self.error_msg.format(
                'schema', Schemas.IMAGE_MEMBER_SCHEMA, image_member.schema))
        if image_member.status is None:
            errors.append(self.error_msg.format('status', not None, None))
        if image_member.updated_at is None:
            errors.append(self.error_msg.format('updated_at', not None, None))
        return errors

    def wait_for_image_status(self, image_id, desired_status,
                              interval_time=None, timeout=None):
        """
        @summary: Waits for a image to reach a desired status
        @param image_id: The uuid of the image
        @type image_id: String
        @param desired_status: The desired final status of the image
        @type desired_status: String
        @param interval_time: The amount of time in seconds to wait
                              between polling
        @type interval_time: Integer
        @param timeout: The amount of time in seconds to wait
                              before aborting
        @type timeout: Integer
        @return: Response object containing response and the image
                 domain object
        @rtype: requests.Response
        """

        interval_time = interval_time or self.config.image_status_interval
        timeout = timeout or self.config.snapshot_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_image(image_id)
            image = resp.entity

            if image.status.lower() == ImageStatus.ERROR.lower():
                raise BuildErrorException(
                    "Build failed. Image with uuid {0} "
                    "entered ERROR status.".format(image.id))

            if image.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                "wait_for_image_status ran for {0} seconds and did not "
                "observe image {1} reach the {2} status.".format(
                    timeout, image_id, desired_status))

        return resp
Esempio n. 23
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors class for images v2"""

    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()
        self.error_msg = Messages.ERROR_MSG
        self.id_regex = re.compile(ImageProperties.ID_REGEX)

    def create_image_via_task(self, image_properties=None, import_from=None,
                              import_from_format=None):
        """
        @summary: Create new image via the create new task method and add it
        for deletion
        """

        image_properties = image_properties or {'name': rand_name('image')}
        import_from = import_from or self.config.import_from
        import_from_format = import_from or self.config.import_from_format

        input_ = {'image_properties': image_properties,
                  'import_from': import_from,
                  'import_from_format': import_from_format}
        task = self.create_new_task(input_=input_, type_=TaskTypes.IMPORT)
        image_id = task.result.image_id

        response = self.client.get_image(image_id=image_id)
        image = response.entity

        if image is not None:
            self.resources.add(image.id_, self.client.delete_image)

        return image

    def create_images_via_task(self, image_properties=None, import_from=None,
                               import_from_format=None, count=1):
        """
        @summary: Create new images via the create new task method and add them
        for deletion
        """

        image_list = []

        for i in range(count):
            image = self.create_image_via_task(
                image_properties=image_properties, import_from=import_from,
                import_from_format=import_from_format)
            image_list.append(image)

        return image_list

    def create_new_image(self, container_format=None, disk_format=None,
                         name=None, protected=None, tags=None):
        """@summary: Create new image and add it for deletion"""

        container_format = container_format or ImageContainerFormat.BARE
        disk_format = disk_format or ImageDiskFormat.RAW
        name = name or rand_name('image')

        response = self.client.create_image(
            container_format=container_format, disk_format=disk_format,
            name=name, protected=protected, tags=tags)
        image = response.entity

        if image is not None:
            self.resources.add(image.id_, self.client.delete_image)

        return image

    def create_new_images(self, container_format=None, disk_format=None,
                          name=None, protected=None, tags=None, count=1):
        """@summary: Create new images and add them for deletion"""

        image_list = []

        for i in range(count):
            image = self.create_new_image(
                container_format=container_format, disk_format=disk_format,
                name=name, protected=protected, tags=tags)
            image_list.append(image)

        return image_list

    def list_images_pagination(self, **filters):
        """
        @summary: Get images accounting for pagination as needed with
        variable number of filter arguments
        """

        image_list = []
        results_limit = self.config.results_limit

        response = self.client.list_images(filters=filters)
        images = response.entity

        while len(images) == results_limit:
            image_list += images
            marker = images[results_limit - 1].id_
            filters.update({"marker": marker})
            response = self.client.list_images(filters=filters)
            images = response.entity

        image_list += images

        return image_list

    def get_member_ids(self, image_id):
        """
        @summary: Return a complete list of ids for all members for a given
        image id
        """

        response = self.client.list_members(image_id)
        members = response.entity
        return [member.member_id for member in members]

    @staticmethod
    def get_creation_delta(image_creation_time_in_sec, time_property):
        """
        @summary: Calculate and return the difference between the image
        creation time and a given image time_property
        """

        time_property_in_sec = calendar.timegm(time_property.timetuple())
        return abs(time_property_in_sec - image_creation_time_in_sec)

    def validate_image(self, image):
        """@summary: Generically validate an image contains crucial expected
        data
        """

        errors = []

        if image.auto_disk_config is None:
            errors.append(self.error_msg.format(
                'auto_disk_config', 'not None', image.auto_disk_config))
        if image.created_at is None:
            errors.append(self.error_msg.format(
                'created_at', 'not None', image.created_at))
        if image.file_ != '/v2/images/{0}/file'.format(image.id_):
            errors.append(self.error_msg.format(
                'file_', '/v2/images/{0}/file'.format(image.id_), image.file_))
        if image.image_type is None:
            errors.append(self.error_msg.format(
                'image_type', 'not None', image.image_type))
        if self.id_regex.match(image.id_) is None:
            errors.append(self.error_msg.format(
                'id_', 'not None', self.id_regex))
        if image.min_disk is None:
            errors.append(self.error_msg.format(
                'min_disk', 'not None', image.min_disk))
        if image.min_ram is None:
            errors.append(self.error_msg.format(
                'min_ram', 'not None', image.min_ram))
        if image.os_type is None:
            errors.append(self.error_msg.format(
                'os_type', 'not None', image.os_type))
        if image.protected is None:
            errors.append(self.error_msg.format(
                'protected', 'not None', image.protected))
        if image.schema != Schemas.IMAGE_SCHEMA:
            errors.append(self.error_msg.format(
                'schema', Schemas.IMAGE_SCHEMA, image.schema))
        if image.self_ != '/v2/images/{0}'.format(image.id_):
            errors.append(self.error_msg.format(
                'schema', '/v2/images/{0}'.format(image.id_), image.self_))
        if image.status is None:
            errors.append(self.error_msg.format(
                'status', 'not None', image.status))
        if image.updated_at is None:
            errors.append(self.error_msg.format(
                'updated_at', 'not None', image.updated_at))
        if image.user_id is None:
            errors.append(self.error_msg.format(
                'user_id', 'not None', image.user_id))

        return errors

    def validate_image_member(self, image_id, image_member, member_id):
        """@summary: Generically validate an image member contains crucial
        expected data
        """

        errors = []

        if image_member.created_at is None:
            errors.append(self.error_msg.format(
                'created_at', 'not None', image_member.created_at))
        if image_member.image_id != image_id:
            errors.append(self.error_msg.format(
                'image_id', image_id, image_member.image_id))
        if image_member.member_id != member_id:
            errors.append(self.error_msg.format(
                'member_id', member_id, image_member.member_id))
        if image_member.schema != Schemas.IMAGE_MEMBER_SCHEMA:
            errors.append(self.error_msg.format(
                'schema', Schemas.IMAGE_MEMBER_SCHEMA, image_member.schema))
        if image_member.status is None:
            errors.append(self.error_msg.format(
                'status', 'not None', image_member.status))
        if image_member.updated_at is None:
            errors.append(self.error_msg.format(
                'updated_at', 'not None', image_member.updated_at))

        return errors

    def wait_for_image_status(self, image_id, desired_status,
                              interval_time=None, timeout=None):
        """
        @summary: Waits for a image to reach a desired status
        @param image_id: The uuid of the image
        @type image_id: String
        @param desired_status: The desired final status of the image
        @type desired_status: String
        @param interval_time: The amount of time in seconds to wait
                              between polling
        @type interval_time: Integer
        @param timeout: The amount of time in seconds to wait
                              before aborting
        @type timeout: Integer
        @return: Response object containing response and the image
                 domain object
        @rtype: requests.Response
        """

        interval_time = interval_time or self.config.image_status_interval
        timeout = timeout or self.config.snapshot_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_image(image_id)
            image = resp.entity

            if image.status.lower() == ImageStatus.ERROR.lower():
                raise BuildErrorException(
                    "Build failed. Image with uuid {0} "
                    "entered ERROR status.".format(image.id))

            if image.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                "wait_for_image_status ran for {0} seconds and did not "
                "observe image {1} reach the {2} status.".format(
                    timeout, image_id, desired_status))

        return resp

    def create_new_task(self, input_=None, type_=None):
        """@summary: Create new task and wait for success status"""

        import_from = self.config.import_from
        import_from_format = self.config.import_from_format
        input_ = input_ or {'image_properties': {},
                            'import_from': import_from,
                            'import_from_format': import_from_format}
        type_ = type_ or TaskTypes.IMPORT
        failures = []
        attempts = self.config.resource_creation_attempts

        for attempt in range(attempts):
            try:
                response = self.client.create_task(input_=input_, type_=type_)
                task_id = response.entity.id_
                task = self.wait_for_task_status(task_id, TaskStatus.SUCCESS)
                return task
            except (TimeoutException, BuildErrorException) as ex:
                self._log.error('Failed to create task with uuid {0}: '
                                '{1}'.format(task_id, ex.message))
                failures.append(ex.message)
        raise RequiredResourceException(
            'Failed to successfully create a task after {0} attempts: '
            '{1}'.format(attempts, failures))

    def create_new_tasks(self, input_=None, type_=None, count=1):
        """@summary: Create new tasks and wait for success status for each"""

        task_list = []

        for i in range(count):
            task = self.create_new_task(input_=input_, type_=type_)
            task_list.append(task)

        return task_list

    def list_tasks_pagination(self, limit=None, marker=None, sort_dir=None,
                              status=None, type_=None):
        """@summary: Get tasks accounting for pagination as needed"""

        task_list = []
        results_limit = limit or self.config.results_limit

        response = self.client.list_tasks(
            limit=limit, marker=marker, sort_dir=sort_dir, status=status,
            type_=type_)
        tasks = response.entity

        while len(tasks) == results_limit:
            task_list += tasks
            marker = tasks[results_limit - 1].id_
            response = self.client.list_tasks(
                limit=limit, marker=marker, sort_dir=sort_dir, status=status,
                type_=type_)
            tasks = response.entity

        task_list += tasks

        return task_list

    def validate_task(self, task):
        """@summary: Generically validate a task contains crucial expected
        data
        """

        errors = []

        if task.status is None:
            errors.append(self.error_msg.format(
                'status', 'not None', task.status))
        if self.id_regex.match(task.id_) is None:
            errors.append(self.error_msg.format(
                'id_', 'not None', self.id_regex.match(task.id_)))
        if task.created_at is None:
            errors.append(self.error_msg.format(
                'created_at', 'not None', task.created_at))
        if task.type_ == TaskTypes.IMPORT:
            if task.input_.import_from is None:
                errors.append(self.error_msg.format(
                    'import_from', 'not None', task.input_.import_from))
            if (task.result is not None and
                    self.id_regex.match(task.result.image_id) is None):
                errors.append(self.error_msg.format(
                    'image_id', 'not None',
                    self.id_regex.match(task.result.image_id)))
        elif task.type_ == TaskTypes.EXPORT:
            if task.input_.image_uuid is None:
                errors.append(self.error_msg.format(
                    'image_uuid', 'not None', task.input_.image_uuid))
            if task.input_.receiving_swift_container is None:
                errors.append(self.error_msg.format(
                    'receiving_swift_container', 'not None',
                    task.input_.receiving_swift_container))
            if task.result is not None and task.result.export_location is None:
                errors.append(self.error_msg.format(
                    'export_location', 'not None',
                    task.result.export_location))
        elif task.type_ is None:
            errors.append(self.error_msg.format(
                'type_', 'not None', task.type_))
        if task.updated_at is None:
            errors.append(self.error_msg.format(
                'updated_at', 'not None', task.updated_at))
        if task.self_ != '/v2/tasks/{0}'.format(task.id_):
            errors.append(self.error_msg.format(
                'self_', '/v2/tasks/{0}'.format(task.id_), task.self_))
        if task.owner is None:
            errors.append(self.error_msg.format(
                'owner', 'not None', task.owner))
        if task.message != 'None':
            errors.append(self.error_msg.format(
                'message', 'None', task.message))
        if task.schema != '/v2/schemas/task':
            errors.append(self.error_msg.format(
                'schema', '/v2/schemas/task', task.schema))

        return errors

    def validate_exported_files(self, export_to, expect_success, files,
                                image_id):
        """
        @summary: Validate that a given cloud files location contains a
        given file or not
        """

        errors = []
        file_names = [file_.name for file_ in files]

        if expect_success:
            if '{0}.vhd'.format(image_id) not in file_names:
                errors.append(self.error_msg.format(
                    'file present', True, False))
        else:
            if '{0}.vhd'.format(image_id) in file_names:
                errors.append(self.error_msg.format(
                    'file present', False, True))

        return errors, file_names

    def wait_for_task_status(self, task_id, desired_status, interval_time=None,
                             timeout=None):
        """@summary: Waits for a task to reach a desired status"""

        interval_time = interval_time or self.config.task_status_interval
        timeout = timeout or self.config.task_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_task(task_id)
            task = resp.entity

            if ((task.status.lower() == TaskStatus.FAILURE and
                    desired_status != TaskStatus.FAILURE) or
                    (task.status.lower() == TaskStatus.SUCCESS and
                     desired_status != TaskStatus.SUCCESS)):
                raise BuildErrorException(
                    'Task with uuid {0} entered {1} status. Task responded '
                    'with the message {2}'.format(
                        task.id_, task.status, task.message))

            if task.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                'Failed to reach the {0} status after {1} seconds for task '
                'with uuid {2}'.format(desired_status, timeout, task_id))

        if (task is not None and task.type_ == TaskTypes.IMPORT and
                task.status.lower() == TaskStatus.SUCCESS):
            self.resources.add(task.result.image_id, self.client.delete_image)

        return task

    def get_task_status(self, task_id):
        """@summary: Retrieve task status"""

        response = self.client.get_task(task_id)
        return response.entity.status.lower()

    def create_task_with_transitions(self, input_, task_type,
                                     final_status=None):
        """
        @summary: Create a task and verify that it transitions through the
        expected statuses
        """

        response = self.client.create_task(
            input_=input_, type_=task_type)
        task = response.entity

        # Verify task progresses as expected
        verifier = StatusProgressionVerifier(
            'task', task.id_, self.get_task_status, task.id_)

        verifier.add_state(
            expected_statuses=[TaskStatus.PENDING],
            acceptable_statuses=[TaskStatus.PROCESSING, TaskStatus.SUCCESS],
            error_statuses=[TaskStatus.FAILURE],
            timeout=self.config.task_timeout, poll_rate=1)

        verifier.add_state(
            expected_statuses=[TaskStatus.PROCESSING],
            acceptable_statuses=[TaskStatus.SUCCESS],
            error_statuses=[TaskStatus.FAILURE],
            timeout=self.config.task_timeout, poll_rate=1)

        if final_status == TaskStatus.SUCCESS:
            verifier.add_state(
                expected_statuses=[TaskStatus.SUCCESS],
                error_statuses=[TaskStatus.FAILURE],
                timeout=self.config.task_timeout, poll_rate=1)

        verifier.start()

        response = self.client.get_task(task.id_)
        return response.entity
Esempio n. 24
0
 def __init__(self, images_client, images_config):
     super(ImagesBehaviors, self).__init__()
     self.config = images_config
     self.client = images_client
     self.resources = ResourcePool()
Esempio n. 25
0
class ImagesBehaviors(BaseBehavior):
    """@summary: Behaviors for Images"""
    def __init__(self, images_client, images_config):
        super(ImagesBehaviors, self).__init__()
        self.config = images_config
        self.client = images_client
        self.resources = ResourcePool()

    @staticmethod
    def read_data_file(file_path):
        """
        @summary: Retrieve data file for a given file path

        @param file_path: Location of data file
        @type file_path: String

        @return: Test_data
        @rtype: String
        """
        try:
            with open(file_path, "r") as DATA:
                test_data = DATA.read().rstrip()
        except IOError as file_error:
            raise file_error

        return test_data

    def create_image_via_task(self, image_properties=None, import_from=None):
        """
        @summary: Create new image via task

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String

        @return: Image
        @rtype: Object
        """

        image_properties = image_properties or {'name': rand_name('image')}
        import_from = import_from or self.config.import_from

        input_ = {
            'image_properties': image_properties,
            'import_from': import_from
        }
        task = self.create_new_task(input_=input_, type_=TaskTypes.IMPORT)
        image_id = task.result.image_id

        self.client.add_image_tag(image_id=image_id, tag=rand_name('tag'))

        response = self.client.get_image_details(image_id=image_id)
        image = response.entity

        return image

    def create_images_via_task(self,
                               image_properties=None,
                               import_from=None,
                               count=2):
        """
        @summary: Create new images via tasks

        @param image_properties: Properties to use for the image creation
        @type image_properties: Dictionary
        @param import_from: Location of image
        @type import_from: String
        @param count: Number of images to create
        @type count: Integer

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.create_image_via_task(
                image_properties=image_properties, import_from=import_from)
            image_list.append(image)

        return image_list

    def register_new_image(self,
                           auto_disk_config=None,
                           checksum=None,
                           container_format=None,
                           created_at=None,
                           disk_format=None,
                           file_=None,
                           id_=None,
                           image_type=None,
                           min_disk=None,
                           min_ram=None,
                           name=None,
                           os_type=None,
                           owner=None,
                           protected=None,
                           schema=None,
                           self_=None,
                           size=None,
                           status=None,
                           tags=None,
                           updated_at=None,
                           user_id=None,
                           visibility=None,
                           additional_properties=None):
        """
        @summary: Register new image and add it for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image
        @rtype: Object
        """

        container_format = container_format or ImageContainerFormat.BARE
        disk_format = disk_format or ImageDiskFormat.RAW
        name = name or rand_name('image')

        response = self.client.register_image(
            auto_disk_config=auto_disk_config,
            checksum=checksum,
            container_format=container_format,
            created_at=created_at,
            disk_format=disk_format,
            file_=file_,
            id_=id_,
            image_type=image_type,
            min_disk=min_disk,
            min_ram=min_ram,
            name=name,
            os_type=os_type,
            owner=owner,
            protected=protected,
            schema=schema,
            self_=self_,
            size=size,
            status=status,
            tags=tags,
            updated_at=updated_at,
            user_id=user_id,
            visibility=visibility,
            additional_properties=additional_properties)
        image = response.entity

        if image is not None:
            self.resources.add(image.id_, self.client.delete_image)

        return image

    def register_new_images(self,
                            auto_disk_config=None,
                            checksum=None,
                            container_format=None,
                            created_at=None,
                            disk_format=None,
                            file_=None,
                            id_=None,
                            image_type=None,
                            min_disk=None,
                            min_ram=None,
                            name=None,
                            os_type=None,
                            owner=None,
                            protected=None,
                            schema=None,
                            self_=None,
                            size=None,
                            status=None,
                            tags=None,
                            updated_at=None,
                            user_id=None,
                            visibility=None,
                            additional_properties=None,
                            count=2):
        """
        @summary: Register new images and add them for deletion

        @param auto_disk_config: Auto disk config for the image being created
        @type auto_disk_config: String
        @param checksum: Checksum for the image being created
        @type checksum: String
        @param container_format: Container format for the image being created
        @type container_format: String
        @param created_at: Created at for the image being created
        @type created_at: Datetime
        @param disk_format: Disk format for the image being created
        @type disk_format: String
        @param file_: File location for the image being created
        @type file_: String
        @param id_: Id for the image being created
        @type id_: UUID
        @param image_type: Image type for the image being created
        @type image_type: String
        @param min_disk: Minimum disk for the image being created
        @type min_disk: String
        @param min_ram: Minimum ram for the image being created
        @type min_ram: String
        @param name: Name for the image being created
        @type name: String
        @param os_type: OS type for the image being created
        @type os_type: String
        @param owner: Owner for the image being created
        @type owner: String
        @param protected: Protected flag for the image being created
        @type protected: Boolean
        @param schema: Schema for the image being created
        @type schema: String
        @param self_: Self location for the image being created
        @type self_: String
        @param size: Size for the image being created
        @type size: String
        @param status: Status for the image being created
        @type status: String
        @param tags: Tags for the image being created
        @type tags: Dictionary
        @param updated_at: Updated at for the image being created
        @type updated_at: Datetime
        @param user_id: User id for the image being created
        @type user_id: String
        @param visibility: Visibility for the image being created
        @type visibility: String
        @param additional_properties: Additional properties for the image being
        created
        @type additional_properties: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []

        for i in range(count):
            image = self.register_new_image(
                auto_disk_config=auto_disk_config,
                checksum=checksum,
                container_format=container_format,
                created_at=created_at,
                disk_format=disk_format,
                file_=file_,
                id_=id_,
                image_type=image_type,
                min_disk=min_disk,
                min_ram=min_ram,
                name=name,
                os_type=os_type,
                owner=owner,
                protected=protected,
                schema=schema,
                self_=self_,
                size=size,
                status=status,
                tags=tags,
                updated_at=updated_at,
                user_id=user_id,
                visibility=visibility,
                additional_properties=additional_properties)
            image_list.append(image)

        return image_list

    def list_all_images(self, **params):
        """
        @summary: Retrieve a complete list of images accounting for any
        query parameters

        @param params: Parameters to alter the returned list of images
        @type params: Dictionary

        @return: Image_list
        @rtype: List
        """

        image_list = []
        results_limit = self.config.results_limit

        response = self.client.list_images(params)
        images = response.entity

        while len(images) == results_limit:
            image_list += images
            marker = images[results_limit - 1].id_
            params.update({"marker": marker})
            response = self.client.list_images(params)
            images = response.entity

        image_list += images

        return image_list

    @staticmethod
    def get_time_delta(time_in_sec, time_property):
        """
        @summary: Calculate the difference between an image attribute's time
        value and a time_property

        @param time_in_sec: Current time in seconds
        @type time_in_sec: Integer
        @param time_property: Image property containing a time
        @type time_property: Datetime

        @return: Time_delta
        @rtype: Integer
        """

        time_property_in_sec = calendar.timegm(time_property.timetuple())

        return abs(time_property_in_sec - time_in_sec)

    @staticmethod
    def validate_image(image):
        """
        @summary: Generically validate an image contains crucial expected
        data

        @param image: Image to be validated
        @type image: Object

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        # The following properties do not always have values:
        # checksum, container_format, disk_format, name, tags

        if image.auto_disk_config is None:
            errors.append(
                Messages.PROPERTY_MSG.format('auto_disk_config', 'not None',
                                             image.auto_disk_config))
        if image.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             image.created_at))
        if image.file_ != '/v2/images/{0}/file'.format(image.id_):
            errors.append(
                Messages.PROPERTY_MSG.format(
                    'file', '/v2/images/{0}/file'.format(image.id_),
                    image.file_))
        if id_regex.match(image.id_) is None:
            errors.append(
                Messages.PROPERTY_MSG.format('id', 'not None', id_regex))
        if image.image_type is None:
            errors.append(
                Messages.PROPERTY_MSG.format('image_type', 'not None',
                                             image.image_type))
        if image.min_disk is None:
            errors.append(
                Messages.PROPERTY_MSG.format('min_disk', 'not None',
                                             image.min_disk))
        if image.min_ram is None:
            errors.append(
                Messages.PROPERTY_MSG.format('min_ram', 'not None',
                                             image.min_ram))
        if image.os_type is None:
            errors.append(
                Messages.PROPERTY_MSG.format('os_type', 'not None',
                                             image.os_type))
        if image.owner is None:
            errors.append(
                Messages.PROPERTY_MSG.format('owner', 'not None', image.owner))
        if image.protected is None:
            errors.append(
                Messages.PROPERTY_MSG.format('protected', 'not None',
                                             image.protected))
        if image.schema != Schemas.IMAGE_SCHEMA:
            errors.append(
                Messages.PROPERTY_MSG.format('schema', Schemas.IMAGE_SCHEMA,
                                             image.schema))
        if image.self_ != '/v2/images/{0}'.format(image.id_):
            errors.append(
                Messages.PROPERTY_MSG.format(
                    'self', '/v2/images/{0}'.format(image.id_), image.self_))
        if image.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             image.status))
        if image.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             image.updated_at))
        if image.user_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('user_id', 'not None',
                                             image.user_id))
        if image.visibility is None:
            errors.append(
                Messages.PROPERTY_MSG.format('visibility', 'not None',
                                             image.visibility))

        return errors

    @staticmethod
    def validate_image_member(image_member):
        """
        @summary: Generically validate an image member contains crucial
        expected data

        @param image_member: Image member to be validated
        @type image_member: Object

        @return: Errors
        @rtype: List
        """

        errors = []

        if image_member.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             image_member.created_at))
        if image_member.image_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('image_id', 'not None',
                                             image_member.image_id))
        if image_member.member_id is None:
            errors.append(
                Messages.PROPERTY_MSG.format('member_id', 'not None',
                                             image_member.member_id))
        if image_member.schema != Schemas.IMAGE_MEMBER_SCHEMA:
            errors.append(
                Messages.PROPERTY_MSG.format('schema',
                                             Schemas.IMAGE_MEMBER_SCHEMA,
                                             image_member.schema))
        if image_member.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             image_member.status))
        if image_member.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             image_member.updated_at))

        return errors

    def wait_for_image_status(self,
                              image_id,
                              desired_status,
                              interval_time=15,
                              timeout=900):
        """
        @summary: Wait for a image to reach a desired status

        @param image_id: Image id to evaluate
        @type image_id: UUID
        @param desired_status: Expected final status of image
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer

        @return: Resp
        @rtype: Object
        """

        interval_time = interval_time or self.config.image_status_interval
        timeout = timeout or self.config.snapshot_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_image_details(image_id)
            image = resp.entity

            if image.status.lower() == ImageStatus.ERROR.lower():
                raise BuildErrorException("Build failed. Image with uuid {0} "
                                          "entered ERROR status.".format(
                                              image.id))

            if image.status == desired_status:
                break

            time.sleep(interval_time)
        else:
            raise TimeoutException(
                "wait_for_image_status ran for {0} seconds and did not "
                "observe image {1} reach the {2} status.".format(
                    timeout, image_id, desired_status))

        return resp

    def create_new_task(self, input_=None, type_=None):
        """
        @summary: Create new task and wait for success status

        @param input_: Image properties and location data
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String

        @return: Task
        @rtype: Object
        """

        import_from = self.config.import_from
        input_ = input_ or {'image_properties': {}, 'import_from': import_from}
        type_ = type_ or TaskTypes.IMPORT
        failures = []
        attempts = self.config.resource_creation_attempts

        for attempt in range(attempts):
            try:
                resp = self.client.task_to_import_image(input_=input_,
                                                        type_=type_)
                task_id = resp.entity.id_
                task = self.wait_for_task_status(task_id, TaskStatus.SUCCESS)
                return task
            except (BuildErrorException, TimeoutException) as ex:
                failure = ('Attempt {0}: Failed to create task with '
                           'the message '
                           '{1}'.format(attempt + 1, ex.message))
                self._log.error(failure)
                failures.append(failure)
        raise RequiredResourceException(
            'Failed to successfully create a task after {0} attempts: '
            '{1}'.format(attempts, failures))

    def create_new_tasks(self, input_=None, type_=None, count=2):
        """
        @summary: Create new tasks and wait for success status for each

        @param input_: Image properties and image location
        @type input_: Dictionary
        @param type_: Type of task
        @type type_: String
        @param count: Number of tasks to create
        @type count: Integer

        @return: Task_list
        @rtype: List
        """

        task_list = []

        for i in range(count):
            task = self.create_new_task(input_=input_, type_=type_)
            task_list.append(task)

        return task_list

    def list_all_tasks(self,
                       limit=None,
                       marker=None,
                       sort_dir=None,
                       status=None,
                       type_=None):
        """
        @summary: Retrieve a complete list of tasks accounting for query
        parameters

        @param limit: Number of tasks to return
        @type limit: Integer
        @param marker: Task to start from
        @type marker: UUID
        @param sort_dir: Direction in which tasks will be returned
        @type sort_dir: String
        @param status: Status of tasks to return
        @type status: String
        @param type_: Type of tasks to return
        @type type_: String

        @return: Task_list
        @rtype: List
        """

        task_list = []
        results_limit = limit or self.config.results_limit

        response = self.client.list_tasks(limit=limit,
                                          marker=marker,
                                          sort_dir=sort_dir,
                                          status=status,
                                          type_=type_)
        tasks = response.entity

        while len(tasks) == results_limit:
            task_list += tasks
            marker = tasks[results_limit - 1].id_
            response = self.client.list_tasks(limit=limit,
                                              marker=marker,
                                              sort_dir=sort_dir,
                                              status=status,
                                              type_=type_)
            tasks = response.entity

        task_list += tasks

        return task_list

    @staticmethod
    def validate_task(task):
        """
        @summary: Generically validate a task contains crucial expected
        data

        @param task: Task to be validated
        @type task: UUID

        @return: Errors
        @rtype: List
        """

        id_regex = re.compile(ImageProperties.ID_REGEX)
        errors = []

        if task.status is None:
            errors.append(
                Messages.PROPERTY_MSG.format('status', 'not None',
                                             task.status))
        if id_regex.match(task.id_) is None:
            errors.append(
                Messages.PROPERTY_MSG.format('id_', 'not None',
                                             id_regex.match(task.id_)))
        if task.created_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('created_at', 'not None',
                                             task.created_at))
        if task.type_ == TaskTypes.IMPORT:
            if task.input_.import_from is None:
                errors.append(
                    Messages.PROPERTY_MSG.format('import_from', 'not None',
                                                 task.input_.import_from))
            if (task.result is not None
                    and id_regex.match(task.result.image_id) is None):
                errors.append(
                    Messages.PROPERTY_MSG.format(
                        'image_id', 'not None',
                        id_regex.match(task.result.image_id)))
        elif task.type_ == TaskTypes.EXPORT:
            if task.input_.image_uuid is None:
                errors.append(
                    Messages.PROPERTY_MSG.format('image_uuid', 'not None',
                                                 task.input_.image_uuid))
            if task.input_.receiving_swift_container is None:
                errors.append(
                    Messages.PROPERTY_MSG.format(
                        'receiving_swift_container', 'not None',
                        task.input_.receiving_swift_container))
            if task.result is not None and task.result.export_location is None:
                errors.append(
                    Messages.PROPERTY_MSG.format('export_location', 'not None',
                                                 task.result.export_location))
        elif task.type_ is None:
            errors.append(
                Messages.PROPERTY_MSG.format('type_', 'not None', task.type_))
        if task.updated_at is None:
            errors.append(
                Messages.PROPERTY_MSG.format('updated_at', 'not None',
                                             task.updated_at))
        if task.self_ != '/v2/tasks/{0}'.format(task.id_):
            errors.append(
                Messages.PROPERTY_MSG.format('self_',
                                             '/v2/tasks/{0}'.format(task.id_),
                                             task.self_))
        if task.owner is None:
            errors.append(
                Messages.PROPERTY_MSG.format('owner', 'not None', task.owner))
        if task.message != '':
            errors.append(
                Messages.PROPERTY_MSG.format('message', '', task.message))
        if task.schema != '/v2/schemas/task':
            errors.append(
                Messages.PROPERTY_MSG.format('schema', '/v2/schemas/task',
                                             task.schema))

        return errors

    @staticmethod
    def validate_exported_files(expect_success, files, image_id):
        """
        @summary: Validate that a given storage location contains a
        given file or not

        @param expect_success: Flag to determine if tasks completed
        successfully
        @type expect_success: Boolean
        @param files: File objects to be validated
        @type files: List
        @param image_id: Image id to validate against
        @type image_id: UUID

        @return: Errors, file_names
        @rtype: List, list
        """

        errors = []
        file_names = [file_.name for file_ in files]

        if expect_success:
            if '{0}.vhd'.format(image_id) not in file_names:
                errors.append('Unexpected file presence status.'
                              'Expected: True Received: False')
        else:
            if '{0}.vhd'.format(image_id) in file_names:
                errors.append('Unexpected file presence status. '
                              'Expected: False Received: True')

        return errors, file_names

    def wait_for_task_status(self,
                             task_id,
                             desired_status,
                             interval_time=10,
                             timeout=1200):
        """
        @summary: Waits for a task to reach a desired status

        @param task_id: Task id to evaluate
        @type task_id: UUID
        @param desired_status: Expected final status of task
        @type desired_status: String
        @param interval_time: Amount of time in seconds to wait between polling
        @type interval_time: Integer
        @param timeout: Amount of time in seconds to wait before aborting
        @type timeout: Integer

        @return: Task
        @rtype: Object
        """

        interval_time = interval_time or self.config.task_status_interval
        timeout = timeout or self.config.task_timeout
        end_time = time.time() + timeout

        while time.time() < end_time:
            resp = self.client.get_task_details(task_id)
            task = resp.entity

            if ((task.status.lower() == TaskStatus.FAILURE
                 and desired_status != TaskStatus.FAILURE)
                    or (task.status.lower() == TaskStatus.SUCCESS
                        and desired_status != TaskStatus.SUCCESS)):
                raise BuildErrorException(
                    'Task with uuid {0} entered {1} status. Task responded '
                    'with the message {2}'.format(
                        task.id_, task.status, task.message.replace('\\', '')))

            if task.status == desired_status:
                break
            time.sleep(interval_time)
        else:
            raise TimeoutException(
                'Failed to reach the {0} status after {1} seconds for task '
                'with uuid {2}'.format(desired_status, timeout, task_id))

        if (task is not None and task.type_ == TaskTypes.IMPORT
                and task.status.lower() == TaskStatus.SUCCESS):
            self.resources.add(task.result.image_id, self.client.delete_image)

        return task

    def create_task_with_transitions(self,
                                     input_,
                                     task_type,
                                     outcome,
                                     final_status=None):
        """
        @summary: Create a task and verify that it transitions through the
        expected statuses

        @param input_: Image properties and location data
        @type input_: Dictionary
        @param task_type: Type of task
        @type task_type: String
        @param outcome: Expected final status
        @type outcome: Integer
        @param final_status: Flag to determine success or failure
        @type final_status: String

        @return: Task
        @rtype: Object
        """

        response = self.client.create_task(input_=input_, type_=task_type)
        task = response.entity

        response = self.client.get_task_details(task.id_)
        task_status = response.entity.status.lower()

        # Verify task progresses as expected
        verifier = StatusProgressionVerifier('task', task.id_, task_status,
                                             task.id_)

        verifier.add_state(
            expected_statuses=[TaskStatus.PENDING],
            acceptable_statuses=[TaskStatus.PROCESSING, outcome],
            error_statuses=[TaskStatus.SUCCESS],
            timeout=self.config.task_timeout,
            poll_rate=1)

        verifier.add_state(
            expected_statuses=[TaskStatus.PROCESSING],
            acceptable_statuses=[outcome],
            error_statuses=[TaskStatus.PENDING, TaskStatus.SUCCESS],
            timeout=self.config.task_timeout,
            poll_rate=1)

        if final_status == TaskStatus.SUCCESS:
            verifier.add_state(
                expected_statuses=[TaskStatus.SUCCESS],
                error_statuses=[TaskStatus.PENDING, TaskStatus.FAILURE],
                timeout=self.config.task_timeout,
                poll_rate=1)

        if final_status == TaskStatus.FAILURE:
            verifier.add_state(
                expected_statuses=[TaskStatus.FAILURE],
                error_statuses=[TaskStatus.PENDING, TaskStatus.SUCCESS],
                timeout=self.config.task_timeout,
                poll_rate=1)

        verifier.start()

        return self.client.get_task_details(task.id_).entity
Esempio n. 26
0
 def setUpClass(cls):
     super(ImagesFixture, cls).setUpClass()
     cls.config = ImagesConfig()
     cls.resources = ResourcePool()
Esempio n. 27
0
 def __init__(self, images_client, images_config):
     super(ImagesBehaviors, self).__init__()
     self.config = images_config
     self.client = images_client
     self.resources = ResourcePool()