Methods for adding, deleting and renaming "networks" which are the MCP 1 network separation feature. Create network does include the ID in the message, but not by convention, just convenience so I decided to rely on the uniqueness of the name within a location to fetch the ID. Included tests
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4e26ef0d Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4e26ef0d Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4e26ef0d Branch: refs/heads/trunk Commit: 4e26ef0d1c40ac4ecfc091d5189df7549dac70f1 Parents: c923de3 Author: Anthony Shaw <anthony.p.s...@gmail.com> Authored: Fri Oct 30 11:36:34 2015 +1100 Committer: Anthony Shaw <anthony.p.s...@gmail.com> Committed: Fri Oct 30 11:36:34 2015 +1100 ---------------------------------------------------------------------- libcloud/common/dimensiondata.py | 1 + libcloud/compute/drivers/dimensiondata.py | 75 ++++++++++++++++++-- ...8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml | 2 +- ...ork_4bba37be_506f_11e3_b29c_001517c4643e.xml | 16 +++++ libcloud/test/compute/test_dimensiondata.py | 26 +++++++ 5 files changed, 115 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/4e26ef0d/libcloud/common/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/common/dimensiondata.py b/libcloud/common/dimensiondata.py index d6792d9..715d5fd 100644 --- a/libcloud/common/dimensiondata.py +++ b/libcloud/common/dimensiondata.py @@ -33,6 +33,7 @@ ORGANIZATION_NS = NAMESPACE_BASE + "/organization" SERVER_NS = NAMESPACE_BASE + "/server" NETWORK_NS = NAMESPACE_BASE + "/network" DIRECTORY_NS = NAMESPACE_BASE + "/directory" +GENERAL_NS = NAMESPACE_BASE + "/general" # API 2.0 Namespaces and URNs TYPES_URN = "urn:didata.com:api:cloud:types" http://git-wip-us.apache.org/repos/asf/libcloud/blob/4e26ef0d/libcloud/compute/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py index 1015562..51a21d5 100644 --- a/libcloud/compute/drivers/dimensiondata.py +++ b/libcloud/compute/drivers/dimensiondata.py @@ -33,11 +33,9 @@ from libcloud.common.dimensiondata import DimensionDataFirewallRule from libcloud.common.dimensiondata import DimensionDataFirewallAddress from libcloud.common.dimensiondata import DimensionDataNatRule from libcloud.common.dimensiondata import NetworkDomainServicePlan -from libcloud.common.dimensiondata import API_ENDPOINTS -from libcloud.common.dimensiondata import DEFAULT_REGION +from libcloud.common.dimensiondata import API_ENDPOINTS, DEFAULT_REGION from libcloud.common.dimensiondata import TYPES_URN -from libcloud.common.dimensiondata import SERVER_NS -from libcloud.common.dimensiondata import NETWORK_NS +from libcloud.common.dimensiondata import SERVER_NS, NETWORK_NS, GENERAL_NS from libcloud.utils.xml import fixxpath, findtext, findall from libcloud.compute.types import NodeState, Provider @@ -465,6 +463,75 @@ class DimensionDataNodeDriver(NodeDriver): params=params).object return self._to_networks(response) + def ex_create_network(self, location, name, description=None): + """ + Create a new network in an MCP 1.0 location + + :param location: The target location (MCP1) + :type location: :class:`NodeLocation` + + :param name: The name of the network + :type name: ``str`` + + :param description: Additional description of the network + :type description: ``str`` + + :return: A new instance of `DimensionDataNetwork` + :rtype: Instance of :class:`DimensionDataNetwork` + """ + create_node = ET.Element('NewNetworkWithLocation', + {'xmlns': NETWORK_NS}) + ET.SubElement(create_node, "name").text = name + if description is not None: + ET.SubElement(create_node, "description").text = description + ET.SubElement(create_node, "location").text = location.id + + response = self.connection.request_with_orgId_api_1( + 'networkWithLocation', + method='POST', + data=ET.tostring(create_node)).object + + # MCP1 API does not return the ID, but name is unique for location + network = list( + filter(lambda x: x.name == name, + self.ex_list_networks(location)))[0] + + return network + + def ex_delete_network(self, network): + """ + Delete a network from an MCP 1 data center + + :param network: The network to delete + :type network: :class:`DimensionDataNetwork` + + :rtype: ``bool`` + """ + response = self.connection.request_with_orgId_api_1( + 'network/%s?delete' % network.id, + method='GET').object + response_code = findtext(response, 'result', GENERAL_NS) + return response_code == "SUCCESS" + + def ex_rename_network(self, network, new_name): + """ + Rename a network in MCP 1 data center + + :param network: The network to rename + :type network: :class:`DimensionDataNetwork` + + :param new_name: The new name of the network + :type new_name: ``str`` + + :rtype: ``bool`` + """ + response = self.connection.request_with_orgId_api_1( + 'network/%s' % network.id, + method='POST', + data='name=%s' % new_name).object + response_code = findtext(response, 'result', GENERAL_NS) + return response_code == "SUCCESS" + def ex_get_network_domain(self, network_domain_id): """ Get an individual Network Domain, by identifier http://git-wip-us.apache.org/repos/asf/libcloud/blob/4e26ef0d/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml index 5a8dfee..227def2 100644 --- a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml +++ b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml @@ -12,7 +12,7 @@ <ns3:id>208e3a8e-9d2f-11e2-b29c-001517c4643e</ns3:id> <ns3:name>Test Network</ns3:name> <ns3:description>Network description</ns3:description> - <ns3:location>NA1</ns3:location> + <ns3:location>NA9</ns3:location> <ns3:privateNet>10.172.74.0</ns3:privateNet> <ns3:multicast>false</ns3:multicast> </ns3:network> http://git-wip-us.apache.org/repos/asf/libcloud/blob/4e26ef0d/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e.xml b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e.xml new file mode 100644 index 0000000..1e28e0d --- /dev/null +++ b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<ns7:Status xmlns:ns16="http://oec.api.opsource.net/schemas/serverbootstrap" + xmlns="http://oec.api.opsource.net/schemas/network" + xmlns:ns14="http://oec.api.opsource.net/schemas/storage" + xmlns:ns15="http://oec.api.opsource.net/schemas/backup" + xmlns:ns9="http://oec.api.opsource.net/schemas/admin" + xmlns:ns5="http://oec.api.opsource.net/schemas/organization" + xmlns:ns12="http://oec.api.opsource.net/schemas/support" + xmlns:ns13="http://oec.api.opsource.net/schemas/multigeo" + xmlns:ns6="http://oec.api.opsource.net/schemas/directory" + xmlns:ns7="http://oec.api.opsource.net/schemas/general" xmlns:ns10="http://oec.api.opsource.net/schemas/reset" xmlns:ns8="http://oec.api.opsource.net/schemas/vip" xmlns:ns11="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns2="http://oec.api.opsource.net/schemas/manualimport" xmlns:ns4="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns3="http://oec.api.opsource.net/schemas/server"> + <ns7:operation>Add Network</ns7:operation> + <ns7:result>SUCCESS</ns7:result> + <ns7:resultDetail>Network created successfully (Network ID: 9eb15060-e2f7-11e1-9153-001b21cfdbe0)</ns7:resultDetail> + <ns7:resultCode>REASON_0</ns7:resultCode> +</ns7:Status> http://git-wip-us.apache.org/repos/asf/libcloud/blob/4e26ef0d/libcloud/test/compute/test_dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_dimensiondata.py b/libcloud/test/compute/test_dimensiondata.py index cbaa22f..d779900 100644 --- a/libcloud/test/compute/test_dimensiondata.py +++ b/libcloud/test/compute/test_dimensiondata.py @@ -217,6 +217,22 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin): self.assertEqual(nets[0].name, 'test-net1') self.assertTrue(isinstance(nets[0].location, NodeLocation)) + def test_ex_create_network(self): + location = self.driver.ex_get_location_by_id('NA9') + net = self.driver.ex_create_network(location, "Test Network", "test") + self.assertEqual(net.id, "208e3a8e-9d2f-11e2-b29c-001517c4643e") + self.assertEqual(net.name, "Test Network") + + def test_ex_delete_network(self): + net = self.driver.ex_list_networks()[0] + result = self.driver.ex_delete_network(net) + self.assertTrue(result) + + def test_ex_rename_network(self): + net = self.driver.ex_list_networks()[0] + result = self.driver.ex_rename_network(net, "barry") + self.assertTrue(result) + def test_ex_create_network_domain(self): location = self.driver.ex_get_location_by_id('NA9') plan = NetworkDomainServicePlan.ADVANCED @@ -474,10 +490,20 @@ class DimensionDataMockHttp(MockHttp): return (httplib.OK, body, {}, httplib.responses[httplib.OK]) def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation(self, method, url, body, headers): + if method is "POST": + request = ET.fromstring(body) + if request.tag != "{http://oec.api.opsource.net/schemas/network}NewNetworkWithLocation": + raise InvalidRequestError(request.tag) body = self.fixtures.load( 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e(self, method, + url, body, headers): + body = self.fixtures.load( + 'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_4bba37be_506f_11e3_b29c_001517c4643e.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server(self, method, url, body, headers): body = self.fixtures.load( 'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server.xml')