From c029b58ddcde9973a9665abd7cf66d51786afa08 Mon Sep 17 00:00:00 2001 From: Luke Wollney Date: Mon, 11 May 2015 14:51:07 -0500 Subject: [PATCH] Remove all references to export task from cloudcafe *Removed all references to exporting a task in behaviors, client, constants, types, config, and task model *These references are being moved internally as they are not available in Openstack *Removed single reference to clone as well since it is not used anywhere currently *Updated behaviors and client to handle additional parameters related to tasks *Rebased master Change-Id: I1c8ab3e1fc2e1d52803dfb21f2b137482c812609 --- cloudcafe/glance/behaviors.py | 119 ++++++++++----------------- cloudcafe/glance/client.py | 37 +++------ cloudcafe/glance/common/constants.py | 5 -- cloudcafe/glance/common/types.py | 3 - cloudcafe/glance/composite.py | 6 +- cloudcafe/glance/config.py | 10 --- cloudcafe/glance/models/task.py | 6 +- 7 files changed, 57 insertions(+), 129 deletions(-) diff --git a/cloudcafe/glance/behaviors.py b/cloudcafe/glance/behaviors.py index 433998bf..84e53fb9 100644 --- a/cloudcafe/glance/behaviors.py +++ b/cloudcafe/glance/behaviors.py @@ -29,6 +29,7 @@ from cloudcafe.glance.common.constants import ImageProperties, Messages from cloudcafe.glance.common.types import ( ImageContainerFormat, ImageDiskFormat, ImageStatus, Schemas, TaskStatus, TaskTypes) +from cloudcafe.glance.models.task import Task class ImagesBehaviors(BaseBehavior): @@ -522,12 +523,8 @@ class ImagesBehaviors(BaseBehavior): 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_) + resp = self.client.task_to_import_image(input_=input_, + type_=type_) task = resp.entity task = self.wait_for_task_status(task.id_, TaskStatus.SUCCESS) @@ -624,27 +621,14 @@ class ImagesBehaviors(BaseBehavior): 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)) + 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_ is None: errors.append(Messages.PROPERTY_MSG.format( 'type_', 'not None', task.type_)) @@ -666,41 +650,8 @@ class ImagesBehaviors(BaseBehavior): 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): + 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 @@ -714,6 +665,9 @@ class ImagesBehaviors(BaseBehavior): @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 @@ -722,9 +676,12 @@ class ImagesBehaviors(BaseBehavior): 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) + 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 @@ -751,33 +708,33 @@ class ImagesBehaviors(BaseBehavior): return task - def create_task_with_transitions(self, input_, task_type, - final_status=None): + 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 input_: Image properties and location data - @type input_: Dictionary - @param task_type: Type of task - @type task_type: String + @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 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) + if not response_entity_type: + response_entity_type = Task - task = self.verify_resp(resp, 'create 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_) + 'task', task.id_, self.get_task_status, task.id_, + response_entity_type=response_entity_type) if final_status == TaskStatus.SUCCESS: error_statuses = [TaskStatus.FAILURE] @@ -814,21 +771,29 @@ class ImagesBehaviors(BaseBehavior): verifier.start() - return self.client.get_task_details(task.id_).entity + return self.client.get_task_details( + task.id_, response_entity_type=response_entity_type).entity - def get_task_status(self, task_id): + 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 """ - resp = self.client.get_task_details(task_id) + 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() diff --git a/cloudcafe/glance/client.py b/cloudcafe/glance/client.py index 6a62e7f3..5aafd961 100644 --- a/cloudcafe/glance/client.py +++ b/cloudcafe/glance/client.py @@ -488,7 +488,8 @@ class ImagesClient(AutoMarshallingHTTPClient): response_entity_type=Tasks, requestslib_kwargs=requestslib_kwargs) - def get_task_details(self, task_id, requestslib_kwargs=None): + def get_task_details(self, task_id, requestslib_kwargs=None, + response_entity_type=None): """ @summary: Get the details of a task @@ -497,6 +498,9 @@ class ImagesClient(AutoMarshallingHTTPClient): @param requestslib_kwargs: Keyword arguments to be passed on to python requests @type requestslib_kwargs: Dictionary + @param response_entity_type: Response entity type to be passed on to + python requests + @type response_entity_type: Type @return: Response @rtype: Object @@ -504,7 +508,11 @@ class ImagesClient(AutoMarshallingHTTPClient): url = '{0}/tasks/{1}'.format(self.base_url, task_id) - return self.request('GET', url, response_entity_type=Task, + if not response_entity_type: + response_entity_type = Task + + return self.request('GET', url, + response_entity_type=response_entity_type, requestslib_kwargs=requestslib_kwargs) def task_to_import_image(self, input_=None, type_=None, @@ -532,31 +540,6 @@ class ImagesClient(AutoMarshallingHTTPClient): response_entity_type=Task, requestslib_kwargs=requestslib_kwargs) - def task_to_export_image(self, input_=None, type_=None, - requestslib_kwargs=None): - """ - @summary: Create a task to export an image - - @param input_: Container for export input parameters containing - image uuid and receiving swift container - @type input_: Dictionary - @param type_: Type of task - @type type_: String - @param requestslib_kwargs: Keyword arguments to be passed on to - python requests - @type requestslib_kwargs: Dictionary - - @return: Response - @rtype: Object - """ - - url = '{0}/tasks'.format(self.base_url) - task = Task(input_=input_, type_=type_) - - return self.request('POST', url, request_entity=task, - response_entity_type=Task, - requestslib_kwargs=requestslib_kwargs) - def delete_task(self, task_id, requestslib_kwargs=None): """ @summary: Delete a task - Not listed in the Images API docs diff --git a/cloudcafe/glance/common/constants.py b/cloudcafe/glance/common/constants.py index 3060425c..26f8310f 100644 --- a/cloudcafe/glance/common/constants.py +++ b/cloudcafe/glance/common/constants.py @@ -25,18 +25,13 @@ class Messages(object): CONTAINER_DNE = 'Container not found. Container: {0}' DUPLICATE_FILE_MSG = ('Object already exists in user\'s container. ' 'Container/Object: {0}/{1}.vhd') - EXPORT_WINDOWS_MSG = ('Image cannot be exported due to licensing or ' - 'billing restrictions (com.rackspace__1__options: ' - '\'{0}\')') EXTRA_IMAGE_PROPERTIES_MSG = ('Unsupported element in image_properties, ' 'please consult the documentation.') - NOT_OWNER_MSG = 'An image may only be exported by the image owner.' IMAGE_NOT_FOUND = 'Image not found for import. Possible invalid location' OK_RESP_MSG = 'Unexpected response received. Expected: OK, Received: {0}' PROPERTY_MSG = ('Unexpected value for {0} received. Expected: {1}, ' 'Received: {2}') STATUS_CODE_MSG = ('Unexpected status code received. Expected: {0}, ' 'Received: {1}') - EXPORT_UNKNOWN_ERROR_MSG = 'Unknown error occurred during image export' UPDATE_IMAGE_MEMBER_STATUS = ('You are not permitted to modify \'status\' ' 'on this image.') diff --git a/cloudcafe/glance/common/types.py b/cloudcafe/glance/common/types.py index 1825dc05..26bfc382 100644 --- a/cloudcafe/glance/common/types.py +++ b/cloudcafe/glance/common/types.py @@ -72,7 +72,6 @@ class ImageType(object): """@summary: Types denoting an Image's type""" BASE = 'base' - EXPORT = 'export' IMPORT = 'import' SNAPSHOT = 'snapshot' @@ -116,5 +115,3 @@ class TaskTypes(object): """@summary: Types denoting a Task's types""" IMPORT = 'import' - EXPORT = 'export' - CLONE = 'clone' diff --git a/cloudcafe/glance/composite.py b/cloudcafe/glance/composite.py index 91ca83a3..cf9c337e 100644 --- a/cloudcafe/glance/composite.py +++ b/cloudcafe/glance/composite.py @@ -70,11 +70,11 @@ class ImagesComposite(object): self.marshalling = MarshallingConfig() # If an override_url was provided, use it instead if self.auth.images_endpoint_config.override_url: - url = self.auth.images_endpoint_config.override_url + self.url = self.auth.images_endpoint_config.override_url else: - url = self.auth.public_url + self.url = self.auth.public_url self.client = ImagesClient( - url, self.auth.token_id, self.marshalling.serializer, + self.url, self.auth.token_id, self.marshalling.serializer, self.marshalling.deserializer) self.behaviors = ImagesBehaviors( diff --git a/cloudcafe/glance/config.py b/cloudcafe/glance/config.py index f36cbfb7..aac1e583 100644 --- a/cloudcafe/glance/config.py +++ b/cloudcafe/glance/config.py @@ -244,16 +244,6 @@ class ImagesConfig(ConfigSectionInterface): """Location from which to import a bootable VHD""" return self.get('import_from_bootable') - @property - def export_to(self): - """Location to export a given file""" - return self.get('export_to') - - @property - def alt_export_to(self): - """Location to export a given file""" - return self.get('alt_export_to') - @property def task_status_interval(self): """Amount of time to wait between polling the status of a task""" diff --git a/cloudcafe/glance/models/task.py b/cloudcafe/glance/models/task.py index e7554bd8..9ef9d5d4 100644 --- a/cloudcafe/glance/models/task.py +++ b/cloudcafe/glance/models/task.py @@ -187,9 +187,8 @@ class Input(AutoMarshallingModel): class Result(AutoMarshallingModel): """@summary: Result for Task v2 model""" - def __init__(self, export_location=None, image_id=None): + def __init__(self, image_id=None): super(Result, self).__init__() - self.export_location = export_location self.image_id = image_id def __eq__(self, other): @@ -208,8 +207,7 @@ class Result(AutoMarshallingModel): result = None result_dict = json_dict.get('result') if result_dict: - result = Result(image_id=result_dict.get('image_id'), - export_location=result_dict.get('export_location')) + result = Result(image_id=result_dict.get('image_id')) return result @classmethod