Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# 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 sys
from libcloud.utils.py3 import httplib

from libcloud.common.types import InvalidCredsError
from libcloud.backup.drivers.dimensiondata import DimensionDataBackupDriver as DimensionData

from libcloud.test import MockHttp, unittest
from libcloud.test.backup import TestCaseMixin
from libcloud.test.file_fixtures import BackupFileFixtures

from libcloud.test.secrets import DIMENSIONDATA_PARAMS


class DimensionDataTests(unittest.TestCase, TestCaseMixin):

def setUp(self):
DimensionData.connectionCls.conn_classes = (None, DimensionDataMockHttp)
DimensionDataMockHttp.type = None
self.driver = DimensionData(*DIMENSIONDATA_PARAMS)

def test_invalid_region(self):
with self.assertRaises(ValueError):
self.driver = DimensionData(*DIMENSIONDATA_PARAMS, region='blah')

def test_invalid_creds(self):
DimensionDataMockHttp.type = 'UNAUTHORIZED'
with self.assertRaises(InvalidCredsError):
self.driver.list_targets()

def test_list_targets(self):
targets = self.driver.list_targets()
self.assertEqual(len(targets), 2)
self.assertEqual(targets[0].id, '5579f3a7-4c32-4cf5-8a7e-b45c36a35c10')
self.assertEqual(targets[0].address, 'e75ead52-692f-4314-8725-c8a4f4d13a87')
self.assertEqual(targets[0].extra['servicePlan'], 'Enterprise')

def test_create_target(self):
target = self.driver.create_target(
'name',
'e75ead52-692f-4314-8725-c8a4f4d13a87',
extra={'servicePlan': 'Enterprise'})
self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f')
self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87')
self.assertEqual(target.extra['servicePlan'], 'Enterprise')

def test_create_target_EXISTS(self):
DimensionDataMockHttp.type = 'EXISTS'
with self.assertRaises(DimensionDataAPIException):
target = self.driver.create_target(
'name',
'e75ead52-692f-4314-8725-c8a4f4d13a87',
extra={'servicePlan': 'Enterprise'})

def test_update_target(self):
target = self.driver.list_targets()[0]
extra = {'servicePlan': 'Enterprise'}
new_target = self.driver.update_target(target, extra=extra)
self.assertEqual(new_target.extra['servicePlan'], 'Enterprise')

def test_delete_target(self):
target = self.driver.list_targets()[0]
self.assertTrue(self.driver.delete_target(target))

def test_ex_list_available_client_types(self):
target = self.driver.list_targets()[0]
answer = self.driver.ex_list_available_client_types(target)
self.assertEqual(len(answer), 1)
self.assertEqual(answer[0].type, 'FA.Linux')
self.assertEqual(answer[0].is_file_system, True)
self.assertEqual(answer[0].description, 'Linux File system')

def test_ex_list_available_storage_policies(self):
target = self.driver.list_targets()[0]
answer = self.driver.ex_list_available_storage_policies(target)
self.assertEqual(len(answer), 1)
self.assertEqual(answer[0].name,
'30 Day Storage Policy + Secondary Copy')
self.assertEqual(answer[0].retention_period, 30)
self.assertEqual(answer[0].secondary_location, 'Primary')

def test_ex_list_available_schedule_policies(self):
target = self.driver.list_targets()[0]
answer = self.driver.ex_list_available_schedule_policies(target)
self.assertEqual(len(answer), 1)
self.assertEqual(answer[0].name, '12AM - 6AM')
self.assertEqual(answer[0].description, 'Daily backup will start between 12AM - 6AM')


class InvalidRequestError(Exception):
def __init__(self, tag):
super(InvalidRequestError, self).__init__("Invalid Request - %s" % tag)


class DimensionDataMockHttp(MockHttp):

fixtures = BackupFileFixtures('dimensiondata')

def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
return (httplib.UNAUTHORIZED, "", {}, httplib.responses[httplib.UNAUTHORIZED])

def _oec_0_9_myaccount(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_INPROGRESS(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')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])

def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_type(self, method, url, body, headers):
body = self.fixtures.load(
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_type.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_client_storagePolicy(
self, method, url, body, headers):
body = self.fixtures.load(
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_storagePolicy.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_client_schedulePolicy(
self, method, url, body, headers):
body = self.fixtures.load(
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_schedulePolicy.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):
body = self.fixtures.load(
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup.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_modify(
self, method, url, body, headers):
body = self.fixtures.load(
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])


if __name__ == '__main__':
sys.exit(unittest.main())
26 changes: 20 additions & 6 deletions libcloud/common/dimensiondata.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@
# Default API end-point for the base connection class.
DEFAULT_REGION = 'dd-na'

BAD_CODE_XML_ELEMENTS = (
('responseCode', SERVER_NS),
('reponseCode', TYPES_URN),
('result', GENERAL_NS)
)

BAD_MESSAGE_XML_ELEMENTS = (
('message', SERVER_NS),
('message', TYPES_URN),
('resultDetail', GENERAL_NS)
)


class NetworkDomainServicePlan(object):
ESSENTIALS = "ESSENTIALS"
Expand All @@ -97,12 +109,14 @@ def parse_error(self):
body = self.parse_body()

if self.status == httplib.BAD_REQUEST:
code = findtext(body, 'responseCode', SERVER_NS)
if code is None:
code = findtext(body, 'responseCode', TYPES_URN)
message = findtext(body, 'message', SERVER_NS)
if message is None:
message = findtext(body, 'message', TYPES_URN)
for response_code in BAD_CODE_XML_ELEMENTS:
code = findtext(body, response_code[0], response_code[1])
if code is not None:
break
for message in BAD_MESSAGE_XML_ELEMENTS:
message = findtext(body, message[0], message[1])
if message is not None:
break
raise DimensionDataAPIException(code=code,
msg=message,
driver=self.connection.driver)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns0:Status xmlns:ns0="http://oec.api.opsource.net/schemas/general">
<ns0:operation>Enable Backup for Server</ns0:operation>
<ns0:result>ERROR</ns0:result>
<ns0:resultDetail>Cloud backup for this server is already enabled or being enabled (state: NORMAL).</ns0:resultDetail>
<ns0:resultCode>REASON_550</ns0:resultCode>
</ns0:Status>
21 changes: 21 additions & 0 deletions libcloud/test/backup/test_dimensiondata.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import sys
from libcloud.utils.py3 import httplib

from libcloud.common.dimensiondata import DimensionDataAPIException
from libcloud.common.types import InvalidCredsError
from libcloud.backup.drivers.dimensiondata import DimensionDataBackupDriver as DimensionData

Expand Down Expand Up @@ -58,6 +59,16 @@ def test_create_target(self):
self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87')
self.assertEqual(target.extra['servicePlan'], 'Enterprise')

def test_create_target_EXISTS(self):
DimensionDataMockHttp.type = 'EXISTS'
with self.assertRaises(DimensionDataAPIException) as context:
self.driver.create_target(
'name',
'e75ead52-692f-4314-8725-c8a4f4d13a87',
extra={'servicePlan': 'Enterprise'})
self.assertEqual(context.exception.code, 'ERROR')
self.assertEqual(context.exception.msg, 'Cloud backup for this server is already enabled or being enabled (state: NORMAL).')

def test_update_target(self):
target = self.driver.list_targets()[0]
extra = {'servicePlan': 'Enterprise'}
Expand Down Expand Up @@ -113,6 +124,10 @@ def _oec_0_9_myaccount_INPROGRESS(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_EXISTS(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')
Expand Down Expand Up @@ -141,6 +156,12 @@ def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725
'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup.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_EXISTS(
self, method, url, body, headers):
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])

def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify(
self, method, url, body, headers):
body = self.fixtures.load(
Expand Down