DimensionData: Backups adding more tests, moving classes to common
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/67f7e06f Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/67f7e06f Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/67f7e06f Branch: refs/heads/trunk Commit: 67f7e06fad55660be8d67c377f18167cce516803 Parents: bb8ab66 Author: Jeffrey Dunham <jeffrey.a.dun...@gmail.com> Authored: Tue Feb 9 18:05:34 2016 -0500 Committer: anthony-shaw <anthony.p.s...@gmail.com> Committed: Wed Feb 10 12:08:06 2016 +1100 ---------------------------------------------------------------------- libcloud/backup/drivers/dimensiondata.py | 118 ++++------- libcloud/common/dimensiondata.py | 209 +++++++++++++++++++ ..._692f_4314_8725_c8a4f4d13a87_backup_INFO.xml | 27 ++- ...4_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml | 7 + ...4_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml | 2 + ...4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml | 11 + libcloud/test/backup/test_dimensiondata.py | 75 ++++++- 7 files changed, 361 insertions(+), 88 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/backup/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/backup/drivers/dimensiondata.py b/libcloud/backup/drivers/dimensiondata.py index 45fb1d7..41cc9f7 100644 --- a/libcloud/backup/drivers/dimensiondata.py +++ b/libcloud/backup/drivers/dimensiondata.py @@ -22,69 +22,18 @@ from libcloud.backup.base import BackupDriver, BackupTarget from libcloud.backup.types import BackupTargetType from libcloud.backup.types import Provider from libcloud.common.dimensiondata import DimensionDataConnection -from libcloud.common.dimensiondata import API_ENDPOINTS -from libcloud.common.dimensiondata import DEFAULT_REGION +from libcloud.common.dimensiondata import DimensionDataBackupClientType +from libcloud.common.dimensiondata import DimensionDataBackupDetails +from libcloud.common.dimensiondata import DimensionDataBackupClient +from libcloud.common.dimensiondata import DimensionDataBackupClientAlert +from libcloud.common.dimensiondata import DimensionDataBackupClientRunningJob +from libcloud.common.dimensiondata import DimensionDataBackupStoragePolicy +from libcloud.common.dimensiondata import DimensionDataBackupSchedulePolicy +from libcloud.common.dimensiondata import API_ENDPOINTS, DEFAULT_REGION from libcloud.common.dimensiondata import TYPES_URN -from libcloud.common.dimensiondata import GENERAL_NS +from libcloud.common.dimensiondata import GENERAL_NS, BACKUP_NS from libcloud.utils.xml import fixxpath, findtext, findall -BACKUP_NS = 'http://oec.api.opsource.net/schemas/backup' - - -class DimensionDataBackupClientType(object): - def __init__(self, type, is_file_system, description): - self.type = type - self.is_file_system = is_file_system - self.description = description - - -class DimensionDataBackupDetails(object): - def __init__(self, asset_id, service_plan, state, clients=[]): - self.asset_id = asset_id - self.service_plan = service_plan - self.state = state - self.clients = clients - - -class DimensionDataBackupClient(object): - def __init__(self, type, is_file_system, status, description, - schedule_pol, storage_pol, trigger=None, email=None, - last_backup_time=None, next_backup=None, download_url=None, - total_backup_size=None, running_job=None): - self.type = type - self.is_file_system = is_file_system - self.status = status - self.description = description - self.schedule_policy = schedule_pol - self.storage_policy = storage_pol - self.trigger = trigger - self.email = email - self.last_backup_time = last_backup_time - self.next_backup = next_backup - self.total_backup_size = total_backup_size - self.download_url = download_url - self.running_job = running_job - - -class DimensionDataBackupRunningJob(object): - def __init__(self, id, status, percentage=0): - self.id = id - self.percentage = percentage - self.status = status - - -class DimensionDataBackupStoragePolicy(object): - def __init__(self, name, retention_period, secondary_location): - self.name = name - self.retention_period = retention_period - self.secondary_location = secondary_location - - -class DimensionDataBackupSchedulePolicy(object): - def __init__(self, name, description): - self.name = name - self.description = description - class DimensionDataBackupDriver(BackupDriver): """ @@ -579,9 +528,12 @@ class DimensionDataBackupDriver(BackupDriver): 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=element.get('description'), + description=description, is_file_system=bool(element.get('isFileSystem') == 'true') ) @@ -599,26 +551,40 @@ class DimensionDataBackupDriver(BackupDriver): return [self._to_client(el) for el in elements] def _to_client(self, element): - job = element.find(fixxpath('runningJob', BACKUP_NS)) - running_job = None - if job is not None: - running_job = DimensionDataBackupRunningJob( - id=job.get('id'), - status=job.get('status'), - percentage=int(job.get('percentageComplete')) - ) - return DimensionDataBackupClient( - type=element.get('type'), - is_file_system=bool(element.get('isFileSystem') == 'true'), + id=element.get('id'), + type=self._to_client_type(element, ), status=element.get('status'), - description=findtext(element, 'description', BACKUP_NS), - schedule_pol=findtext(element, 'schedulePolicyName', BACKUP_NS), - storage_pol=findtext(element, 'storagePolicyName', BACKUP_NS), + schedule_policy=findtext(element, 'schedulePolicyName', BACKUP_NS), + storage_policy=findtext(element, 'storagePolicyName', BACKUP_NS), download_url=findtext(element, 'downloadUrl', BACKUP_NS), - running_job=running_job + running_job=self._to_running_job(element), + 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_running_job(self, element): + running_job = element.find(fixxpath('runningJob', BACKUP_NS)) + if running_job is not None: + return DimensionDataBackupClientRunningJob( + id=running_job.get('id'), + status=running_job.get('status'), + percentage=int(running_job.get('percentageComplete')) + ) + return None + def _to_targets(self, object): node_elements = object.findall(fixxpath('server', TYPES_URN)) http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/common/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/common/dimensiondata.py b/libcloud/common/dimensiondata.py index 841f790..5ecd89e 100644 --- a/libcloud/common/dimensiondata.py +++ b/libcloud/common/dimensiondata.py @@ -35,6 +35,7 @@ SERVER_NS = NAMESPACE_BASE + "/server" NETWORK_NS = NAMESPACE_BASE + "/network" DIRECTORY_NS = NAMESPACE_BASE + "/directory" GENERAL_NS = NAMESPACE_BASE + "/general" +BACKUP_NS = NAMESPACE_BASE + "/backup" # API 2.0 Namespaces and URNs TYPES_URN = "urn:didata.com:api:cloud:types" @@ -812,3 +813,211 @@ class DimensionDataVirtualListenerCompatibility(object): return (('<DimensionDataVirtualListenerCompatibility: ' 'type=%s, protocol=%s>') % (self.type, self.protocol)) + + +class DimensionDataBackupClientType(object): + """ + A client type object for backups + """ + def __init__(self, type, is_file_system, description): + """ + Initialize an instance of :class:`DimensionDataBackupClientType` + + :param type: The type of client i.e. (FA.Linux, MySQL, ect.) + :type type: ``str`` + + :param is_file_system: The name of the iRule + :type is_file_system: ``bool`` + + :param description: Description of the client + :type description: ``str`` + """ + self.type = type + self.is_file_system = is_file_system + self.description = description + + def __repr__(self): + return (('<DimensionDataBackupClientType: type=%s>') + % (self.type)) + + +class DimensionDataBackupDetails(object): + """ + Dimension Data Backup Details represents information about + a targets backups configuration + """ + + def __init__(self, asset_id, service_plan, state, clients=None): + """ + Initialize an instance of :class:`DimensionDataBackupDetails` + + :param asset_id: Asset identification for backups + :type asset_id: ``str`` + + :param service_plan: The service plan for backups. i.e (Essentials) + :type service_plan: ``str`` + + :param state: The overall state this backup target. i.e. (unregistered) + :type state: ``str`` + + :param clients: Backup clients attached to this target + :type clients: ``list`` of :class:`DimensionDataBackupClient` + """ + self.asset_id = asset_id + self.service_plan = service_plan + self.state = state + self.clients = clients + + def __repr__(self): + return (('<DimensionDataBackupDetails: id=%s>') + % (self.asset_id)) + + +class DimensionDataBackupClient(object): + """ + An object that represents a backup client + """ + def __init__(self, id, type, status, + schedule_policy, storage_policy, download_url, + alert=None, running_job=None): + """ + Initialize an instance of :class:`DimensionDataBackupClient` + + :param id: Unique ID for the client + :type id: ``str`` + + :param type: The type of client that this client is + :type type: :class:`DimensionDataBackupClientType` + + :param status: The states of this particular backup client. + i.e. (Unregistered) + :type status: ``str`` + + :param schedule_policy: The schedule policy for this client + NOTE: Dimension Data only sends back the name + of the schedule policy, no further details + :type schedule_policy: ``str`` + + :param storage_policy: The storage policy for this client + NOTE: Dimension Data only sends back the name + of the storage policy, no further details + :type storage_policy: ``str`` + + :param download_url: The download url for this client + :type download_url: ``str`` + + :param alert: The alert configured for this backup client (optional) + :type alert: :class:`DimensionDataBackupClientAlert` + + :param alert: The running job for the client (optional) + :type alert: :class:`DimensionDataBackupClientRunningJob` + """ + self.id = id + self.type = type + self.status = status + self.schedule_policy = schedule_policy + self.storage_policy = storage_policy + self.download_url = download_url + self.alert = alert + self.running_job = running_job + + def __repr__(self): + return (('<DimensionDataBackupClient: id=%s>') + % (self.asset_id)) + + +class DimensionDataBackupClientAlert(object): + """ + An alert for a backup client + """ + def __init__(self, trigger, notify_list=[]): + """ + Initialize an instance of :class:`DimensionDataBackupClientAlert` + + :param trigger: Trigger type for the client i.e. ON_FAILURE + :type trigger: ``str`` + + :param notify_list: List of email addresses that are notified + when the alert is fired + :type notify_list: ``list`` of ``str`` + """ + self.trigger = trigger + self.notify_list = notify_list + + def __repr__(self): + return (('<DimensionDataBackupClient: id=%s>') + % (self.asset_id)) + + +class DimensionDataBackupClientRunningJob(object): + """ + A running job for a given backup client + """ + def __init__(self, id, status, percentage=0): + """ + Initialize an instance of :class:`DimensionDataBackupClientRunningJob` + + :param id: The unqiue ID of the job + :type id: ``str`` + + :param status: The status of the job i.e. Waiting + :type status: ``str`` + + :param percentage: The percentage completion of the job + :type percentage: ``int`` + """ + self.id = id + self.percentage = percentage + self.status = status + + def __repr__(self): + return (('<DimensionDataBackupClientRunningJob: id=%s>') + % (self.id)) + + +class DimensionDataBackupStoragePolicy(object): + """ + A representation of a storage policy + """ + def __init__(self, name, retention_period, secondary_location): + """ + Initialize an instance of :class:`DimensionDataBackupStoragePolicy` + + :param name: The name of the storage policy i.e. 14 Day Storage Policy + :type name: ``str`` + + :param retention_period: How long to keep the backup in days + :type retention_period: ``int`` + + :param secondary_location: The secondary location i.e. Primary + :type secondary_location: ``str`` + """ + self.name = name + self.retention_period = retention_period + self.secondary_location = secondary_location + + def __repr__(self): + return (('<DimensionDataBackupClientStoragePolicy: name=%s>') + % (self.name)) + + +class DimensionDataBackupSchedulePolicy(object): + """ + A representation of a schedule policy + """ + def __init__(self, name, description): + """ + Initialize an instance of :class:`DimensionDataBackupSchedulePolicy` + + :param name: The name of the policy i.e 12AM - 6AM + :type name: ``str`` + + :param description: Short summary of the details of the policy + :type description: ``str`` + """ + self.name = name + self.description = description + + def __repr__(self): + return (('<DimensionDataBackupClientSchedulePolicy: name=%s>') + % (self.name)) http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO.xml b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO.xml index 8b5cf55..fc61cce 100644 --- a/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO.xml +++ b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO.xml @@ -1,11 +1,16 @@ -<ns5:BackupDetails assetId="fbf90c74-a6de-459e-942c-b75b5176ed72" servicePlan="Enterprise" state="NORMAL" xmlns:ns16="http://oec.api.opsource.net/schemas/serverbootstrap" xmlns="http://oec.api.opsource.net/schemas/server" xmlns:ns14="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns15="http://oec.api.opsource.net/schemas/reset" xmlns:ns9="http://oec.api.opsource.net/schemas/storage" xmlns:ns5="http://oec.api.opsource.net/schemas/backup" xmlns:ns12="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns13="http://oec.api.opsource.net/schemas/general" xmlns:ns6="http://oec.api.opsource.net/schemas/support" xmlns:ns7="http://oec.api.opsource.net/schemas/organization" xmlns:ns10="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns8="http://oec.api.opsource.net/schemas/multigeo" xmlns:ns11="http://oec.api.opsource.net/schemas/vip" xmlns:ns2="http://oec.api.opsource.net/schemas/network" xmlns:ns4="http://oec.api.opsource.net/schemas/directory" xmlns:ns3="http://oec.api.ops ource.net/schemas/admin"> - <ns5:backupClient id="5fe7502e-f8d7-4547-93b5-f54ac6e58281" type="FA.Linux" isFileSystem="true" status="Offline"> - <ns5:description>Linux File Agent</ns5:description> - <ns5:schedulePolicyName>12AM - 6AM</ns5:schedulePolicyName> - <ns5:storagePolicyName>30 Day Storage Policy + Secondary Copy</ns5:storagePolicyName> - <ns5:times nextBackup="2016-02-09T00:00:00" lastOnline="2016-02-08T06:10:25"/> - <ns5:totalBackupSizeGb>0</ns5:totalBackupSizeGb> - <ns5:downloadUrl>https://backups-na.cloud-vpn.net/PCS/BackupClientInstallerDownload/27645708a713cf406b47ccf73895cc8d27d4172c</ns5:downloadUrl> - <ns5:runningJob id="106130" name="Backup" percentageComplete="5" status="Waiting"/> - </ns5:backupClient> -</ns5:BackupDetails> +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<ns9:BackupDetails assetId="12769311-938c-4669-9460-7723eb194269" servicePlan="Enterprise" state="NORMAL" xmlns:ns16="http://oec.api.opsource.net/schemas/storage" xmlns="http://oec.api.opsource.net/schemas/admin" xmlns:ns14="http://oec.api.opsource.net/schemas/directory" xmlns:ns15="http://oec.api.opsource.net/schemas/multigeo" xmlns:ns9="http://oec.api.opsource.net/schemas/backup" xmlns:ns5="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns12="http://oec.api.opsource.net/schemas/support" xmlns:ns13="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns6="http://oec.api.opsource.net/schemas/general" xmlns:ns7="http://oec.api.opsource.net/schemas/reset" xmlns:ns10="http://oec.api.opsource.net/schemas/server" xmlns:ns8="http://oec.api.opsource.net/schemas/network" xmlns:ns11="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns2="http://oec.api.opsource.net/schemas/organization" xmlns:ns4="http://oec.api.opsource.net/schemas/serverbootstrap" xmlns:ns3="http://oec.api.o psource.net/schemas/vip"> + <ns9:backupClient id="30b1ff76-c76d-4d7c-b39d-3b72be0384c8" type="FA.Linux" isFileSystem="true" status="Unregistered"> + <ns9:description>Linux File Agent</ns9:description> + <ns9:schedulePolicyName>12AM - 6AM</ns9:schedulePolicyName> + <ns9:storagePolicyName>14 Day Storage Policy</ns9:storagePolicyName> + <ns9:alerting trigger="ON_FAILURE"> + <ns9:emailAddress>fake_em...@example.com</ns9:emailAddress> + <ns9:emailAddress>fake_ema...@example.com</ns9:emailAddress> + </ns9:alerting> + <ns9:times nextBackup="2016-02-09T00:00:00" lastOnline="2016-02-08T06:10:25"/> + <ns9:totalBackupSizeGb>0</ns9:totalBackupSizeGb> + <ns9:downloadUrl>https://backups-na.cloud-vpn.net/PCS/BackupClientInstallerDownload/cbb8a8c607ca4144e8828814edfc1634c8dd8782</ns9:downloadUrl> + <ns9:runningJob id="106130" name="Backup" percentageComplete="5" status="Waiting"/> + </ns9:backupClient> +</ns9:BackupDetails> http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml new file mode 100644 index 0000000..c3a9c37 --- /dev/null +++ b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<ns6:Status xmlns:ns16="http://oec.api.opsource.net/schemas/storage" xmlns="http://oec.api.opsource.net/schemas/admin" xmlns:ns14="http://oec.api.opsource.net/schemas/directory" xmlns:ns15="http://oec.api.opsource.net/schemas/multigeo" xmlns:ns9="http://oec.api.opsource.net/schemas/backup" xmlns:ns5="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns12="http://oec.api.opsource.net/schemas/support" xmlns:ns13="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns6="http://oec.api.opsource.net/schemas/general" xmlns:ns7="http://oec.api.opsource.net/schemas/reset" xmlns:ns10="http://oec.api.opsource.net/schemas/server" xmlns:ns8="http://oec.api.opsource.net/schemas/network" xmlns:ns11="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns2="http://oec.api.opsource.net/schemas/organization" xmlns:ns4="http://oec.api.opsource.net/schemas/serverbootstrap" xmlns:ns3="http://oec.api.opsource.net/schemas/vip"> + <ns6:operation>Get Backup Details</ns6:operation> + <ns6:result>ERROR</ns6:result> + <ns6:resultDetail>Server e75ead52-692f-4314_8725-c8a4f4d13a87 has not been provisioned for backup</ns6:resultDetail> + <ns6:resultCode>REASON_543</ns6:resultCode> +</ns6:Status> http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml new file mode 100644 index 0000000..0f62576 --- /dev/null +++ b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<ns9:BackupDetails assetId="71febbbc-337a-40c4-8c29-0afe85ccb3ea" servicePlan="Essentials" state="NORMAL" xmlns:ns16="http://oec.api.opsource.net/schemas/storage" xmlns="http://oec.api.opsource.net/schemas/admin" xmlns:ns14="http://oec.api.opsource.net/schemas/directory" xmlns:ns15="http://oec.api.opsource.net/schemas/multigeo" xmlns:ns9="http://oec.api.opsource.net/schemas/backup" xmlns:ns5="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns12="http://oec.api.opsource.net/schemas/support" xmlns:ns13="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns6="http://oec.api.opsource.net/schemas/general" xmlns:ns7="http://oec.api.opsource.net/schemas/reset" xmlns:ns10="http://oec.api.opsource.net/schemas/server" xmlns:ns8="http://oec.api.opsource.net/schemas/network" xmlns:ns11="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns2="http://oec.api.opsource.net/schemas/organization" xmlns:ns4="http://oec.api.opsource.net/schemas/serverbootstrap" xmlns:ns3="http://oec.api.o psource.net/schemas/vip"/> http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml new file mode 100644 index 0000000..45c97ce --- /dev/null +++ b/libcloud/test/backup/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<ns9:BackupDetails assetId="12769311-938c-4669-9460-7723eb194269" servicePlan="Enterprise" state="NORMAL" xmlns:ns16="http://oec.api.opsource.net/schemas/storage" xmlns="http://oec.api.opsource.net/schemas/admin" xmlns:ns14="http://oec.api.opsource.net/schemas/directory" xmlns:ns15="http://oec.api.opsource.net/schemas/multigeo" xmlns:ns9="http://oec.api.opsource.net/schemas/backup" xmlns:ns5="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns12="http://oec.api.opsource.net/schemas/support" xmlns:ns13="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns6="http://oec.api.opsource.net/schemas/general" xmlns:ns7="http://oec.api.opsource.net/schemas/reset" xmlns:ns10="http://oec.api.opsource.net/schemas/server" xmlns:ns8="http://oec.api.opsource.net/schemas/network" xmlns:ns11="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns2="http://oec.api.opsource.net/schemas/organization" xmlns:ns4="http://oec.api.opsource.net/schemas/serverbootstrap" xmlns:ns3="http://oec.api.o psource.net/schemas/vip"> + <ns9:backupClient id="30b1ff76-c76d-4d7c-b39d-3b72be0384c8" type="FA.Linux" isFileSystem="true" status="Unregistered"> + <ns9:description>Linux File Agent</ns9:description> + <ns9:schedulePolicyName>12AM - 6AM</ns9:schedulePolicyName> + <ns9:storagePolicyName>14 Day Storage Policy</ns9:storagePolicyName> + <ns9:times nextBackup="2016-02-09T00:00:00" lastOnline="2016-02-08T06:10:25"/> + <ns9:totalBackupSizeGb>0</ns9:totalBackupSizeGb> + <ns9:downloadUrl>https://backups-na.cloud-vpn.net/PCS/BackupClientInstallerDownload/cbb8a8c607ca4144e8828814edfc1634c8dd8782</ns9:downloadUrl> + </ns9:backupClient> +</ns9:BackupDetails> http://git-wip-us.apache.org/repos/asf/libcloud/blob/67f7e06f/libcloud/test/backup/test_dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/test_dimensiondata.py b/libcloud/test/backup/test_dimensiondata.py index fe5a964..5ce91e3 100644 --- a/libcloud/test/backup/test_dimensiondata.py +++ b/libcloud/test/backup/test_dimensiondata.py @@ -100,8 +100,39 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin): response = self.driver.ex_get_backup_details_for_target(target) self.assertEqual(response.service_plan, 'Enterprise') client = response.clients[0] - self.assertEqual(client.type, 'FA.Linux') + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') self.assertEqual(client.running_job.percentage, 5) + self.assertEqual(len(client.alert.notify_list), 2) + self.assertTrue(isinstance(client.alert.notify_list, list)) + + """Test a backup info for a target that does not have a client""" + def test_ex_get_backup_details_for_target_NO_CLIENT(self): + DimensionDataMockHttp.type = 'NOCLIENT' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Essentials') + self.assertEqual(len(response.clients), 0) + + """Test a backup details that has a client, but no alerting or running jobs""" + def test_ex_get_backup_details_for_target_NO_JOB_OR_ALERT(self): + DimensionDataMockHttp.type = 'NOJOB' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Enterprise') + self.assertTrue(isinstance(response.clients, list)) + self.assertEqual(len(response.clients), 1) + client = response.clients[0] + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') + self.assertIsNone(client.running_job) + self.assertIsNone(client.alert) + + """Test getting backup info for a server that doesn't exist""" + def test_ex_get_backup_details_for_target_DISABLED(self): + DimensionDataMockHttp.type = 'DISABLED' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') + self.assertEqual(context.exception.code, 'ERROR') + self.assertEqual(context.exception.msg, 'Server e75ead52-692f-4314_8725-c8a4f4d13a87 has not been provisioned for backup') def test_ex_list_available_client_types(self): target = self.driver.list_targets()[0] @@ -152,6 +183,18 @@ class DimensionDataMockHttp(MockHttp): body = self.fixtures.load('oec_0_9_myaccount.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _oec_0_9_myaccount_NOCLIENT(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_DISABLED(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_NOJOB(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _caas_2_1_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers): body = self.fixtures.load( 'caas_2_1_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml') @@ -183,6 +226,33 @@ class DimensionDataMockHttp(MockHttp): else: raise ValueError("Unknown Method {0}".format(method)) + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOCLIENT( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOCLIENT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DISABLED( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_DISABLED.xml') + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOJOB( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_INFO_NOJOB.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup( self, method, url, body, headers): if method == 'POST': @@ -203,6 +273,9 @@ class DimensionDataMockHttp(MockHttp): def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_EXISTS( self, method, url, body, headers): + # only POSTs are implemented + # If we get any other method something has gone wrong + assert(method == 'POST') body = self.fixtures.load( 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_EXISTS.xml') return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])