http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dimensiondata.py b/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dimensiondata.py deleted file mode 100644 index fc83a55..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dimensiondata.py +++ /dev/null @@ -1,688 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -try: - from lxml import etree as ET -except ImportError: - from xml.etree import ElementTree as ET - -from libcloud.backup.base import BackupDriver, BackupTarget, BackupTargetJob -from libcloud.backup.types import BackupTargetType -from libcloud.backup.types import Provider -from libcloud.common.dimensiondata import dd_object_to_id -from libcloud.common.dimensiondata import DimensionDataConnection -from libcloud.common.dimensiondata import DimensionDataBackupClient -from libcloud.common.dimensiondata import DimensionDataBackupClientAlert -from libcloud.common.dimensiondata import DimensionDataBackupClientType -from libcloud.common.dimensiondata import DimensionDataBackupDetails -from libcloud.common.dimensiondata import DimensionDataBackupSchedulePolicy -from libcloud.common.dimensiondata import DimensionDataBackupStoragePolicy -from libcloud.common.dimensiondata import API_ENDPOINTS, DEFAULT_REGION -from libcloud.common.dimensiondata import TYPES_URN -from libcloud.common.dimensiondata import GENERAL_NS, BACKUP_NS -from libcloud.utils.xml import fixxpath, findtext, findall - -DEFAULT_BACKUP_PLAN = 'Advanced' - - -class DimensionDataBackupDriver(BackupDriver): - """ - DimensionData backup driver. - """ - - selected_region = None - connectionCls = DimensionDataConnection - name = 'Dimension Data Backup' - website = 'https://cloud.dimensiondata.com/' - type = Provider.DIMENSIONDATA - api_version = 1.0 - - network_domain_id = None - - def __init__(self, key, secret=None, secure=True, host=None, port=None, - api_version=None, region=DEFAULT_REGION, **kwargs): - - if region not in API_ENDPOINTS: - raise ValueError('Invalid region: %s' % (region)) - - self.selected_region = API_ENDPOINTS[region] - - super(DimensionDataBackupDriver, self).__init__( - key=key, secret=secret, - secure=secure, host=host, - port=port, - api_version=api_version, - region=region, - **kwargs) - - def _ex_connection_class_kwargs(self): - """ - Add the region to the kwargs before the connection is instantiated - """ - - kwargs = super(DimensionDataBackupDriver, - self)._ex_connection_class_kwargs() - kwargs['region'] = self.selected_region - return kwargs - - def get_supported_target_types(self): - """ - Get a list of backup target types this driver supports - - :return: ``list`` of :class:``BackupTargetType`` - """ - return [BackupTargetType.VIRTUAL] - - def list_targets(self): - """ - List all backuptargets - - :rtype: ``list`` of :class:`BackupTarget` - """ - targets = self._to_targets( - self.connection.request_with_orgId_api_2('server/server').object) - return targets - - def create_target(self, name, address, - type=BackupTargetType.VIRTUAL, extra=None): - """ - Creates a new backup target - - :param name: Name of the target (not used) - :type name: ``str`` - - :param address: The ID of the node in Dimension Data Cloud - :type address: ``str`` - - :param type: Backup target type, only Virtual supported - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - if extra is not None: - service_plan = extra.get('servicePlan', DEFAULT_BACKUP_PLAN) - else: - service_plan = DEFAULT_BACKUP_PLAN - extra = {'servicePlan': service_plan} - - create_node = ET.Element('NewBackup', - {'xmlns': BACKUP_NS}) - create_node.set('servicePlan', service_plan) - - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup' % (address), - method='POST', - data=ET.tostring(create_node)).object - - asset_id = None - for info in findall(response, - 'additionalInformation', - GENERAL_NS): - if info.get('name') == 'assetId': - asset_id = findtext(info, 'value', GENERAL_NS) - - return BackupTarget( - id=asset_id, - name=name, - address=address, - type=type, - extra=extra, - driver=self - ) - - def create_target_from_node(self, node, type=BackupTargetType.VIRTUAL, - extra=None): - """ - Creates a new backup target from an existing node - - :param node: The Node to backup - :type node: ``Node`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - return self.create_target(name=node.name, - address=node.id, - type=BackupTargetType.VIRTUAL, - extra=extra) - - def create_target_from_container(self, container, - type=BackupTargetType.OBJECT, - extra=None): - """ - Creates a new backup target from an existing storage container - - :param node: The Container to backup - :type node: ``Container`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - return NotImplementedError( - 'create_target_from_container not supported for this driver') - - def update_target(self, target, name=None, address=None, extra=None): - """ - Update the properties of a backup target, only changing the serviceplan - is supported. - - :param target: Backup target to update - :type target: Instance of :class:`BackupTarget` or ``str`` - - :param name: Name of the target - :type name: ``str`` - - :param address: Hostname, FQDN, IP, file path etc. - :type address: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - if extra is not None: - service_plan = extra.get('servicePlan', DEFAULT_BACKUP_PLAN) - else: - service_plan = DEFAULT_BACKUP_PLAN - request = ET.Element('ModifyBackup', - {'xmlns': BACKUP_NS}) - request.set('servicePlan', service_plan) - server_id = self._target_to_target_address(target) - self.connection.request_with_orgId_api_1( - 'server/%s/backup/modify' % (server_id), - method='POST', - data=ET.tostring(request)).object - if isinstance(target, BackupTarget): - target.extra = extra - else: - target = self.ex_get_target_by_id(server_id) - return target - - def delete_target(self, target): - """ - Delete a backup target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` or ``str`` - - :rtype: ``bool`` - """ - server_id = self._target_to_target_address(target) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup?disable' % (server_id), - method='GET').object - response_code = findtext(response, 'result', GENERAL_NS) - return response_code in ['IN_PROGRESS', 'SUCCESS'] - - def list_recovery_points(self, target, start_date=None, end_date=None): - """ - List the recovery points available for a target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param start_date: The start date to show jobs between (optional) - :type start_date: :class:`datetime.datetime` - - :param end_date: The end date to show jobs between (optional) - :type end_date: :class:`datetime.datetime`` - - :rtype: ``list`` of :class:`BackupTargetRecoveryPoint` - """ - raise NotImplementedError( - 'list_recovery_points not implemented for this driver') - - def recover_target(self, target, recovery_point, path=None): - """ - Recover a backup target to a recovery point - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'recover_target not implemented for this driver') - - def recover_target_out_of_place(self, target, recovery_point, - recovery_target, path=None): - """ - Recover a backup target to a recovery point out-of-place - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param recovery_target: Backup target with to recover the data to - :type recovery_target: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'recover_target_out_of_place not implemented for this driver') - - def get_target_job(self, target, id): - """ - Get a specific backup job by ID - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param id: Backup target with the backup data - :type id: Instance of :class:`BackupTarget` - - :rtype: :class:`BackupTargetJob` - """ - jobs = self.list_target_jobs(target) - return list(filter(lambda x: x.id == id, jobs))[0] - - def list_target_jobs(self, target): - """ - List the backup jobs on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :rtype: ``list`` of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'list_target_jobs not implemented for this driver') - - def create_target_job(self, target, extra=None): - """ - Create a new backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'create_target_job not implemented for this driver') - - def resume_target_job(self, target, job): - """ - Resume a suspended backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param job: Backup target job to resume - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'resume_target_job not implemented for this driver') - - def suspend_target_job(self, target, job): - """ - Suspend a running backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param job: Backup target job to suspend - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'suspend_target_job not implemented for this driver') - - def cancel_target_job(self, job, ex_client=None, ex_target=None): - """ - Cancel a backup job on a target - - :param job: Backup target job to cancel. If it is ``None`` - ex_client and ex_target must be set - :type job: Instance of :class:`BackupTargetJob` or ``None`` - - :param ex_client: Client of the job to cancel. - Not necessary if job is specified. - DimensionData only has 1 job per client - :type ex_client: Instance of :class:`DimensionDataBackupClient` - or ``str`` - - :param ex_target: Target to cancel a job from. - Not necessary if job is specified. - :type ex_target: Instance of :class:`BackupTarget` or ``str`` - - :rtype: ``bool`` - """ - if job is None: - if ex_client is None or ex_target is None: - raise ValueError("Either job or ex_client and " - "ex_target have to be set") - server_id = self._target_to_target_address(ex_target) - client_id = self._client_to_client_id(ex_client) - else: - server_id = job.target.address - client_id = job.extra['clientId'] - - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client/%s?cancelJob' % (server_id, - client_id), - method='GET').object - response_code = findtext(response, 'result', GENERAL_NS) - return response_code in ['IN_PROGRESS', 'SUCCESS'] - - def ex_get_target_by_id(self, id): - """ - Get a target by server id - - :param id: The id of the target you want to get - :type id: ``str`` - - :rtype: :class:`BackupTarget` - """ - node = self.connection.request_with_orgId_api_2( - 'server/server/%s' % id).object - return self._to_target(node) - - def ex_add_client_to_target(self, target, client_type, storage_policy, - schedule_policy, trigger, email): - """ - Add a client to a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` or ``str`` - - :param client: Client to add to the target - :type client: Instance of :class:`DimensionDataBackupClientType` - or ``str`` - - :param storage_policy: The storage policy for the client - :type storage_policy: Instance of - :class:`DimensionDataBackupStoragePolicy` - or ``str`` - - :param schedule_policy: The schedule policy for the client - :type schedule_policy: Instance of - :class:`DimensionDataBackupSchedulePolicy` - or ``str`` - - :param trigger: The notify trigger for the client - :type trigger: ``str`` - - :param email: The notify email for the client - :type email: ``str`` - - :rtype: ``bool`` - """ - server_id = self._target_to_target_address(target) - - backup_elm = ET.Element('NewBackupClient', - {'xmlns': BACKUP_NS}) - if isinstance(client_type, DimensionDataBackupClientType): - ET.SubElement(backup_elm, "type").text = client_type.type - else: - ET.SubElement(backup_elm, "type").text = client_type - - if isinstance(storage_policy, DimensionDataBackupStoragePolicy): - ET.SubElement(backup_elm, - "storagePolicyName").text = storage_policy.name - else: - ET.SubElement(backup_elm, - "storagePolicyName").text = storage_policy - - if isinstance(schedule_policy, DimensionDataBackupSchedulePolicy): - ET.SubElement(backup_elm, - "schedulePolicyName").text = schedule_policy.name - else: - ET.SubElement(backup_elm, - "schedulePolicyName").text = schedule_policy - - alerting_elm = ET.SubElement(backup_elm, "alerting") - alerting_elm.set('trigger', trigger) - ET.SubElement(alerting_elm, "emailAddress").text = email - - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client' % (server_id), - method='POST', - data=ET.tostring(backup_elm)).object - response_code = findtext(response, 'result', GENERAL_NS) - return response_code in ['IN_PROGRESS', 'SUCCESS'] - - def ex_remove_client_from_target(self, target, backup_client): - """ - Removes a client from a backup target - - :param target: The backup target to remove the client from - :type target: :class:`BackupTarget` or ``str`` - - :param backup_client: The backup client to remove - :type backup_client: :class:`DimensionDataBackupClient` or ``str`` - - :rtype: ``bool`` - """ - server_id = self._target_to_target_address(target) - client_id = self._client_to_client_id(backup_client) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client/%s?disable' % (server_id, client_id), - method='GET').object - response_code = findtext(response, 'result', GENERAL_NS) - return response_code in ['IN_PROGRESS', 'SUCCESS'] - - def ex_get_backup_details_for_target(self, target): - """ - Returns a backup details object for a target - - :param target: The backup target to get details for - :type target: :class:`BackupTarget` or ``str`` - - :rtype: :class:`DimensionDataBackupDetails` - """ - if not isinstance(target, BackupTarget): - target = self.ex_get_target_by_id(target) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup' % (target.address), - method='GET').object - return self._to_backup_details(response, target) - - def ex_list_available_client_types(self, target): - """ - Returns a list of available backup client types - - :param target: The backup target to list available types for - :type target: :class:`BackupTarget` or ``str`` - - :rtype: ``list`` of :class:`DimensionDataBackupClientType` - """ - server_id = self._target_to_target_address(target) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client/type' % (server_id), - method='GET').object - return self._to_client_types(response) - - def ex_list_available_storage_policies(self, target): - """ - Returns a list of available backup storage policies - - :param target: The backup target to list available policies for - :type target: :class:`BackupTarget` or ``str`` - - :rtype: ``list`` of :class:`DimensionDataBackupStoragePolicy` - """ - server_id = self._target_to_target_address(target) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client/storagePolicy' % (server_id), - method='GET').object - return self._to_storage_policies(response) - - def ex_list_available_schedule_policies(self, target): - """ - Returns a list of available backup schedule policies - - :param target: The backup target to list available policies for - :type target: :class:`BackupTarget` or ``str`` - - :rtype: ``list`` of :class:`DimensionDataBackupSchedulePolicy` - """ - server_id = self._target_to_target_address(target) - response = self.connection.request_with_orgId_api_1( - 'server/%s/backup/client/schedulePolicy' % (server_id), - method='GET').object - return self._to_schedule_policies(response) - - def _to_storage_policies(self, object): - elements = object.findall(fixxpath('storagePolicy', BACKUP_NS)) - - return [self._to_storage_policy(el) for el in elements] - - def _to_storage_policy(self, element): - return DimensionDataBackupStoragePolicy( - retention_period=int(element.get('retentionPeriodInDays')), - name=element.get('name'), - secondary_location=element.get('secondaryLocation') - ) - - def _to_schedule_policies(self, object): - elements = object.findall(fixxpath('schedulePolicy', BACKUP_NS)) - - return [self._to_schedule_policy(el) for el in elements] - - def _to_schedule_policy(self, element): - return DimensionDataBackupSchedulePolicy( - name=element.get('name'), - description=element.get('description') - ) - - def _to_client_types(self, object): - elements = object.findall(fixxpath('backupClientType', BACKUP_NS)) - - return [self._to_client_type(el) for el in elements] - - def _to_client_type(self, element): - description = element.get('description') - if description is None: - description = findtext(element, 'description', BACKUP_NS) - return DimensionDataBackupClientType( - type=element.get('type'), - description=description, - is_file_system=bool(element.get('isFileSystem') == 'true') - ) - - def _to_backup_details(self, object, target): - return DimensionDataBackupDetails( - asset_id=object.get('assetId'), - service_plan=object.get('servicePlan'), - status=object.get('state'), - clients=self._to_clients(object, target) - ) - - def _to_clients(self, object, target): - elements = object.findall(fixxpath('backupClient', BACKUP_NS)) - - return [self._to_client(el, target) for el in elements] - - def _to_client(self, element, target): - client_id = element.get('id') - return DimensionDataBackupClient( - id=client_id, - type=self._to_client_type(element), - status=element.get('status'), - schedule_policy=findtext(element, 'schedulePolicyName', BACKUP_NS), - storage_policy=findtext(element, 'storagePolicyName', BACKUP_NS), - download_url=findtext(element, 'downloadUrl', BACKUP_NS), - running_job=self._to_backup_job(element, target, client_id), - alert=self._to_alert(element) - ) - - def _to_alert(self, element): - alert = element.find(fixxpath('alerting', BACKUP_NS)) - if alert is not None: - notify_list = [ - email_addr.text for email_addr - in alert.findall(fixxpath('emailAddress', BACKUP_NS)) - ] - return DimensionDataBackupClientAlert( - trigger=element.get('trigger'), - notify_list=notify_list - ) - return None - - def _to_backup_job(self, element, target, client_id): - running_job = element.find(fixxpath('runningJob', BACKUP_NS)) - if running_job is not None: - return BackupTargetJob( - id=running_job.get('id'), - status=running_job.get('status'), - progress=int(running_job.get('percentageComplete')), - driver=self.connection.driver, - target=target, - extra={'clientId': client_id} - ) - return None - - def _to_targets(self, object): - node_elements = object.findall(fixxpath('server', TYPES_URN)) - - return [self._to_target(el) for el in node_elements] - - def _to_target(self, element): - backup = findall(element, 'backup', TYPES_URN) - if len(backup) == 0: - return - extra = { - 'description': findtext(element, 'description', TYPES_URN), - 'sourceImageId': findtext(element, 'sourceImageId', TYPES_URN), - 'datacenterId': element.get('datacenterId'), - 'deployedTime': findtext(element, 'createTime', TYPES_URN), - 'servicePlan': backup[0].get('servicePlan') - } - - n = BackupTarget(id=backup[0].get('assetId'), - name=findtext(element, 'name', TYPES_URN), - address=element.get('id'), - driver=self.connection.driver, - type=BackupTargetType.VIRTUAL, - extra=extra) - return n - - @staticmethod - def _client_to_client_id(backup_client): - return dd_object_to_id(backup_client, DimensionDataBackupClient) - - @staticmethod - def _target_to_target_address(target): - return dd_object_to_id(target, BackupTarget, id_value='address')
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dummy.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dummy.py b/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dummy.py deleted file mode 100644 index 2b28d66..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/dummy.py +++ /dev/null @@ -1,41 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from libcloud.backup.base import BackupDriver - - -class DummyBackupDriver(BackupDriver): - """ - Dummy Backup driver. - - >>> from libcloud.backup.drivers.dummy import DummyBackupDriver - >>> driver = DummyBackupDriver('key', 'secret') - >>> driver.name - 'Dummy Backup Provider' - """ - - name = 'Dummy Backup Provider' - website = 'http://example.com' - - def __init__(self, api_key, api_secret): - """ - :param api_key: API key or username to used (required) - :type api_key: ``str`` - - :param api_secret: Secret password to be used (required) - :type api_secret: ``str`` - - :rtype: ``None`` - """ http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/ebs.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/ebs.py b/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/ebs.py deleted file mode 100644 index fbeddb1..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/ebs.py +++ /dev/null @@ -1,413 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -__all__ = [ - 'EBSBackupDriver' -] - - -from libcloud.utils.xml import findtext, findall -from libcloud.utils.iso8601 import parse_date -from libcloud.backup.base import BackupDriver, BackupTargetRecoveryPoint,\ - BackupTargetJob, BackupTarget -from libcloud.backup.types import BackupTargetType, BackupTargetJobStatusType -from libcloud.common.aws import AWSGenericResponse, SignedAWSConnection - - -VERSION = '2015-10-01' -HOST = 'ec2.amazonaws.com' -ROOT = '/%s/' % (VERSION) -NS = 'http://ec2.amazonaws.com/doc/%s/' % (VERSION, ) - - -class EBSResponse(AWSGenericResponse): - """ - Amazon EBS response class. - """ - namespace = NS - exceptions = {} - xpath = 'Error' - - -class EBSConnection(SignedAWSConnection): - version = VERSION - host = HOST - responseCls = EBSResponse - service_name = 'backup' - - -class EBSBackupDriver(BackupDriver): - name = 'Amazon EBS Backup Driver' - website = 'http://aws.amazon.com/ebs/' - connectionCls = EBSConnection - - def __init__(self, access_id, secret, region): - super(EBSBackupDriver, self).__init__(access_id, secret) - self.region = region - self.connection.host = HOST % (region) - - def get_supported_target_types(self): - """ - Get a list of backup target types this driver supports - - :return: ``list`` of :class:``BackupTargetType`` - """ - return [BackupTargetType.VOLUME] - - def list_targets(self): - """ - List all backuptargets - - :rtype: ``list`` of :class:`BackupTarget` - """ - raise NotImplementedError( - 'list_targets not implemented for this driver') - - def create_target(self, name, address, - type=BackupTargetType.VOLUME, extra=None): - """ - Creates a new backup target - - :param name: Name of the target - :type name: ``str`` - - :param address: The volume ID. - :type address: ``str`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Does nothing since any volume can be snapped at anytime. - return self.ex_get_target_by_volume_id(address) - - def create_target_from_node(self, node, type=BackupTargetType.VIRTUAL, - extra=None): - """ - Creates a new backup target from an existing node - - :param node: The Node to backup - :type node: ``Node`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Get the first EBS volume. - device_mapping = node.extra['block_device_mapping'] - if device_mapping is not None: - return self.create_target( - name=node.name, - address=device_mapping['ebs'][0]['volume_id'], - type=BackupTargetType.VOLUME, - extra=None) - else: - raise RuntimeError("Node does not have any block devices") - - def create_target_from_container(self, container, - type=BackupTargetType.OBJECT, - extra=None): - """ - Creates a new backup target from an existing storage container - - :param node: The Container to backup - :type node: ``Container`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - raise NotImplementedError( - 'create_target_from_container not implemented for this driver') - - def update_target(self, target, name, address, extra): - """ - Update the properties of a backup target - - :param target: Backup target to update - :type target: Instance of :class:`BackupTarget` - - :param name: Name of the target - :type name: ``str`` - - :param address: Hostname, FQDN, IP, file path etc. - :type address: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Does nothing since any volume can be snapped at anytime. - return self.ex_get_target_by_volume_id(address) - - def delete_target(self, target): - """ - Delete a backup target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - """ - raise NotImplementedError( - 'delete_target not implemented for this driver') - - def list_recovery_points(self, target, start_date=None, end_date=None): - """ - List the recovery points available for a target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param start_date: The start date to show jobs between (optional) - :type start_date: :class:`datetime.datetime` - - :param end_date: The end date to show jobs between (optional) - :type end_date: :class:`datetime.datetime`` - - :rtype: ``list`` of :class:`BackupTargetRecoveryPoint` - """ - params = { - 'Action': 'DescribeSnapshots', - 'Filter.1.Name': 'volume-id', - 'Filter.1.Value': target.extra['volume-id'] - } - data = self.connection.request(ROOT, params=params).object - return self._to_recovery_points(data, target) - - def recover_target(self, target, recovery_point, path=None): - """ - Recover a backup target to a recovery point - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'delete_target not implemented for this driver') - - def recover_target_out_of_place(self, target, recovery_point, - recovery_target, path=None): - """ - Recover a backup target to a recovery point out-of-place - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param recovery_target: Backup target with to recover the data to - :type recovery_target: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'delete_target not implemented for this driver') - - def get_target_job(self, target, id): - """ - Get a specific backup job by ID - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param id: Backup target with the backup data - :type id: Instance of :class:`BackupTarget` - - :rtype: :class:`BackupTargetJob` - """ - jobs = self.list_target_jobs(target) - return list(filter(lambda x: x.id == id, jobs))[0] - - def list_target_jobs(self, target): - """ - List the backup jobs on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :rtype: ``list`` of :class:`BackupTargetJob` - """ - params = { - 'Action': 'DescribeSnapshots', - 'Filter.1.Name': 'volume-id', - 'Filter.1.Value': target.extra['volume-id'], - 'Filter.2.Name': 'status', - 'Filter.2.Value': 'pending' - } - data = self.connection.request(ROOT, params=params).object - return self._to_jobs(data) - - def create_target_job(self, target, extra=None): - """ - Create a new backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - params = { - 'Action': 'CreateSnapshot', - 'VolumeId': target.extra['volume-id'] - } - data = self.connection.request(ROOT, params=params).object - xpath = 'CreateSnapshotResponse' - return self._to_job(findall(element=data, - xpath=xpath, namespace=NS)[0]) - - def resume_target_job(self, job): - """ - Resume a suspended backup job on a target - - :param job: Backup target job to resume - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'resume_target_job not supported for this driver') - - def suspend_target_job(self, job): - """ - Suspend a running backup job on a target - - :param job: Backup target job to suspend - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'suspend_target_job not supported for this driver') - - def cancel_target_job(self, job): - """ - Cancel a backup job on a target - - :param job: Backup target job to cancel - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'cancel_target_job not supported for this driver') - - def _to_recovery_points(self, data, target): - xpath = 'DescribeSnapshotsResponse/snapshotSet/item' - return [self._to_recovery_point(el, target) - for el in findall(element=data, xpath=xpath, namespace=NS)] - - def _to_recovery_point(self, el, target): - id = findtext(element=el, xpath='snapshotId', namespace=NS) - date = parse_date( - findtext(element=el, xpath='startTime', namespace=NS)) - tags = self._get_resource_tags(el) - point = BackupTargetRecoveryPoint( - id=id, - date=date, - target=target, - driver=self.connection.driver, - extra={ - 'snapshot-id': id, - 'tags': tags - }, - ) - return point - - def _to_jobs(self, data): - xpath = 'DescribeSnapshotsResponse/snapshotSet/item' - return [self._to_job(el) - for el in findall(element=data, xpath=xpath, namespace=NS)] - - def _to_job(self, el): - id = findtext(element=el, xpath='snapshotId', namespace=NS) - progress = findtext(element=el, xpath='progress', namespace=NS)\ - .replace('%', '') - volume_id = findtext(element=el, xpath='volumeId', namespace=NS) - target = self.ex_get_target_by_volume_id(volume_id) - job = BackupTargetJob( - id=id, - status=BackupTargetJobStatusType.PENDING, - progress=int(progress), - target=target, - driver=self.connection.driver, - extra={ - }, - ) - return job - - def ex_get_target_by_volume_id(self, volume_id): - return BackupTarget( - id=volume_id, - name=volume_id, - address=volume_id, - type=BackupTargetType.VOLUME, - driver=self.connection.driver, - extra={ - "volume-id": volume_id - } - ) - - def _get_resource_tags(self, element): - """ - Parse tags from the provided element and return a dictionary with - key/value pairs. - - :rtype: ``dict`` - """ - tags = {} - - # Get our tag set by parsing the element - tag_set = findall(element=element, - xpath='tagSet/item', - namespace=NS) - - for tag in tag_set: - key = findtext(element=tag, - xpath='key', - namespace=NS) - - value = findtext(element=tag, - xpath='value', - namespace=NS) - - tags[key] = value - - return tags http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/gce.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/gce.py b/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/gce.py deleted file mode 100644 index 151f734..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/drivers/gce.py +++ /dev/null @@ -1,478 +0,0 @@ - - -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -__all__ = [ - 'GCEBackupDriver' -] - -from libcloud.utils.iso8601 import parse_date -from libcloud.backup.base import BackupDriver, BackupTargetRecoveryPoint,\ - BackupTargetJob, BackupTarget -from libcloud.backup.types import BackupTargetType, BackupTargetJobStatusType - -from libcloud.common.google import GoogleResponse, GoogleBaseConnection - -API_VERSION = 'v1' -DEFAULT_TASK_COMPLETION_TIMEOUT = 180 - - -class GCEResponse(GoogleResponse): - pass - - -class GCEConnection(GoogleBaseConnection): - """ - Connection class for the GCE driver. - - GCEConnection extends :class:`google.GoogleBaseConnection` for 2 reasons: - 1. modify request_path for GCE URI. - 2. Implement gce_params functionality described below. - - If the parameter gce_params is set to a dict prior to calling request(), - the URL parameters will be updated to include those key/values FOR A - SINGLE REQUEST. If the response contains a nextPageToken, - gce_params['pageToken'] will be set to its value. This can be used to - implement paging in list: - - >>> params, more_results = {'maxResults': 2}, True - >>> while more_results: - ... driver.connection.gce_params=params - ... driver.ex_list_urlmaps() - ... more_results = 'pageToken' in params - ... - [<GCEUrlMap id="..." name="cli-map">, <GCEUrlMap id="..." name="lc-map">] - [<GCEUrlMap id="..." name="web-map">] - """ - host = 'www.googleapis.com' - responseCls = GCEResponse - - def __init__(self, user_id, key, secure, auth_type=None, - credential_file=None, project=None, **kwargs): - super(GCEConnection, self).__init__(user_id, key, secure=secure, - auth_type=auth_type, - credential_file=credential_file, - **kwargs) - self.request_path = '/compute/%s/projects/%s' % (API_VERSION, - project) - self.gce_params = None - - def pre_connect_hook(self, params, headers): - """ - Update URL parameters with values from self.gce_params. - - @inherits: :class:`GoogleBaseConnection.pre_connect_hook` - """ - params, headers = super(GCEConnection, self).pre_connect_hook(params, - headers) - if self.gce_params: - params.update(self.gce_params) - return params, headers - - def request(self, *args, **kwargs): - """ - Perform request then do GCE-specific processing of URL params. - - @inherits: :class:`GoogleBaseConnection.request` - """ - response = super(GCEConnection, self).request(*args, **kwargs) - - # If gce_params has been set, then update the pageToken with the - # nextPageToken so it can be used in the next request. - if self.gce_params: - if 'nextPageToken' in response.object: - self.gce_params['pageToken'] = response.object['nextPageToken'] - elif 'pageToken' in self.gce_params: - del self.gce_params['pageToken'] - self.gce_params = None - - return response - - -class GCEBackupDriver(BackupDriver): - name = 'Google Compute Engine Backup Driver' - website = 'http://cloud.google.com/' - connectionCls = GCEConnection - - def __init__(self, user_id, key=None, project=None, - auth_type=None, scopes=None, credential_file=None, **kwargs): - """ - :param user_id: The email address (for service accounts) or Client ID - (for installed apps) to be used for authentication. - :type user_id: ``str`` - - :param key: The RSA Key (for service accounts) or file path containing - key or Client Secret (for installed apps) to be used for - authentication. - :type key: ``str`` - - :keyword project: Your GCE project name. (required) - :type project: ``str`` - - :keyword auth_type: Accepted values are "SA" or "IA" or "GCE" - ("Service Account" or "Installed Application" or - "GCE" if libcloud is being used on a GCE instance - with service account enabled). - If not supplied, auth_type will be guessed based - on value of user_id or if the code is being - executed in a GCE instance. - :type auth_type: ``str`` - - :keyword scopes: List of authorization URLs. Default is empty and - grants read/write to Compute, Storage, DNS. - :type scopes: ``list`` - - :keyword credential_file: Path to file for caching authentication - information used by GCEConnection. - :type credential_file: ``str`` - """ - if not project: - raise ValueError('Project name must be specified using ' - '"project" keyword.') - - self.auth_type = auth_type - self.project = project - self.scopes = scopes - self.credential_file = credential_file or \ - '~/.gce_libcloud_auth' + '.' + self.project - - super(GCEBackupDriver, self).__init__(user_id, key, **kwargs) - - # Cache Zone and Region information to reduce API calls and - # increase speed - self.base_path = '/compute/%s/projects/%s' % (API_VERSION, - self.project) - - def get_supported_target_types(self): - """ - Get a list of backup target types this driver supports - - :return: ``list`` of :class:``BackupTargetType`` - """ - return [BackupTargetType.VOLUME] - - def list_targets(self): - """ - List all backuptargets - - :rtype: ``list`` of :class:`BackupTarget` - """ - raise NotImplementedError( - 'list_targets not implemented for this driver') - - def create_target(self, name, address, - type=BackupTargetType.VOLUME, extra=None): - """ - Creates a new backup target - - :param name: Name of the target - :type name: ``str`` - - :param address: The volume ID. - :type address: ``str`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Does nothing since any volume can be snapped at anytime. - return self.ex_get_target_by_source(address) - - def create_target_from_node(self, node, type=BackupTargetType.VIRTUAL, - extra=None): - """ - Creates a new backup target from an existing node - - :param node: The Node to backup - :type node: ``Node`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Get the first persistent disk - disks = node.extra['disks'] - if disks is not None: - return self.create_target( - name=node.name, - address=disks[0]['source'], - type=BackupTargetType.VOLUME, - extra=None) - else: - raise RuntimeError("Node does not have any block devices") - - def create_target_from_container(self, container, - type=BackupTargetType.OBJECT, - extra=None): - """ - Creates a new backup target from an existing storage container - - :param node: The Container to backup - :type node: ``Container`` - - :param type: Backup target type (Physical, Virtual, ...). - :type type: :class:`BackupTargetType` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - raise NotImplementedError( - 'create_target_from_container not implemented for this driver') - - def update_target(self, target, name, address, extra): - """ - Update the properties of a backup target - - :param target: Backup target to update - :type target: Instance of :class:`BackupTarget` - - :param name: Name of the target - :type name: ``str`` - - :param address: Hostname, FQDN, IP, file path etc. - :type address: ``str`` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTarget` - """ - # Does nothing since any volume can be snapped at anytime. - return self.ex_get_target_by_source(address) - - def delete_target(self, target): - """ - Delete a backup target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - """ - raise NotImplementedError( - 'delete_target not implemented for this driver') - - def list_recovery_points(self, target, start_date=None, end_date=None): - """ - List the recovery points available for a target - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param start_date: The start date to show jobs between (optional) - :type start_date: :class:`datetime.datetime` - - :param end_date: The end date to show jobs between (optional) - :type end_date: :class:`datetime.datetime`` - - :rtype: ``list`` of :class:`BackupTargetRecoveryPoint` - """ - request = '/global/snapshots' - response = self.connection.request(request, method='GET').object - return self._to_recovery_points(response, target) - - def recover_target(self, target, recovery_point, path=None): - """ - Recover a backup target to a recovery point - - :param target: Backup target to delete - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'recover_target not implemented for this driver') - - def recover_target_out_of_place(self, target, recovery_point, - recovery_target, path=None): - """ - Recover a backup target to a recovery point out-of-place - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param recovery_point: Backup target with the backup data - :type recovery_point: Instance of :class:`BackupTarget` - - :param recovery_target: Backup target with to recover the data to - :type recovery_target: Instance of :class:`BackupTarget` - - :param path: The part of the recovery point to recover (optional) - :type path: ``str`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - raise NotImplementedError( - 'recover_target_out_of_place not implemented for this driver') - - def get_target_job(self, target, id): - """ - Get a specific backup job by ID - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param id: Backup target with the backup data - :type id: Instance of :class:`BackupTarget` - - :rtype: :class:`BackupTargetJob` - """ - jobs = self.list_target_jobs(target) - return list(filter(lambda x: x.id == id, jobs))[0] - - def list_target_jobs(self, target): - """ - List the backup jobs on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :rtype: ``list`` of :class:`BackupTargetJob` - """ - return [] - - def create_target_job(self, target, extra=None): - """ - Create a new backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param extra: (optional) Extra attributes (driver specific). - :type extra: ``dict`` - - :rtype: Instance of :class:`BackupTargetJob` - """ - name = target.name - request = '/zones/%s/disks/%s/createSnapshot' % ( - target.extra['zone'].name, target.name) - snapshot_data = { - 'source': target.extra['source'] - } - self.connection.async_request(request, method='POST', - data=snapshot_data) - return self._to_job(self.ex_get_snapshot(name), target) - - def resume_target_job(self, target, job): - """ - Resume a suspended backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param job: Backup target job to resume - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'resume_target_job not supported for this driver') - - def suspend_target_job(self, target, job): - """ - Suspend a running backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param job: Backup target job to suspend - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'suspend_target_job not supported for this driver') - - def cancel_target_job(self, target, job): - """ - Cancel a backup job on a target - - :param target: Backup target with the backup data - :type target: Instance of :class:`BackupTarget` - - :param job: Backup target job to cancel - :type job: Instance of :class:`BackupTargetJob` - - :rtype: ``bool`` - """ - raise NotImplementedError( - 'cancel_target_job not supported for this driver') - - def _to_recovery_points(self, data, target): - return [self._to_recovery_point(item, target) - for item in data.items] - - def _to_recovery_point(self, item, target): - id = item.id - date = parse_date(item.creationTimestamp) - point = BackupTargetRecoveryPoint( - id=id, - date=date, - target=target, - driver=self.connection.driver, - extra={ - 'snapshot-id': id, - }, - ) - return point - - def _to_jobs(self, data, target): - return [self._to_job(item, target) - for item in data.items] - - def _to_job(self, item, target): - id = item.id - job = BackupTargetJob( - id=id, - status=BackupTargetJobStatusType.PENDING, - progress=0, - target=target, - driver=self.connection.driver, - extra={ - }, - ) - return job - - def ex_get_snapshot(self, name): - request = '/global/snapshots/%s' % (name) - response = self.connection.request(request, method='GET').object - return response - - def ex_get_target_by_source(self, source): - return BackupTarget( - id=source, - name=source, - address=source, - type=BackupTargetType.VOLUME, - driver=self.connection.driver, - extra={ - "source": source - } - ) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/providers.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/providers.py b/apache-libcloud-1.0.0rc2/libcloud/backup/providers.py deleted file mode 100644 index 16cd610..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/providers.py +++ /dev/null @@ -1,38 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from libcloud.backup.types import Provider -from libcloud.common.providers import get_driver as _get_provider_driver -from libcloud.common.providers import set_driver as _set_provider_driver - -DRIVERS = { - Provider.DUMMY: - ('libcloud.backup.drivers.dummy', 'DummyBackupDriver'), - Provider.EBS: - ('libcloud.backup.drivers.ebs', 'EBSBackupDriver'), - Provider.GCE: - ('libcloud.backup.drivers.gce', 'GCEBackupDriver'), - Provider.DIMENSIONDATA: - ('libcloud.backup.drivers.dimensiondata', 'DimensionDataBackupDriver') -} - - -def get_driver(provider): - return _get_provider_driver(drivers=DRIVERS, provider=provider) - - -def set_driver(provider, module, klass): - return _set_provider_driver(drivers=DRIVERS, provider=provider, - module=module, klass=klass) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/backup/types.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/backup/types.py b/apache-libcloud-1.0.0rc2/libcloud/backup/types.py deleted file mode 100644 index 0264268..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/backup/types.py +++ /dev/null @@ -1,63 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -__all__ = [ - 'Provider', - 'BackupTargetType', - 'BackupTargetJobStatusType' -] - - -class Provider(object): - DUMMY = 'dummy' - EBS = 'ebs' - GCE = 'gce' - DIMENSIONDATA = 'dimensiondata' - - -class BackupTargetType(object): - """ - Backup Target type. - """ - - VIRTUAL = 'Virtual' - """ Denotes a virtual host """ - - PHYSICAL = 'Physical' - """ Denotes a physical host """ - - FILESYSTEM = 'Filesystem' - """ Denotes a file system (e.g. NAS) """ - - DATABASE = 'Database' - """ Denotes a database target """ - - OBJECT = 'Object' - """ Denotes an object based file system """ - - VOLUME = 'Volume' - """ Denotes a block storage volume """ - - -class BackupTargetJobStatusType(object): - """ - The status of a backup target job - """ - - RUNNING = 'Running' - CANCELLED = 'Cancelled' - FAILED = 'Failed' - COMPLETED = 'Completed' - PENDING = 'Pending' http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/common/__init__.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/common/__init__.py b/apache-libcloud-1.0.0rc2/libcloud/common/__init__.py deleted file mode 100644 index e69de29..0000000 http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/common/abiquo.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/common/abiquo.py b/apache-libcloud-1.0.0rc2/libcloud/common/abiquo.py deleted file mode 100644 index a972243..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/common/abiquo.py +++ /dev/null @@ -1,274 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Abiquo Utilities Module for the Abiquo Driver. - -Common utilities needed by the :class:`AbiquoNodeDriver`. -""" -import base64 - -from libcloud.common.base import ConnectionUserAndKey, PollingConnection -from libcloud.common.base import XmlResponse -from libcloud.common.types import InvalidCredsError, LibcloudError -from libcloud.utils.py3 import httplib -from libcloud.utils.py3 import urlparse -from libcloud.utils.py3 import b -from libcloud.compute.base import NodeState - - -def get_href(element, rel): - """ - Search a RESTLink element in the :class:`AbiquoResponse`. - - Abiquo, as a REST API, it offers self-discovering functionality. - That means that you could walk through the whole API only - navigating from the links offered by the entities. - - This is a basic method to find the 'relations' of an entity searching into - its links. - - For instance, a Rack entity serialized as XML as the following:: - - <?xml version="1.0" encoding="UTF-8" standalone="yes"?> - <rack> - <link href="http://host/api/admin/datacenters/1" - type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/> - <link href="http://host/api/admin/datacenters/1/racks/1" - type="application/vnd.abiquo.rack+xml" rel="edit"/> - <link href="http://host/api/admin/datacenters/1/racks/1/machines" - type="application/vnd.abiquo.machines+xml" rel="machines"/> - <haEnabled>false</haEnabled> - <id>1</id> - <longDescription></longDescription> - <name>racacaca</name> - <nrsq>10</nrsq> - <shortDescription></shortDescription> - <vlanIdMax>4094</vlanIdMax> - <vlanIdMin>2</vlanIdMin> - <vlanPerVdcReserved>1</vlanPerVdcReserved> - <vlansIdAvoided></vlansIdAvoided> - </rack> - - offers link to datacenters (rel='datacenter'), to itself (rel='edit') and - to the machines defined in it (rel='machines') - - A call to this method with the 'rack' element using 'datacenter' as 'rel' - will return: - - 'http://10.60.12.7:80/api/admin/datacenters/1' - - :type element: :class:`xml.etree.ElementTree` - :param element: Xml Entity returned by Abiquo API (required) - :type rel: ``str`` - :param rel: relation link name - :rtype: ``str`` - :return: the 'href' value according to the 'rel' input parameter - """ - links = element.findall('link') - for link in links: - if link.attrib['rel'] == rel: - href = link.attrib['href'] - # href is something like: - # - # 'http://localhost:80/api/admin/enterprises' - # - # we are only interested in '/admin/enterprises/' part - needle = '/api/' - url_path = urlparse.urlparse(href).path - index = url_path.find(needle) - result = url_path[index + len(needle) - 1:] - return result - - -class AbiquoResponse(XmlResponse): - """ - Abiquo XML Response. - - Wraps the response in XML bodies or extract the error data in - case of error. - """ - - # Map between abiquo state and Libcloud State - NODE_STATE_MAP = { - 'NOT_ALLOCATED': NodeState.TERMINATED, - 'ALLOCATED': NodeState.PENDING, - 'CONFIGURED': NodeState.PENDING, - 'ON': NodeState.RUNNING, - 'PAUSED': NodeState.PENDING, - 'OFF': NodeState.PENDING, - 'LOCKED': NodeState.PENDING, - 'UNKNOWN': NodeState.UNKNOWN - } - - def parse_error(self): - """ - Parse the error messages. - - Response body can easily be handled by this class parent - :class:`XmlResponse`, but there are use cases which Abiquo API - does not respond an XML but an HTML. So we need to - handle these special cases. - """ - if self.status == httplib.UNAUTHORIZED: - raise InvalidCredsError(driver=self.connection.driver) - elif self.status == httplib.FORBIDDEN: - raise ForbiddenError(self.connection.driver) - elif self.status == httplib.NOT_ACCEPTABLE: - raise LibcloudError('Not Acceptable') - else: - parsebody = self.parse_body() - if parsebody is not None and hasattr(parsebody, 'findall'): - errors = self.parse_body().findall('error') - # Most of the exceptions only have one error - raise LibcloudError(errors[0].findtext('message')) - else: - raise LibcloudError(self.body) - - def success(self): - """ - Determine if the request was successful. - - Any of the 2XX HTTP response codes are accepted as successful requests - - :rtype: ``bool`` - :return: successful request or not. - """ - return self.status in [httplib.OK, httplib.CREATED, httplib.NO_CONTENT, - httplib.ACCEPTED] - - def async_success(self): - """ - Determinate if async request was successful. - - An async_request retrieves for a task object that can be successfully - retrieved (self.status == OK), but the asynchronous task (the body of - the HTTP response) which we are asking for has finished with an error. - So this method checks if the status code is 'OK' and if the task - has finished successfully. - - :rtype: ``bool`` - :return: successful asynchronous request or not - """ - if self.success(): - # So we have a 'task' object in the body - task = self.parse_body() - return task.findtext('state') == 'FINISHED_SUCCESSFULLY' - else: - return False - - -class AbiquoConnection(ConnectionUserAndKey, PollingConnection): - """ - A Connection to Abiquo API. - - Basic :class:`ConnectionUserAndKey` connection with - :class:`PollingConnection` features for asynchronous tasks. - """ - - responseCls = AbiquoResponse - - def __init__(self, user_id, key, secure=True, host=None, port=None, - url=None, timeout=None, - retry_delay=None, backoff=None, proxy_url=None): - super(AbiquoConnection, self).__init__(user_id=user_id, key=key, - secure=secure, - host=host, port=port, - url=url, timeout=timeout, - retry_delay=retry_delay, - backoff=backoff, - proxy_url=proxy_url) - - # This attribute stores data cached across multiple request - self.cache = {} - - def add_default_headers(self, headers): - """ - Add Basic Authentication header to all the requests. - - It injects the 'Authorization: Basic Base64String===' header - in each request - - :type headers: ``dict`` - :param headers: Default input headers - - :rtype: ``dict`` - :return: Default input headers with the 'Authorization' - header - """ - b64string = b('%s:%s' % (self.user_id, self.key)) - encoded = base64.b64encode(b64string).decode('utf-8') - - authorization = 'Basic ' + encoded - - headers['Authorization'] = authorization - return headers - - def get_poll_request_kwargs(self, response, context, request_kwargs): - """ - Manage polling request arguments. - - Return keyword arguments which are passed to the - :class:`NodeDriver.request` method when polling for the job status. The - Abiquo Asynchronous Response returns and 'acceptedrequest' XmlElement - as the following:: - - <acceptedrequest> - <link href="http://uri/to/task" rel="status"/> - <message>You can follow the progress in the link</message> - </acceptedrequest> - - We need to extract the href URI to poll. - - :type response: :class:`xml.etree.ElementTree` - :keyword response: Object returned by poll request. - :type request_kwargs: ``dict`` - :keyword request_kwargs: Default request arguments and headers - :rtype: ``dict`` - :return: Modified keyword arguments - """ - accepted_request_obj = response.object - link_poll = get_href(accepted_request_obj, 'status') - hdr_poll = {'Accept': 'application/vnd.abiquo.task+xml'} - - # Override the 'action', 'method' and 'headers' - # keys of the previous dict - request_kwargs['action'] = link_poll - request_kwargs['method'] = 'GET' - request_kwargs['headers'] = hdr_poll - return request_kwargs - - def has_completed(self, response): - """ - Decide if the asynchronous job has ended. - - :type response: :class:`xml.etree.ElementTree` - :param response: Response object returned by poll request - :rtype: ``bool`` - :return: Whether the job has completed - """ - task = response.object - task_state = task.findtext('state') - return task_state in ['FINISHED_SUCCESSFULLY', 'ABORTED', - 'FINISHED_UNSUCCESSFULLY'] - - -class ForbiddenError(LibcloudError): - """ - Exception used when credentials are ok but user has not permissions. - """ - - def __init__(self, driver): - message = 'User has not permission to perform this task.' - super(LibcloudError, self).__init__(message, driver) http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/common/aliyun.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/common/aliyun.py b/apache-libcloud-1.0.0rc2/libcloud/common/aliyun.py deleted file mode 100644 index 4e91dbb..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/common/aliyun.py +++ /dev/null @@ -1,239 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import base64 -import hashlib -import hmac -import sys -import time -import uuid - -try: - from lxml import etree as ET -except ImportError: - from xml.etree import ElementTree as ET - -from libcloud.common.base import ConnectionUserAndKey, XmlResponse -from libcloud.common.types import MalformedResponseError -from libcloud.utils.py3 import b, u, urlquote, PY3 -from libcloud.utils.xml import findtext - -__all__ = [ - 'AliyunXmlResponse', - 'AliyunRequestSigner', - 'AliyunRequestSignerAlgorithmV1_0', - 'SignedAliyunConnection', - 'AliyunConnection', - - 'SIGNATURE_VERSION_1_0', - 'DEFAULT_SIGNATURE_VERSION' -] - -SIGNATURE_VERSION_1_0 = '1.0' -DEFAULT_SIGNATURE_VERSION = SIGNATURE_VERSION_1_0 - - -class AliyunXmlResponse(XmlResponse): - namespace = None - - def success(self): - return self.status >= 200 and self.status < 300 - - def parse_body(self): - """ - Each response from Aliyun contains a request id and a host id. - The response body is in utf-8 encoding. - """ - if len(self.body) == 0 and not self.parse_zero_length_body: - return self.body - - try: - if PY3: - parser = ET.XMLParser(encoding='utf-8') - body = ET.XML(self.body.encode('utf-8'), parser=parser) - else: - body = ET.XML(self.body) - except: - raise MalformedResponseError('Failed to parse XML', - body=self.body, - driver=self.connection.driver) - self.request_id = findtext(element=body, xpath='RequestId', - namespace=self.namespace) - self.host_id = findtext(element=body, xpath='HostId', - namespace=self.namespace) - return body - - def parse_error(self): - """ - Parse error responses from Aliyun. - """ - body = super(AliyunXmlResponse, self).parse_error() - code, message = self._parse_error_details(element=body) - request_id = findtext(element=body, xpath='RequestId', - namespace=self.namespace) - host_id = findtext(element=body, xpath='HostId', - namespace=self.namespace) - error = {'code': code, - 'message': message, - 'request_id': request_id, - 'host_id': host_id} - return u(error) - - def _parse_error_details(self, element): - """ - Parse error code and message from the provided error element. - - :return: ``tuple`` with two elements: (code, message) - :rtype: ``tuple`` - """ - code = findtext(element=element, xpath='Code', - namespace=self.namespace) - message = findtext(element=element, xpath='Message', - namespace=self.namespace) - - return (code, message) - - -class AliyunRequestSigner(object): - """ - Class handles signing the outgoing Aliyun requests. - """ - - def __init__(self, access_key, access_secret, version): - """ - :param access_key: Access key. - :type access_key: ``str`` - - :param access_secret: Access secret. - :type access_secret: ``str`` - - :param version: API version. - :type version: ``str`` - """ - self.access_key = access_key - self.access_secret = access_secret - self.version = version - - def get_request_params(self, params, method='GET', path='/'): - return params - - def get_request_headers(self, params, headers, method='GET', path='/'): - return params, headers - - -class AliyunRequestSignerAlgorithmV1_0(AliyunRequestSigner): - """Aliyun request signer using signature version 1.0.""" - def get_request_params(self, params, method='GET', path='/'): - params['Format'] = 'XML' - params['Version'] = self.version - params['AccessKeyId'] = self.access_key - params['SignatureMethod'] = 'HMAC-SHA1' - params['SignatureVersion'] = SIGNATURE_VERSION_1_0 - params['SignatureNonce'] = _get_signature_nonce() - # TODO: Support 'ResourceOwnerAccount' - params['Timestamp'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', - time.gmtime()) - params['Signature'] = self._sign_request(params, method, path) - return params - - def _sign_request(self, params, method, path): - """ - Sign Aliyun requests parameters and get the signature. - - StringToSign = HTTPMethod + '&' + - percentEncode('/') + '&' + - percentEncode(CanonicalizedQueryString) - """ - keys = list(params.keys()) - keys.sort() - pairs = [] - for key in keys: - pairs.append('%s=%s' % (_percent_encode(key), - _percent_encode(params[key]))) - qs = urlquote('&'.join(pairs), safe='-_.~') - string_to_sign = '&'.join((method, urlquote(path, safe=''), qs)) - b64_hmac = base64.b64encode( - hmac.new(b(self._get_access_secret()), b(string_to_sign), - digestmod=hashlib.sha1).digest() - ) - - return b64_hmac.decode('utf8') - - def _get_access_secret(self): - return '%s&' % self.access_secret - - -class AliyunConnection(ConnectionUserAndKey): - pass - - -class SignedAliyunConnection(AliyunConnection): - def __init__(self, user_id, key, secure=True, host=None, port=None, - url=None, timeout=None, proxy_url=None, retry_delay=None, - backoff=None, signature_version=DEFAULT_SIGNATURE_VERSION): - super(SignedAliyunConnection, self).__init__(user_id=user_id, key=key, - secure=secure, - host=host, port=port, - url=url, timeout=timeout, - proxy_url=proxy_url, - retry_delay=retry_delay, - backoff=backoff) - self.signature_version = str(signature_version) - - if self.signature_version == '1.0': - signer_cls = AliyunRequestSignerAlgorithmV1_0 - else: - raise ValueError('Unsupported signature_version: %s' % - signature_version) - - self.signer = signer_cls(access_key=self.user_id, - access_secret=self.key, - version=self.version) - - def add_default_params(self, params): - params = self.signer.get_request_params(params=params, - method=self.method, - path=self.action) - return params - - -def _percent_encode(encode_str): - """ - Encode string to utf8, quote for url and replace '+' with %20, - '*' with %2A and keep '~' not converted. - - :param src_str: ``str`` in the same encoding with sys.stdin, - default to encoding cp936. - :return: ``str`` represents the encoded result - :rtype: ``str`` - """ - encoding = sys.stdin.encoding or 'cp936' - decoded = str(encode_str) - if PY3: - if isinstance(encode_str, bytes): - decoded = encode_str.decode(encoding) - else: - decoded = str(encode_str).decode(encoding) - - res = urlquote( - decoded.encode('utf8'), '') - res = res.replace('+', '%20') - res = res.replace('*', '%2A') - res = res.replace('%7E', '~') - return res - - -def _get_signature_nonce(): - return str(uuid.uuid4())
