http://git-wip-us.apache.org/repos/asf/libcloud/blob/b80bf325/libcloud/compute/drivers/nttcis.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/nttcis.py 
b/libcloud/compute/drivers/nttcis.py
new file mode 100644
index 0000000..937cd67
--- /dev/null
+++ b/libcloud/compute/drivers/nttcis.py
@@ -0,0 +1,4754 @@
+# 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.
+"""
+NTT CIS Driver
+"""
+
+from libcloud.utils.py3 import ET
+from libcloud.common.nttcis import LooseVersion
+from libcloud.common.exceptions import BaseHTTPError
+from libcloud.compute.base import NodeDriver, Node, NodeAuthPassword
+from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
+from libcloud.common.nttcis import dd_object_to_id
+from libcloud.common.nttcis import NttCisAPIException
+from libcloud.common.nttcis import (NttCisConnection,
+                                           NttCisStatus)
+from libcloud.common.nttcis import NttCisNetwork
+from libcloud.common.nttcis import NttCisNetworkDomain
+from libcloud.common.nttcis import NttCisVlan
+from libcloud.common.nttcis import NttCisServerCpuSpecification
+from libcloud.common.nttcis import NttCisServerDisk
+from libcloud.common.nttcis import NttCisServerVMWareTools
+from libcloud.common.nttcis import NttCisPublicIpBlock
+from libcloud.common.nttcis import NttCisFirewallRule
+from libcloud.common.nttcis import NttCisFirewallAddress
+from libcloud.common.nttcis import NttCisNatRule
+from libcloud.common.nttcis import NttCisAntiAffinityRule
+from libcloud.common.nttcis import NttCisIpAddressList
+from libcloud.common.nttcis import NttCisChildIpAddressList
+from libcloud.common.nttcis import NttCisIpAddress
+from libcloud.common.nttcis import NttCisPortList
+from libcloud.common.nttcis import NttCisPort
+from libcloud.common.nttcis import NttCisChildPortList
+from libcloud.common.nttcis import NttCisNic
+from libcloud.common.nttcis import NetworkDomainServicePlan
+from libcloud.common.nttcis import NttCisTagKey
+from libcloud.common.nttcis import NttCisTag
+from libcloud.common.nttcis import API_ENDPOINTS, DEFAULT_REGION
+from libcloud.common.nttcis import TYPES_URN
+from libcloud.common.nttcis import SERVER_NS, NETWORK_NS, GENERAL_NS
+from libcloud.utils.py3 import urlencode, ensure_string
+from libcloud.utils.xml import fixxpath, findtext, findall
+from libcloud.utils.py3 import basestring
+from libcloud.compute.types import NodeState, Provider
+import sys
+
+# Node state map is a dictionary with the keys as tuples
+# These tuples represent:
+# (<state_of_node_from_didata>, <is node started?>, <action happening>)
+NODE_STATE_MAP = {
+    ('NORMAL', 'false', None):
+        NodeState.STOPPED,
+    ('PENDING_CHANGE', 'false', None):
+        NodeState.PENDING,
+    ('PENDING_CHANGE', 'false', 'CHANGE_NETWORK_ADAPTER'):
+        NodeState.PENDING,
+    ('PENDING_CHANGE', 'true', 'CHANGE_NETWORK_ADAPTER'):
+        NodeState.PENDING,
+    ('PENDING_CHANGE', 'false', 'EXCHANGE_NIC_VLANS'):
+        NodeState.PENDING,
+    ('PENDING_CHANGE', 'true', 'EXCHANGE_NIC_VLANS'):
+        NodeState.PENDING,
+    ('NORMAL', 'true', None):
+        NodeState.RUNNING,
+    ('PENDING_CHANGE', 'true', 'START_SERVER'):
+        NodeState.STARTING,
+    ('PENDING_ADD', 'true', 'DEPLOY_SERVER'):
+        NodeState.STARTING,
+    ('PENDING_ADD', 'true', 'DEPLOY_SERVER_WITH_DISK_SPEED'):
+        NodeState.STARTING,
+    ('PENDING_CHANGE', 'true', 'SHUTDOWN_SERVER'):
+        NodeState.STOPPING,
+    ('PENDING_CHANGE', 'true', 'POWER_OFF_SERVER'):
+        NodeState.STOPPING,
+    ('PENDING_CHANGE', 'true', 'REBOOT_SERVER'):
+        NodeState.REBOOTING,
+    ('PENDING_CHANGE', 'true', 'RESET_SERVER'):
+        NodeState.REBOOTING,
+    ('PENDING_CHANGE', 'true', 'RECONFIGURE_SERVER'):
+        NodeState.RECONFIGURING,
+}
+
+OBJECT_TO_TAGGING_ASSET_TYPE_MAP = {
+    'Node': 'SERVER',
+    'NodeImage': 'CUSTOMER_IMAGE',
+    'NttCisNetworkDomain': 'NETWORK_DOMAIN',
+    'NttCisVlan': 'VLAN',
+    'NttCisPublicIpBlock': 'PUBLIC_IP_BLOCK'
+}
+
+
+class NttCisNodeDriver(NodeDriver):
+    """
+    DimensionData node driver.
+    Default api_version is used unless specified.
+    """
+
+    selected_region = None
+    connectionCls = NttCisConnection
+    name = 'DimensionData'
+    website = 'http://www.dimensiondata.com/'
+    type = Provider.DIMENSIONDATA
+    features = {'create_node': ['password']}
+    api_version = 1.0
+
+    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 and host is None:
+            raise ValueError(
+                'Invalid region: %s, no host specified' % (region))
+        if region is not None:
+            self.selected_region = API_ENDPOINTS[region]
+
+        if api_version is not None:
+            self.api_version = api_version
+
+        super(NttCisNodeDriver, 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(NttCisNodeDriver,
+                       self)._ex_connection_class_kwargs()
+        kwargs['region'] = self.selected_region
+        kwargs['api_version'] = self.api_version
+        return kwargs
+
+    def _create_node_mcp1(self, name, image, auth, ex_description,
+                          ex_network=None,
+                          ex_memory_gb=None,
+                          ex_cpu_specification=None,
+                          ex_is_started=True,
+                          ex_primary_dns=None,
+                          ex_secondary_dns=None, **kwargs):
+        """
+            Create a new NTTCIS node
+
+            :keyword    name:   String with a name for this new node (required)
+            :type       name:   ``str``
+
+            :keyword    image:  OS Image to boot on node. (required)
+            :type       image:  :class:`NodeImage` or ``str``
+
+            :keyword    auth:   Initial authentication information for the
+                                node. (If this is a customer LINUX
+                                image auth will be ignored)
+            :type       auth:   :class:`NodeAuthPassword` or ``str`` or
+                                ``None``
+
+            :keyword    ex_description:  description for this node (required)
+            :type       ex_description:  ``str``
+
+            :keyword    ex_network:  Network to create the node within
+                                     (required unless using ex_network_domain
+                                     or ex_primary_ipv4)
+
+            :type       ex_network: :class:`NttCisNetwork` or ``str``
+
+            :keyword    ex_memory_gb:  The amount of memory in GB for the
+                                       server
+            :type       ex_memory_gb: ``int``
+
+            :keyword    ex_cpu_specification: The spec of CPU to deploy (
+                                              optional)
+            :type       ex_cpu_specification:
+                            :class:`DimensionDataServerCpuSpecification`
+
+            :keyword    ex_is_started:  Start server after creation? default
+                                        true (required)
+            :type       ex_is_started:  ``bool``
+
+            :keyword    ex_primary_dns: The node's primary DNS
+
+            :type       ex_primary_dns: ``str``
+
+            :keyword    ex_secondary_dns: The node's secondary DNS
+
+            :type       ex_secondary_dns: ``str``
+
+            :return: The newly created :class:`Node`.
+            :rtype: :class:`Node`
+            """
+        password = None
+        image_needs_auth = self._image_needs_auth(image)
+        if image_needs_auth:
+            if isinstance(auth, basestring):
+                auth_obj = NodeAuthPassword(password=auth)
+                password = auth
+            else:
+                auth_obj = self._get_and_check_auth(auth)
+                password = auth_obj.password
+
+        server_elm = ET.Element('deployServer', {'xmlns': TYPES_URN})
+        ET.SubElement(server_elm, "name").text = name
+        ET.SubElement(server_elm, "description").text = ex_description
+        image_id = self._image_to_image_id(image)
+        ET.SubElement(server_elm, "imageId").text = image_id
+        ET.SubElement(server_elm, "start").text = str(
+            ex_is_started).lower()
+        if password is not None:
+            ET.SubElement(server_elm,
+                          "administratorPassword").text = password
+
+        if ex_cpu_specification is not None:
+            cpu = ET.SubElement(server_elm, "cpu")
+            cpu.set('speed', ex_cpu_specification.performance)
+            cpu.set('count', str(ex_cpu_specification.cpu_count))
+            cpu.set('coresPerSocket',
+                    str(ex_cpu_specification.cores_per_socket))
+
+        if ex_memory_gb is not None:
+            ET.SubElement(server_elm, "memoryGb").text = str(ex_memory_gb)
+
+        if ex_network is not None:
+            network_elm = ET.SubElement(server_elm, "network")
+            network_id = self._network_to_network_id(ex_network)
+            ET.SubElement(network_elm, "networkId").text = network_id
+
+        if ex_primary_dns:
+            dns_elm = ET.SubElement(server_elm, "primaryDns")
+            dns_elm.text = ex_primary_dns
+
+        if ex_secondary_dns:
+            dns_elm = ET.SubElement(server_elm, "secondaryDns")
+            dns_elm.text = ex_secondary_dns
+
+        response = self.connection.request_with_orgId_api_2(
+            'server/deployServer',
+            method='POST',
+            data=ET.tostring(server_elm)).object
+
+        node_id = None
+        for info in findall(response, 'info', TYPES_URN):
+            if info.get('name') == 'serverId':
+                node_id = info.get('value')
+
+        node = self.ex_get_node_by_id(node_id)
+
+        if image_needs_auth:
+            if getattr(auth_obj, "generated", False):
+                node.extra['password'] = auth_obj.password
+
+        return node
+
+    def create_node(self, name,
+                    image,
+                    auth,
+                    ex_network_domain=None,
+                    ex_primary_nic_private_ipv4=None,
+                    ex_primary_nic_vlan=None,
+                    ex_primary_nic_network_adapter=None,
+                    ex_additional_nics=None,
+                    ex_description=None,
+                    ex_disks=None,
+                    ex_cpu_specification=None,
+                    ex_memory_gb=None,
+                    ex_is_started=True,
+                    ex_primary_dns=None,
+                    ex_secondary_dns=None,
+                    ex_ipv4_gateway=None,
+                    ex_microsoft_time_zone=None,
+                    **kwargs
+                    ):
+        """
+        Create a new DimensionData node in MCP2. However, it is still
+        backward compatible for MCP1 for a limited time. Please consider
+        using MCP2 datacenter as MCP1 will phase out soon.
+
+        Legacy Create Node for MCP1 datacenter
+
+        >>> from pprint import pprint
+        >>> from libcloud.compute.types import Provider
+        >>> from libcloud.compute.base import NodeAuthPassword
+        >>> from libcloud.compute.providers import get_driver
+        >>> import libcloud.security
+        >>>
+        >>> # Get dimension data driver
+        >>> libcloud.security.VERIFY_SSL_CERT = False
+        >>> DimensionData = get_driver(Provider.DIMENSIONDATA)
+        >>> driver = cls('myusername','mypassword', region='dd-au')
+        >>>
+        >>> # Password
+        >>> root_pw = NodeAuthPassword('password123')
+        >>>
+        >>> # Get location
+        >>> location = driver.ex_get_location_by_id(id='AU1')
+        >>>
+        >>> # Get network by location
+        >>> my_network = driver.list_networks(location=location)[0]
+        >>> pprint(my_network)
+        >>>
+        >>> # Get Image
+        >>> images = driver.list_images(location=location)
+        >>> image = images[0]
+        >>>
+        >>> node = driver.create_node(name='test_blah_2', image=image,
+        >>>                           auth=root_pw,
+        >>>                           ex_description='test3 node',
+        >>>                           ex_network=my_network,
+        >>>                           ex_is_started=False)
+        >>> pprint(node)
+
+
+        Create Node in MCP2 Data Center
+
+        >>> from pprint import pprint
+        >>> from libcloud.compute.types import Provider
+        >>> from libcloud.compute.base import NodeAuthPassword
+        >>> from libcloud.compute.providers import get_driver
+        >>> import libcloud.security
+        >>>
+        >>> # Get dimension data driver
+        >>> libcloud.security.VERIFY_SSL_CERT = True
+        >>> cls = get_driver(Provider.DIMENSIONDATA)
+        >>> driver = cls('myusername','mypassword', region='dd-au')
+        >>>
+        >>> # Password
+        >>> root_pw = NodeAuthPassword('password123')
+        >>>
+        >>> # Get location
+        >>> location = driver.ex_get_location_by_id(id='AU9')
+        >>>
+        >>> # Get network domain by location
+        >>> networkDomainName = "Baas QA"
+        >>> network_domains = driver.ex_list_network_domains(location=location)
+        >>> my_network_domain = [d for d in network_domains if d.name ==
+                              networkDomainName][0]
+        >>>
+        >>> vlan = driver.ex_list_vlans(location=location,
+        >>>                             network_domain=my_network_domain)[0]
+        >>> pprint(vlan)
+        >>>
+        >>> # Get Image
+        >>> images = driver.list_images(location=location)
+        >>> image = images[0]
+        >>>
+        >>> # Create node using vlan instead of private IPv4
+        >>> node = driver.create_node(name='test_server_01', image=image,
+        >>>                           auth=root_pw,
+        >>>                           ex_description='test2 node',
+        >>>                           ex_network_domain=my_network_domain,
+        >>>                           ex_primary_nic_vlan=vlan,
+        >>>                           ex_is_started=False)
+        >>>
+        >>> # Option: Create node using private IPv4 instead of vlan
+        >>> # node = driver.create_node(name='test_server_02', image=image,
+        >>> #                           auth=root_pw,
+        >>> #                           ex_description='test2 node',
+        >>> #                           ex_network_domain=my_network_domain,
+        >>> #                           ex_primary_nic_private_ipv4='10.1.1.7',
+        >>> #                           ex_is_started=False)
+        >>>
+        >>> # Option: Create node using by specifying Network Adapter
+        >>> # node = driver.create_node(name='test_server_03', image=image,
+        >>> #                           auth=root_pw,
+        >>> #                           ex_description='test2 node',
+        >>> #                           ex_network_domain=my_network_domain,
+        >>> #                           ex_primary_nic_vlan=vlan,
+        >>> #                           ex_primary_nic_network_adapter='E1000',
+        >>> #                           ex_is_started=False)
+        >>>
+
+        :keyword    name:   (required) String with a name for this new node
+        :type       name:   ``str``
+
+        :keyword    image:  (required) OS Image to boot on node.
+        :type       image:  :class:`NodeImage` or ``str``
+
+        :keyword    auth:   Initial authentication information for the
+                            node. (If this is a customer LINUX
+                            image auth will be ignored)
+        :type       auth:   :class:`NodeAuthPassword` or ``str`` or ``None``
+
+        :keyword    ex_description:  (optional) description for this node
+        :type       ex_description:  ``str``
+
+
+        :keyword    ex_network_domain:  (required) Network Domain or Network
+                                        Domain ID to create the node
+        :type       ex_network_domain: :class:`DimensionDataNetworkDomain`
+                                        or ``str``
+
+        :keyword    ex_primary_nic_private_ipv4:  Provide private IPv4. Ignore
+                                                  if ex_primary_nic_vlan is
+                                                  provided. Use one or the
+                                                  other. Not both.
+        :type       ex_primary_nic_private_ipv4: :``str``
+
+        :keyword    ex_primary_nic_vlan:  Provide VLAN for the node if
+                                          ex_primary_nic_private_ipv4 NOT
+                                          provided. One or the other. Not both.
+        :type       ex_primary_nic_vlan: :class: DimensionDataVlan or ``str``
+
+        :keyword    ex_primary_nic_network_adapter: (Optional) Default value
+                                                    for the Operating System
+                                                    will be used if leave
+                                                    empty. Example: "E1000".
+        :type       ex_primary_nic_network_adapter: :``str``
+
+        :keyword    ex_additional_nics: (optional) List
+                                        :class:'NttCisNic' or None
+        :type       ex_additional_nics: ``list`` of :class:'NttCisNic'
+                                        or ``str``
+
+        :keyword    ex_memory_gb:  (optional) The amount of memory in GB for
+                                   the server Can be used to override the
+                                   memory value inherited from the source
+                                   Server Image.
+        :type       ex_memory_gb: ``int``
+
+        :keyword    ex_cpu_specification: (optional) The spec of CPU to deploy
+        :type       ex_cpu_specification:
+                        :class:`DimensionDataServerCpuSpecification`
+
+        :keyword    ex_is_started: (required) Start server after creation.
+                                   Default is set to true.
+        :type       ex_is_started:  ``bool``
+
+        :keyword    ex_primary_dns: (Optional) The node's primary DNS
+        :type       ex_primary_dns: ``str``
+
+        :keyword    ex_secondary_dns: (Optional) The node's secondary DNS
+        :type       ex_secondary_dns: ``str``
+
+        :keyword    ex_ipv4_gateway: (Optional) IPv4 address in dot-decimal
+                                     notation, which will be used as the
+                                     Primary NIC gateway instead of the default
+                                     gateway assigned by the system. If
+                                     ipv4Gateway is provided it does not have
+                                     to be on the VLAN of the Primary NIC
+                                     but MUST be reachable or the Guest OS
+                                     will not be configured correctly.
+        :type       ex_ipv4_gateway: ``str``
+
+        :keyword    ex_disks: (optional) Dimensiondata disks. Optional disk
+                            elements can be used to define the disk speed
+                            that each disk on the Server; inherited from the
+                            source Server Image will be deployed to. It is
+                            not necessary to include a diskelement for every
+                            disk; only those that you wish to set a disk
+                            speed value for. Note that scsiId 7 cannot be
+                            used.Up to 13 disks can be present in addition to
+                            the required OS disk on SCSI ID 0. Refer to
+                            https://docs.mcp-services.net/x/UwIu for disk
+
+        :type       ex_disks: List or tuple of :class:'DimensionDataServerDisk`
+
+        :keyword    ex_microsoft_time_zone: (optional) For use with
+                    Microsoft Windows source Server Images only. For the exact
+                    value to use please refer to the table of time zone
+                    indexes in the following Microsoft Technet
+                    documentation. If none is supplied, the default time
+                    zone for the data center geographic region will be used.
+        :type       ex_microsoft_time_zone: `str``
+
+
+        :return: The newly created :class:`Node`.
+        :rtype: :class:`Node`
+        """
+
+        # Neither legacy MCP1 network nor MCP2 network domain provided
+        if ex_network_domain is None and 'ex_network' not in kwargs:
+            raise ValueError('You must provide either ex_network_domain '
+                             'for MCP2 or ex_network for legacy MCP1')
+
+        # Ambiguous parameter provided. Can't determine if it is MCP 1 or 2.
+        if ex_network_domain is not None and 'ex_network' in kwargs:
+            raise ValueError('You can only supply either '
+                             'ex_network_domain '
+                             'for MCP2 or ex_network for legacy MCP1')
+
+        # Set ex_is_started to False by default if none bool data type provided
+        if not isinstance(ex_is_started, bool):
+            ex_is_started = True
+
+        # Handle MCP1 legacy
+        if 'ex_network' in kwargs:
+            new_node = self._create_node_mcp1(
+                name=name, image=image, auth=auth,
+                ex_network=kwargs.get("ex_network"),
+                ex_description=ex_description,
+                ex_memory_gb=ex_memory_gb,
+                ex_cpu_specification=ex_cpu_specification,
+                ex_is_started=ex_is_started,
+                ex_primary_ipv4=ex_primary_nic_private_ipv4,
+                ex_disks=ex_disks,
+                ex_additional_nics_vlan=kwargs.get("ex_additional_nics_vlan"),
+                ex_additional_nics_ipv4=kwargs.get("ex_additional_nics_ipv4"),
+                ex_primary_dns=ex_primary_dns,
+                ex_secondary_dns=ex_secondary_dns
+            )
+        else:
+            # Handle MCP2 legacy. CaaS api 2.2 or earlier
+            if 'ex_vlan' in kwargs:
+                ex_primary_nic_vlan = kwargs.get('ex_vlan')
+
+            if 'ex_primary_ipv4' in kwargs:
+                ex_primary_nic_private_ipv4 = kwargs.get(
+                    'ex_primary_ipv4')
+
+            additional_nics = []
+
+            if 'ex_additional_nics_vlan' in kwargs:
+                vlans = kwargs.get('ex_additional_nics_vlan')
+                if isinstance(vlans, (list, tuple)):
+                    for v in vlans:
+                        add_nic =NttCisNic(vlan=v)
+                        additional_nics.append(add_nic)
+                else:
+                    raise TypeError("ex_additional_nics_vlan must "
+                                    "be None or a tuple/list")
+
+            if 'ex_additional_nics_ipv4' in kwargs:
+                ips = kwargs.get('ex_additional_nics_ipv4')
+
+                if isinstance(ips, (list, tuple)):
+                    for ip in ips:
+                        add_nic = NttCisNic(private_ip_v4=ip)
+                        additional_nics.append(add_nic)
+                else:
+                    if ips is not None:
+                        raise TypeError("ex_additional_nics_ipv4 must "
+                                        "be None or a tuple/list")
+
+            if ('ex_additional_nics_vlan' in kwargs or
+                    'ex_additional_nics_ipv4' in kwargs):
+                ex_additional_nics = additional_nics
+
+            # Handle MCP2 latest. CaaS API 2.3 onwards
+            if ex_network_domain is None:
+                raise ValueError("ex_network_domain must be specified")
+
+            password = None
+            image_needs_auth = self._image_needs_auth(image)
+            if image_needs_auth:
+                if isinstance(auth, basestring):
+                    auth_obj = NodeAuthPassword(password=auth)
+                    password = auth
+                else:
+                    auth_obj = self._get_and_check_auth(auth)
+                    password = auth_obj.password
+
+            server_elm = ET.Element('deployServer', {'xmlns': TYPES_URN})
+            ET.SubElement(server_elm, "name").text = name
+            ET.SubElement(server_elm, "description").text = ex_description
+            image_id = self._image_to_image_id(image)
+            ET.SubElement(server_elm, "imageId").text = image_id
+            ET.SubElement(server_elm, "start").text = str(
+                ex_is_started).lower()
+            if password is not None:
+                ET.SubElement(server_elm,
+                              "administratorPassword").text = password
+
+            if ex_cpu_specification is not None:
+                cpu = ET.SubElement(server_elm, "cpu")
+                cpu.set('speed', ex_cpu_specification.performance)
+                cpu.set('count', str(ex_cpu_specification.cpu_count))
+                cpu.set('coresPerSocket',
+                        str(ex_cpu_specification.cores_per_socket))
+
+            if ex_memory_gb is not None:
+                ET.SubElement(server_elm, "memoryGb").text = str(ex_memory_gb)
+
+            if (ex_primary_nic_private_ipv4 is None and
+                    ex_primary_nic_vlan is None):
+                raise ValueError("Missing argument. Either "
+                                 "ex_primary_nic_private_ipv4 or "
+                                 "ex_primary_nic_vlan "
+                                 "must be specified.")
+
+            if (ex_primary_nic_private_ipv4 is not None and
+                    ex_primary_nic_vlan is not None):
+                raise ValueError("Either ex_primary_nic_private_ipv4 or "
+                                 "ex_primary_nic_vlan "
+                                 "be specified. Not both.")
+
+            network_elm = ET.SubElement(server_elm, "networkInfo")
+
+            net_domain_id = self._network_domain_to_network_domain_id(
+                ex_network_domain)
+
+            network_elm.set('networkDomainId', net_domain_id)
+
+            pri_nic = ET.SubElement(network_elm, 'primaryNic')
+
+            if ex_primary_nic_private_ipv4 is not None:
+                ET.SubElement(pri_nic,
+                              'privateIpv4').text = ex_primary_nic_private_ipv4
+
+            if ex_primary_nic_vlan is not None:
+                vlan_id = self._vlan_to_vlan_id(ex_primary_nic_vlan)
+                ET.SubElement(pri_nic, 'vlanId').text = vlan_id
+
+            if ex_primary_nic_network_adapter is not None:
+                ET.SubElement(pri_nic,
+                              "networkAdapter").text = \
+                    ex_primary_nic_network_adapter
+
+            if isinstance(ex_additional_nics, (list, tuple)):
+                for nic in ex_additional_nics:
+                    additional_nic = ET.SubElement(network_elm,
+                                                   'additionalNic')
+
+                    if (nic.private_ip_v4 is None and
+                            nic.vlan is None):
+                        raise ValueError("Either a vlan or private_ip_v4 "
+                                         "must be specified for each "
+                                         "additional nic.")
+
+                    if (nic.private_ip_v4 is not None and
+                            nic.vlan is not None):
+                        raise ValueError("Either a vlan or private_ip_v4 "
+                                         "must be specified for each "
+                                         "additional nic. Not both.")
+
+                    if nic.private_ip_v4 is not None:
+                        ET.SubElement(additional_nic,
+                                      'privateIpv4').text = nic.private_ip_v4
+
+                    if nic.vlan is not None:
+                        vlan_id = self._vlan_to_vlan_id(nic.vlan)
+                        ET.SubElement(additional_nic, 'vlanId').text = vlan_id
+
+                    if nic.network_adapter_name is not None:
+                        ET.SubElement(additional_nic,
+                                      "networkAdapter").text = \
+                            nic.network_adapter_name
+            elif ex_additional_nics is not None:
+                raise TypeError(
+                    "ex_additional_NICs must be None or tuple/list")
+
+            if ex_primary_dns:
+                dns_elm = ET.SubElement(server_elm, "primaryDns")
+                dns_elm.text = ex_primary_dns
+
+            if ex_secondary_dns:
+                dns_elm = ET.SubElement(server_elm, "secondaryDns")
+                dns_elm.text = ex_secondary_dns
+
+            if ex_ipv4_gateway:
+                ET.SubElement(server_elm, "ipv4Gateway").text = ex_ipv4_gateway
+
+            if isinstance(ex_disks, (list, tuple)):
+                for disk in ex_disks:
+                    disk_elm = ET.SubElement(server_elm, 'disk')
+                    disk_elm.set('scsiId', disk.scsi_id)
+                    disk_elm.set('speed', disk.speed)
+            elif ex_disks is not None:
+                raise TypeError("ex_disks must be None or tuple/list")
+
+            if ex_microsoft_time_zone:
+                ET.SubElement(server_elm,
+                              "microsoftTimeZone").text = \
+                    ex_microsoft_time_zone
+
+            response = self.connection.request_with_orgId_api_2(
+                'server/deployServer',
+                method='POST',
+                data=ET.tostring(server_elm)).object
+
+            node_id = None
+            for info in findall(response, 'info', TYPES_URN):
+                if info.get('name') == 'serverId':
+                    node_id = info.get('value')
+
+            new_node = self.ex_get_node_by_id(node_id)
+
+            if image_needs_auth:
+                if getattr(auth_obj, "generated", False):
+                    new_node.extra['password'] = auth_obj.password
+
+        return new_node
+
+    def destroy_node(self, node):
+        """
+        Deletes a node, node must be stopped before deletion
+
+
+        :keyword node: The node to delete
+        :type    node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('deleteServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/deleteServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def reboot_node(self, node):
+        """
+        Reboots a node by requesting the OS restart via the hypervisor
+
+
+        :keyword node: The node to reboot
+        :type    node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('rebootServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/rebootServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def list_nodes(self, ex_location=None, ex_name=None,
+                   ex_ipv6=None, ex_ipv4=None, ex_vlan=None,
+                   ex_image=None, ex_deployed=None,
+                   ex_started=None, ex_state=None,
+                   ex_network=None, ex_network_domain=None):
+        """
+        List nodes deployed for your organization.
+
+        :keyword ex_location: Filters the node list to nodes that are
+                              located in this location
+        :type    ex_location: :class:`NodeLocation` or ``str``
+
+        :keyword ex_name: Filters the node list to nodes that have this name
+        :type    ex_name ``str``
+
+        :keyword ex_ipv6: Filters the node list to nodes that have this
+                          ipv6 address
+        :type    ex_ipv6: ``str``
+
+        :keyword ex_ipv4: Filters the node list to nodes that have this
+                          ipv4 address
+        :type    ex_ipv4: ``str``
+
+        :keyword ex_vlan: Filters the node list to nodes that are in this VLAN
+        :type    ex_vlan: :class:`DimensionDataVlan` or ``str``
+
+        :keyword ex_image: Filters the node list to nodes that have this image
+        :type    ex_image: :class:`NodeImage` or ``str``
+
+        :keyword ex_deployed: Filters the node list to nodes that are
+                              deployed or not
+        :type    ex_deployed: ``bool``
+
+        :keyword ex_started: Filters the node list to nodes that are
+                             started or not
+        :type    ex_started: ``bool``
+
+        :keyword ex_state: Filters the node list by nodes that are in
+                           this state
+        :type    ex_state: ``str``
+
+        :keyword ex_network: Filters the node list to nodes in this network
+        :type    ex_network: :class:`NttCisNetwork` or ``str``
+
+        :keyword ex_network_domain: Filters the node list to nodes in this
+                                    network domain
+        :type    ex_network_domain: :class:`NttCisNetworkDomain`
+                                    or ``str``
+
+        :return: a list of `Node` objects
+        :rtype: ``list`` of :class:`Node`
+        """
+        node_list = []
+        for nodes in self.ex_list_nodes_paginated(
+                location=ex_location,
+                name=ex_name, ipv6=ex_ipv6,
+                ipv4=ex_ipv4, vlan=ex_vlan,
+                image=ex_image, deployed=ex_deployed,
+                started=ex_started, state=ex_state,
+                network=ex_network,
+                network_domain=ex_network_domain):
+            node_list.extend(nodes)
+
+        return node_list
+
+    def list_images(self, location=None):
+        """
+        List images available
+
+        Note:  Currently only returns the default 'base OS images'
+               provided by NTTCIS. Customer images (snapshots)
+               use ex_list_customer_images
+
+        :keyword ex_location: Filters the node list to nodes that are
+                              located in this location
+        :type    ex_location: :class:`NodeLocation` or ``str``
+
+        :return: List of images available
+        :rtype: ``list`` of :class:`NodeImage`
+        """
+        params = {}
+        if location is not None:
+            params['datacenterId'] = self._location_to_location_id(location)
+
+        return self._to_images(
+            self.connection.request_with_orgId_api_2(
+                'image/osImage',
+                params=params)
+            .object)
+
+    def list_sizes(self, location=None):
+        """
+        return a list of available sizes
+            Currently, the size of the node is dictated by the chosen OS base
+            image, they cannot be set explicitly.
+
+        @inherits: :class:`NodeDriver.list_sizes`
+        """
+        return [
+            NodeSize(id=1,
+                     name="default",
+                     ram=0,
+                     disk=0,
+                     bandwidth=0,
+                     price=0,
+                     driver=self.connection.driver),
+        ]
+
+    def list_locations(self, ex_id=None):
+        """
+        List locations (datacenters) available for instantiating servers and
+        networks.
+
+        :keyword ex_id: Filters the location list to this id
+        :type    ex_id: ``str``
+
+        :return:  List of locations
+        :rtype:  ``list`` of :class:`NodeLocation`
+        """
+        params = {}
+        if ex_id is not None:
+            params['id'] = ex_id
+
+        return self._to_locations(
+            self.connection
+            .request_with_orgId_api_2(
+                'infrastructure/datacenter',
+                params=params
+            ).object
+        )
+
+    def list_networks(self, location=None):
+        """
+        List networks deployed across all data center locations for your
+        organization.  The response includes the location of each network.
+
+
+        :keyword location: The location
+        :type    location: :class:`NodeLocation` or ``str``
+
+        :return: a list of NttCisNetwork objects
+        :rtype: ``list`` of :class:`NttCisNetwork`
+        """
+        url_ext = ''
+        if location is not None:
+            url_ext = '/' + self._location_to_location_id(location)
+
+        return self._to_networks(
+            self.connection
+            .request_with_orgId_api_1('networkWithLocation%s' % url_ext)
+            .object)
+
+    def import_image(self, ovf_package_name, name,
+                     cluster_id=None, datacenter_id=None, description=None,
+                     is_guest_os_customization=None,
+                     tagkey_name_value_dictionaries=None):
+        """
+        Import image
+
+        :param ovf_package_name: Image OVF package name
+        :type  ovf_package_name: ``str``
+
+        :param name: Image name
+        :type  name: ``str``
+
+        :param cluster_id: Provide either cluster_id or datacenter_id
+        :type  cluster_id: ``str``
+
+        :param datacenter_id: Provide either cluster_id or datacenter_id
+        :type  datacenter_id: ``str``
+
+        :param description: Optional. Description of image
+        :type  description: ``str``
+
+        :param is_guest_os_customization: Optional. true for NGOC image
+        :type  is_guest_os_customization: ``bool``
+
+        :param tagkey_name_value_dictionaries: Optional tagkey name value dict
+        :type  tagkey_name_value_dictionaries: dictionaries
+
+        :return: Return true if successful
+        :rtype:  ``bool``
+        """
+
+        # Unsupported for version lower than 2.4
+        if LooseVersion(self.connection.active_api_version) < LooseVersion(
+                '2.4'):
+            raise Exception("import image is feature is NOT supported in  "
+                            "api version earlier than 2.4")
+        elif cluster_id is None and datacenter_id is None:
+            raise ValueError("Either cluster_id or datacenter_id must be "
+                             "provided")
+        elif cluster_id is not None and datacenter_id is not None:
+            raise ValueError("Cannot accept both cluster_id and "
+                             "datacenter_id. Please provide either one")
+        else:
+            import_image_elem = ET.Element(
+                'urn:importImage',
+                {
+                    'xmlns:urn': TYPES_URN,
+                })
+
+            ET.SubElement(
+                import_image_elem,
+                'urn:ovfPackage'
+            ).text = ovf_package_name
+
+            ET.SubElement(
+                import_image_elem,
+                'urn:name'
+            ).text = name
+
+            if description is not None:
+                ET.SubElement(
+                    import_image_elem,
+                    'urn:description'
+                ).text = description
+
+            if cluster_id is not None:
+                ET.SubElement(
+                    import_image_elem,
+                    'urn:clusterId'
+                ).text = cluster_id
+            else:
+                ET.SubElement(
+                    import_image_elem,
+                    'urn:datacenterId'
+                ).text = datacenter_id
+
+            if is_guest_os_customization is not None:
+                ET.SubElement(
+                    import_image_elem,
+                    'urn:guestOsCustomization'
+                ).text = is_guest_os_customization
+
+            if len(tagkey_name_value_dictionaries) > 0:
+                for k, v in tagkey_name_value_dictionaries.items():
+                    tag_elem = ET.SubElement(
+                        import_image_elem,
+                        'urn:tag')
+                    ET.SubElement(tag_elem,
+                                  'urn:tagKeyName').text = k
+
+                    if v is not None:
+                        ET.SubElement(tag_elem,
+                                      'urn:value').text = v
+
+        response = self.connection.request_with_orgId_api_2(
+            'image/importImage',
+            method='POST',
+            data=ET.tostring(import_image_elem)).object
+
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_list_nodes_paginated(self, name=None, location=None,
+                                ipv6=None, ipv4=None, vlan=None,
+                                image=None, deployed=None, started=None,
+                                state=None, network=None, network_domain=None):
+        """
+        Return a generator which yields node lists in pages
+
+        :keyword location: Filters the node list to nodes that are
+                           located in this location
+        :type    location: :class:`NodeLocation` or ``str``
+
+        :keyword name: Filters the node list to nodes that have this name
+        :type    name ``str``
+
+        :keyword ipv6: Filters the node list to nodes that have this
+                       ipv6 address
+        :type    ipv6: ``str``
+
+        :keyword ipv4: Filters the node list to nodes that have this
+                       ipv4 address
+        :type    ipv4: ``str``
+
+        :keyword vlan: Filters the node list to nodes that are in this VLAN
+        :type    vlan: :class:`NttCisVlan` or ``str``
+
+        :keyword image: Filters the node list to nodes that have this image
+        :type    image: :class:`NodeImage` or ``str``
+
+        :keyword deployed: Filters the node list to nodes that are
+                           deployed or not
+        :type    deployed: ``bool``
+
+        :keyword started: Filters the node list to nodes that are
+                          started or not
+        :type    started: ``bool``
+
+        :keyword state: Filters the node list to nodes that are in
+                        this state
+        :type    state: ``str``
+
+        :keyword network: Filters the node list to nodes in this network
+        :type    network: :class:`NttCisNetwork` or ``str``
+
+        :keyword network_domain: Filters the node list to nodes in this
+                                 network domain
+        :type    network_domain: :class:`NttCisNetworkDomain`
+                                 or ``str``
+
+        :return: a list of `Node` objects
+        :rtype: ``generator`` of `list` of :class:`Node`
+        """
+
+        params = {}
+        if location is not None:
+            params['datacenterId'] = self._location_to_location_id(location)
+        if ipv6 is not None:
+            params['ipv6'] = ipv6
+        if ipv4 is not None:
+            params['privateIpv4'] = ipv4
+        if state is not None:
+            params['state'] = state
+        if started is not None:
+            params['started'] = started
+        if deployed is not None:
+            params['deployed'] = deployed
+        if name is not None:
+            params['name'] = name
+        if network_domain is not None:
+            params['networkDomainId'] = \
+                self._network_domain_to_network_domain_id(network_domain)
+        if network is not None:
+            params['networkId'] = self._network_to_network_id(network)
+        if vlan is not None:
+            params['vlanId'] = self._vlan_to_vlan_id(vlan)
+        if image is not None:
+            params['sourceImageId'] = self._image_to_image_id(image)
+
+        nodes_obj = self._list_nodes_single_page(params)
+        yield self._to_nodes(nodes_obj)
+
+        while nodes_obj.get('pageCount') >= nodes_obj.get('pageSize'):
+            params['pageNumber'] = int(nodes_obj.get('pageNumber')) + 1
+            nodes_obj = self._list_nodes_single_page(params)
+            yield self._to_nodes(nodes_obj)
+
+    def ex_start_node(self, node):
+        """
+        Powers on an existing deployed server
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('startServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/startServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_shutdown_graceful(self, node):
+        """
+        This function will attempt to "gracefully" stop a server by
+        initiating a shutdown sequence within the guest operating system.
+        A successful response on this function means the system has
+        successfully passed the request into the operating system.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('shutdownServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/shutdownServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_power_off(self, node):
+        """
+        This function will abruptly power-off a server.  Unlike
+        ex_shutdown_graceful, success ensures the node will stop but some OS
+        and application configurations may be adversely affected by the
+        equivalent of pulling the power plug out of the machine.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('powerOffServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+
+        try:
+            body = self.connection.request_with_orgId_api_2(
+                'server/powerOffServer',
+                method='POST',
+                data=ET.tostring(request_elm)).object
+            response_code = findtext(body, 'responseCode', TYPES_URN)
+        except (NttCisAPIException, NameError, BaseHTTPError):
+            r = self.ex_get_node_by_id(node.id)
+            response_code = r.state.upper()
+
+        return response_code in ['IN_PROGRESS', 'OK', 'STOPPED', 'STOPPING']
+
+    def ex_reset(self, node):
+        """
+        This function will abruptly reset a server.  Unlike
+        reboot_node, success ensures the node will restart but some OS
+        and application configurations may be adversely affected by the
+        equivalent of pulling the power plug out of the machine.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('resetServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/resetServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_update_vm_tools(self, node):
+        """
+        This function triggers an update of the VMware Tools
+        software running on the guest OS of a Server.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('updateVmwareTools',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/updateVmwareTools',
+            method='POST',
+            data=ET.tostring(request_elm)).object
+        response_code = findtext(body, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_update_node(self, node, name=None, description=None,
+                       cpu_count=None, ram_mb=None):
+        """
+        Update the node, the name, CPU or RAM
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :param      name: The new name (optional)
+        :type       name: ``str``
+
+        :param      description: The new description (optional)
+        :type       description: ``str``
+
+        :param      cpu_count: The new CPU count (optional)
+        :type       cpu_count: ``int``
+
+        :param      ram_mb: The new Memory in MB (optional)
+        :type       ram_mb: ``int``
+
+        :rtype: ``bool``
+        """
+        data = {}
+        if name is not None:
+            data['name'] = name
+        if description is not None:
+            data['description'] = description
+        if cpu_count is not None:
+            data['cpuCount'] = str(cpu_count)
+        if ram_mb is not None:
+            data['memory'] = str(ram_mb)
+        body = self.connection.request_with_orgId_api_1(
+            'server/%s' % (node.id),
+            method='POST',
+            data=urlencode(data, True)).object
+        response_code = findtext(body, 'result', GENERAL_NS)
+        return response_code in ['IN_PROGRESS', 'SUCCESS']
+
+    def ex_create_anti_affinity_rule(self, node_list):
+        """
+        Create an anti affinity rule given a list of nodes
+        Anti affinity rules ensure that servers will not reside
+        on the same VMware ESX host
+
+        :param node_list: The list of nodes to create a rule for
+        :type  node_list: ``list`` of :class:`Node` or
+                          ``list`` of ``str``
+
+        :rtype: ``bool``
+        """
+        if not isinstance(node_list, (list, tuple)):
+            raise TypeError("Node list must be a list or a tuple.")
+        anti_affinity_xml_request = ET.Element('NewAntiAffinityRule',
+                                               {'xmlns': SERVER_NS})
+        for node in node_list:
+            ET.SubElement(anti_affinity_xml_request, 'serverId').text = \
+                self._node_to_node_id(node)
+        result = self.connection.request_with_orgId_api_1(
+            'antiAffinityRule',
+            method='POST',
+            data=ET.tostring(anti_affinity_xml_request)).object
+        response_code = findtext(result, 'result', GENERAL_NS)
+        return response_code in ['IN_PROGRESS', 'SUCCESS']
+
+    def ex_delete_anti_affinity_rule(self, anti_affinity_rule):
+        """
+        Remove anti affinity rule
+
+        :param anti_affinity_rule: The anti affinity rule to delete
+        :type  anti_affinity_rule: :class:`NttCisAntiAffinityRule` or
+                                   ``str``
+
+        :rtype: ``bool``
+        """
+        rule_id = self._anti_affinity_rule_to_anti_affinity_rule_id(
+            anti_affinity_rule)
+        result = self.connection.request_with_orgId_api_1(
+            'antiAffinityRule/%s?delete' % (rule_id),
+            method='GET').object
+        response_code = findtext(result, 'result', GENERAL_NS)
+        return response_code in ['IN_PROGRESS', 'SUCCESS']
+
+    def ex_list_anti_affinity_rules(self, network=None, network_domain=None,
+                                    node=None, filter_id=None,
+                                    filter_state=None):
+        """
+        List anti affinity rules for a network, network domain, or node
+
+        :param network: The network to list anti affinity rules for
+                        One of network, network_domain, or node is required
+        :type  network: :class:`NttCisNetwork` or ``str``
+
+        :param network_domain: The network domain to list anti affinity rules
+                               One of network, network_domain,
+                               or node is required
+        :type  network_domain: :class:`NttCisNetworkDomain` or ``str``
+
+        :param node: The node to list anti affinity rules for
+                     One of network, netwok_domain, or node is required
+        :type  node: :class:`Node` or ``str``
+
+        :param filter_id: This will allow you to filter the rules
+                          by this node id
+        :type  filter_id: ``str``
+
+        :type  filter_state: This will allow you to filter rules by
+                             node state (i.e. NORMAL)
+        :type  filter_state: ``str``
+
+        :rtype: ``list`` of :class:NttCisAntiAffinityRule`
+        """
+        not_none_arguments = [key
+                              for key in (network, network_domain, node)
+                              if key is not None]
+        if len(not_none_arguments) != 1:
+            raise ValueError("One and ONLY one of network, "
+                             "network_domain, or node must be set")
+
+        params = {}
+        if network_domain is not None:
+            params['networkDomainId'] = \
+                self._network_domain_to_network_domain_id(network_domain)
+        if network is not None:
+            params['networkId'] = \
+                self._network_to_network_id(network)
+        if node is not None:
+            params['serverId'] = \
+                self._node_to_node_id(node)
+        if filter_id is not None:
+            params['id'] = filter_id
+        if filter_state is not None:
+            params['state'] = filter_state
+
+        paged_result = self.connection.paginated_request_with_orgId_api_2(
+            'server/antiAffinityRule',
+            method='GET',
+            params=params
+        )
+
+        rules = []
+        for result in paged_result:
+            rules.extend(self._to_anti_affinity_rules(result))
+        return rules
+
+    def ex_attach_node_to_vlan(self, node, vlan=None, private_ipv4=None):
+        """
+        Attach a node to a VLAN by adding an additional NIC to
+        the node on the target VLAN. The IP will be automatically
+        assigned based on the VLAN IP network space. Alternatively, provide
+        a private IPv4 address instead of VLAN information, and this will
+        be assigned to the node on corresponding NIC.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :param      vlan: VLAN to attach the node to
+                          (required unless private_ipv4)
+        :type       vlan: :class:`NttCisVlan`
+
+        :keyword    private_ipv4: Private nic IPv4 Address
+                                  (required unless vlan)
+        :type       private_ipv4: ``str``
+
+        :rtype: ``bool``
+        """
+        request = ET.Element('addNic',
+                             {'xmlns': TYPES_URN})
+        ET.SubElement(request, 'serverId').text = node.id
+        nic = ET.SubElement(request, 'nic')
+
+        if vlan is not None:
+            ET.SubElement(nic, 'vlanId').text = vlan.id
+        elif private_ipv4 is not None:
+            ET.SubElement(nic, 'privateIpv4').text = private_ipv4
+        else:
+            raise ValueError("One of vlan or primary_ipv4 "
+                             "must be specified")
+
+        response = self.connection.request_with_orgId_api_2(
+            'server/addNic',
+            method='POST',
+            data=ET.tostring(request)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_destroy_nic(self, nic_id):
+        """
+        Remove a NIC on a node, removing the node from a VLAN
+
+        :param      nic_id: The identifier of the NIC to remove
+        :type       nic_id: ``str``
+
+        :rtype: ``bool``
+        """
+        request = ET.Element('removeNic',
+                             {'xmlns': TYPES_URN,
+                              'id': nic_id})
+
+        response = self.connection.request_with_orgId_api_2(
+            'server/removeNic',
+            method='POST',
+            data=ET.tostring(request)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_list_networks(self, location=None):
+        """
+        List networks deployed across all data center locations for your
+        organization.  The response includes the location of each network.
+
+        :param location: The target location
+        :type  location: :class:`NodeLocation` or ``str``
+
+        :return: a list of NttCisaNetwork objects
+        :rtype: ``list`` of :class:`NttCisNetwork`
+        """
+        return self.list_networks(location=location)
+
+    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` or ``str``
+
+        :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 `NttCisNetwork`
+        :rtype:  Instance of :class:`NttCisNetwork`
+        """
+        network_location = self._location_to_location_id(location)
+
+        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 = network_location
+
+        self.connection.request_with_orgId_api_1(
+            'networkWithLocation',
+            method='POST',
+            data=ET.tostring(create_node))
+
+        # 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:`NttCisNetwork`
+
+        :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:`NttCisNetwork`
+
+        :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
+
+        :param      network_domain_id: The identifier of the network domain
+        :type       network_domain_id: ``str``
+
+        :rtype: :class:`NttCisNetworkDomain`
+        """
+        locations = self.list_locations()
+        net = self.connection.request_with_orgId_api_2(
+            'network/networkDomain/%s' % network_domain_id).object
+        return self._to_network_domain(net, locations)
+
+    def ex_list_network_domains(self, location=None, name=None,
+                                service_plan=None, state=None):
+        """
+        List networks domains deployed across all data center locations domain.
+
+        for your organization.
+        The response includes the location of each network
+        :param      location: Only network domains in the location (optional)
+        :type       location: :class:`NodeLocation` or ``str``
+
+        :param      name: Only network domains of this name (optional)
+        :type       name: ``str``
+
+        :param      service_plan: Only network domains of this type (optional)
+        :type       service_plan: ``str``
+
+        :param      state: Only network domains in this state (optional)
+        :type       state: ``str``
+
+        :return: a list of `NttCisNetwork` objects
+        :rtype: ``list`` of :class:`NttCisNetwork`
+        """
+        params = {}
+        if location is not None:
+            params['datacenterId'] = self._location_to_location_id(location)
+        if name is not None:
+            params['name'] = name
+        if service_plan is not None:
+            params['type'] = service_plan
+        if state is not None:
+            params['state'] = state
+
+        response = self.connection \
+            .request_with_orgId_api_2('network/networkDomain',
+                                      params=params).object
+        return self._to_network_domains(response)
+
+    def ex_create_network_domain(self, location, name, service_plan,
+                                 description=None):
+        """
+        Deploy a new network domain to a data center
+
+        :param      location: The data center to list
+        :type       location: :class:`NodeLocation` or ``str``
+
+        :param      name: The name of the network domain to create
+        :type       name: ``str``
+
+        :param      service_plan: The service plan, either "ESSENTIALS"
+            or "ADVANCED"
+        :type       service_plan: ``str``
+
+        :param      description: An additional description of
+                                 the network domain
+        :type       description: ``str``
+
+        :return: an instance of `NttCisNetworkDomain`
+        :rtype: :class:`NttCisNetworkDomain`
+        """
+        create_node = ET.Element('deployNetworkDomain', {'xmlns': TYPES_URN})
+        ET.SubElement(
+            create_node,
+            "datacenterId"
+        ).text = self._location_to_location_id(location)
+
+        ET.SubElement(create_node, "name").text = name
+        if description is not None:
+            ET.SubElement(create_node, "description").text = description
+        ET.SubElement(create_node, "type").text = service_plan
+
+        response = self.connection.request_with_orgId_api_2(
+            'network/deployNetworkDomain',
+            method='POST',
+            data=ET.tostring(create_node)).object
+
+        network_domain_id = None
+
+        for info in findall(response, 'info', TYPES_URN):
+            if info.get('name') == 'networkDomainId':
+                network_domain_id = info.get('value')
+
+        return NttCisNetworkDomain(
+            id=network_domain_id,
+            name=name,
+            description=description,
+            location=location,
+            status=NodeState.RUNNING,
+            plan=service_plan
+        )
+
+    def ex_update_network_domain(self, network_domain):
+        """
+        Update the properties of a network domain
+
+        :param      network_domain: The network domain with updated properties
+        :type       network_domain: :class:`NttCisNetworkDomain`
+
+        :return: an instance of `NttCisNetworkDomain`
+        :rtype: :class:`NttCisNetworkDomain`
+        """
+        edit_node = ET.Element('editNetworkDomain', {'xmlns': TYPES_URN})
+        edit_node.set('id', network_domain.id)
+        ET.SubElement(edit_node, "name").text = network_domain.name
+        if network_domain.description is not None:
+            ET.SubElement(edit_node, "description").text \
+                = network_domain.description
+        ET.SubElement(edit_node, "type").text = network_domain.plan
+
+        self.connection.request_with_orgId_api_2(
+            'network/editNetworkDomain',
+            method='POST',
+            data=ET.tostring(edit_node)).object
+
+        return network_domain
+
+    def ex_delete_network_domain(self, network_domain):
+        """
+        Delete a network domain
+
+        :param      network_domain: The network domain to delete
+        :type       network_domain: :class:`NttCisNetworkDomain`
+
+        :rtype: ``bool``
+        """
+        delete_node = ET.Element('deleteNetworkDomain', {'xmlns': TYPES_URN})
+        delete_node.set('id', network_domain.id)
+        result = self.connection.request_with_orgId_api_2(
+            'network/deleteNetworkDomain',
+            method='POST',
+            data=ET.tostring(delete_node)).object
+
+        response_code = findtext(result, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_create_vlan(self,
+                       network_domain,
+                       name,
+                       private_ipv4_base_address,
+                       description=None,
+                       private_ipv4_prefix_size=24):
+        """
+        Deploy a new VLAN to a network domain
+
+        :param      network_domain: The network domain to add the VLAN to
+        :type       network_domain: :class:`NttCisNetworkDomain`
+
+        :param      name: The name of the VLAN to create
+        :type       name: ``str``
+
+        :param      private_ipv4_base_address: The base IPv4 address
+            e.g. 192.168.1.0
+        :type       private_ipv4_base_address: ``str``
+
+        :param      description: An additional description of the VLAN
+        :type       description: ``str``
+
+        :param      private_ipv4_prefix_size: The size of the IPv4
+            address space, e.g 24
+        :type       private_ipv4_prefix_size: ``int``
+
+        :return: an instance of `NttCisVlan`
+        :rtype: :class:`NttCisVlan`
+        """
+        create_node = ET.Element('deployVlan', {'xmlns': TYPES_URN})
+        ET.SubElement(create_node, "networkDomainId").text = network_domain.id
+        ET.SubElement(create_node, "name").text = name
+        if description is not None:
+            ET.SubElement(create_node, "description").text = description
+        ET.SubElement(create_node, "privateIpv4BaseAddress").text = \
+            private_ipv4_base_address
+        ET.SubElement(create_node, "privateIpv4PrefixSize").text = \
+            str(private_ipv4_prefix_size)
+
+        response = self.connection.request_with_orgId_api_2(
+            'network/deployVlan',
+            method='POST',
+            data=ET.tostring(create_node)).object
+
+        vlan_id = None
+
+        for info in findall(response, 'info', TYPES_URN):
+            if info.get('name') == 'vlanId':
+                vlan_id = info.get('value')
+
+        return self.ex_get_vlan(vlan_id)
+
+    def ex_get_vlan(self, vlan_id):
+        """
+        Get a single VLAN, by it's identifier
+
+        :param   vlan_id: The identifier of the VLAN
+        :type    vlan_id: ``str``
+
+        :return: an instance of `NttCisVlan`
+        :rtype: :class:`NttCisVlan`
+        """
+        locations = self.list_locations()
+        vlan = self.connection.request_with_orgId_api_2(
+            'network/vlan/%s' % vlan_id).object
+        return self._to_vlan(vlan, locations)
+
+    def ex_update_vlan(self, vlan):
+        """
+        Updates the properties of the given VLAN
+        Only name and description are updated
+
+        :param      vlan: The VLAN to update
+        :type       vlan: :class:`NttCisetworkDomain`
+
+        :return: an instance of `NttCisVlan`
+        :rtype: :class:`NttCisVlan`
+        """
+        edit_node = ET.Element('editVlan', {'xmlns': TYPES_URN})
+        edit_node.set('id', vlan.id)
+        ET.SubElement(edit_node, "name").text = vlan.name
+        if vlan.description is not None:
+            ET.SubElement(edit_node, "description").text \
+                = vlan.description
+
+        self.connection.request_with_orgId_api_2(
+            'network/editVlan',
+            method='POST',
+            data=ET.tostring(edit_node)).object
+
+        return vlan
+
+    def ex_expand_vlan(self, vlan):
+        """
+        Expands the VLAN to the prefix size in private_ipv4_range_size
+        The expansion will
+        not be permitted if the proposed IP space overlaps with an
+        already deployed VLANs IP space.
+
+        :param      vlan: The VLAN to update
+        :type       vlan: :class:`NttCisNetworkDomain`
+
+        :return: an instance of `NttCisVlan`
+        :rtype: :class:`NttCisVlan`
+        """
+        edit_node = ET.Element('expandVlan', {'xmlns': TYPES_URN})
+        edit_node.set('id', vlan.id)
+        ET.SubElement(edit_node, "privateIpv4PrefixSize").text =\
+            vlan.private_ipv4_range_size
+
+        self.connection.request_with_orgId_api_2(
+            'network/expandVlan',
+            method='POST',
+            data=ET.tostring(edit_node)).object
+
+        return vlan
+
+    def ex_delete_vlan(self, vlan):
+        """
+        Deletes an existing VLAN
+
+        :param      vlan: The VLAN to delete
+        :type       vlan: :class:`DNttCisNetworkDomain`
+
+        :rtype: ``bool``
+        """
+        delete_node = ET.Element('deleteVlan', {'xmlns': TYPES_URN})
+        delete_node.set('id', vlan.id)
+        result = self.connection.request_with_orgId_api_2(
+            'network/deleteVlan',
+            method='POST',
+            data=ET.tostring(delete_node)).object
+
+        response_code = findtext(result, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_list_vlans(self, location=None, network_domain=None, name=None,
+                      ipv4_address=None, ipv6_address=None, state=None):
+        """
+        List VLANs available, can filter by location and/or network domain
+
+        :param      location: Only VLANs in this location (optional)
+        :type       location: :class:`NodeLocation` or ``str``
+
+        :param      network_domain: Only VLANs in this domain (optional)
+        :type       network_domain: :class:`NttCisNetworkDomain`
+
+        :param      name: Only VLANs with this name (optional)
+        :type       name: ``str``
+
+        :param      ipv4_address: Only VLANs with this ipv4 address (optional)
+        :type       ipv4_address: ``str``
+
+        :param      ipv6_address: Only VLANs with this ipv6 address  (optional)
+        :type       ipv6_address: ``str``
+
+        :param      state: Only VLANs with this state (optional)
+        :type       state: ``str``
+
+        :return: a list of NttCisVlan objects
+        :rtype: ``list`` of :class:`NttCisVlan`
+        """
+        params = {}
+        if location is not None:
+            params['datacenterId'] = self._location_to_location_id(location)
+        if network_domain is not None:
+            params['networkDomainId'] = \
+                self._network_domain_to_network_domain_id(network_domain)
+        if name is not None:
+            params['name'] = name
+        if ipv4_address is not None:
+            params['privateIpv4Address'] = ipv4_address
+        if ipv6_address is not None:
+            params['ipv6Address'] = ipv6_address
+        if state is not None:
+            params['state'] = state
+        response = self.connection.request_with_orgId_api_2('network/vlan',
+                                                            params=params) \
+                                  .object
+        return self._to_vlans(response)
+
+    def ex_add_public_ip_block_to_network_domain(self, network_domain):
+        add_node = ET.Element('addPublicIpBlock', {'xmlns': TYPES_URN})
+        ET.SubElement(add_node, "networkDomainId").text =\
+            network_domain.id
+
+        response = self.connection.request_with_orgId_api_2(
+            'network/addPublicIpBlock',
+            method='POST',
+            data=ET.tostring(add_node)).object
+
+        block_id = None
+
+        for info in findall(response, 'info', TYPES_URN):
+            if info.get('name') == 'ipBlockId':
+                block_id = info.get('value')
+        return self.ex_get_public_ip_block(block_id)
+
+    def ex_list_public_ip_blocks(self, network_domain):
+        params = {}
+        params['networkDomainId'] = network_domain.id
+
+        response = self.connection \
+            .request_with_orgId_api_2('network/publicIpBlock',
+                                      params=params).object
+        return self._to_ip_blocks(response)
+
+    def ex_get_public_ip_block(self, block_id):
+        locations = self.list_locations()
+        block = self.connection.request_with_orgId_api_2(
+            'network/publicIpBlock/%s' % block_id).object
+        return self._to_ip_block(block, locations)
+
+    def ex_delete_public_ip_block(self, block):
+        delete_node = ET.Element('removePublicIpBlock', {'xmlns': TYPES_URN})
+        delete_node.set('id', block.id)
+        result = self.connection.request_with_orgId_api_2(
+            'network/removePublicIpBlock',
+            method='POST',
+            data=ET.tostring(delete_node)).object
+
+        response_code = findtext(result, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_get_node_by_id(self, id):
+        node = self.connection.request_with_orgId_api_2(
+            'server/server/%s' % id).object
+        return self._to_node(node)
+
+    def ex_list_firewall_rules(self, network_domain, page_size=50,
+                               page_number=1):
+        params = {'pageSize': page_size, 'pageNumber': page_number}
+        params['networkDomainId'] = self._network_domain_to_network_domain_id(
+            network_domain)
+
+        response = self.connection \
+            .request_with_orgId_api_2('network/firewallRule',
+                                      params=params).object
+        return self._to_firewall_rules(response, network_domain)
+
+    def ex_create_firewall_rule(self, network_domain, rule, position,
+                                position_relative_to_rule=None):
+        """
+        Creates a firewall rule
+
+        :param network_domain: The network domain in which to create
+                                the firewall rule
+        :type  network_domain: :class:`NttCisNetworkDomain` or ``str``
+
+        :param rule: The rule in which to create
+        :type  rule: :class:`NttCisFirewallRule`
+
+        :param position: The position in which to create the rule
+                         There are two types of positions
+                         with position_relative_to_rule arg and without it
+                         With: 'BEFORE' or 'AFTER'
+                         Without: 'FIRST' or 'LAST'
+        :type  position: ``str``
+
+        :param position_relative_to_rule: The rule or rule name in
+                                          which to decide positioning by
+        :type  position_relative_to_rule:
+            :class:`NttCisFirewallRule` or ``str``
+
+        :rtype: ``bool``
+        """
+        positions_without_rule = ('FIRST', 'LAST')
+        positions_with_rule = ('BEFORE', 'AFTER')
+
+        create_node = ET.Element('createFirewallRule', {'xmlns': TYPES_URN})
+        ET.SubElement(create_node, "networkDomainId").text = \
+            self._network_domain_to_network_domain_id(network_domain)
+        ET.SubElement(create_node, "name").text = rule.name
+        ET.SubElement(create_node, "action").text = rule.action
+        ET.SubElement(create_node, "ipVersion").text = rule.ip_version
+        ET.SubElement(create_node, "protocol").text = rule.protocol
+        # Setup source port rule
+        source = ET.SubElement(create_node, "source")
+        if rule.source.address_list_id is not None:
+            source_ip = ET.SubElement(source, 'ipAddressListId')
+            source_ip.text = rule.source.address_list_id
+        else:
+            source_ip = ET.SubElement(source, 'ip')
+            if rule.source.any_ip:
+                source_ip.set('address', 'ANY')
+            else:
+                source_ip.set('address', rule.source.ip_address)
+                if rule.source.ip_prefix_size is not None:
+                    source_ip.set('prefixSize',
+                                  str(rule.source.ip_prefix_size))
+        if rule.source.port_list_id is not None:
+            source_port = ET.SubElement(source, 'portListId')
+            source_port.text = rule.source.port_list_id
+        else:
+            if rule.source.port_begin is not None:
+                source_port = ET.SubElement(source, 'port')
+                source_port.set('begin', rule.source.port_begin)
+            if rule.source.port_end is not None:
+                source_port.set('end', rule.source.port_end)
+        # Setup destination port rule
+        dest = ET.SubElement(create_node, "destination")
+        if rule.destination.address_list_id is not None:
+            dest_ip = ET.SubElement(dest, 'ipAddressListId')
+            dest_ip.text = rule.destination.address_list_id
+        else:
+            dest_ip = ET.SubElement(dest, 'ip')
+            if rule.destination.any_ip:
+                dest_ip.set('address', 'ANY')
+            else:
+                dest_ip.set('address', rule.destination.ip_address)
+                if rule.destination.ip_prefix_size is not None:
+                    dest_ip.set('prefixSize', rule.destination.ip_prefix_size)
+        if rule.destination.port_list_id is not None:
+            dest_port = ET.SubElement(dest, 'portListId')
+            dest_port.text = rule.destination.port_list_id
+        else:
+            if rule.destination.port_begin is not None:
+                dest_port = ET.SubElement(dest, 'port')
+                dest_port.set('begin', rule.destination.port_begin)
+            if rule.destination.port_end is not None:
+                dest_port.set('end', rule.destination.port_end)
+        # Set up positioning of rule
+        ET.SubElement(create_node, "enabled").text = str(rule.enabled).lower()
+        placement = ET.SubElement(create_node, "placement")
+        if position_relative_to_rule is not None:
+            if position not in positions_with_rule:
+                raise ValueError("When position_relative_to_rule is specified"
+                                 " position must be %s"
+                                 % ', '.join(positions_with_rule))
+            if isinstance(position_relative_to_rule,
+                          NttCisFirewallRule):
+                rule_name = position_relative_to_rule.name
+            else:
+                rule_name = position_relative_to_rule
+            placement.set('relativeToRule', rule_name)
+        else:
+            if position not in positions_without_rule:
+                raise ValueError("When position_relative_to_rule is not"
+                                 " specified position must be %s"
+                                 % ', '.join(positions_without_rule))
+        placement.set('position', position)
+
+        response = self.connection.request_with_orgId_api_2(
+            'network/createFirewallRule',
+            method='POST',
+            data=ET.tostring(create_node)).object
+
+        rule_id = None
+        for info in findall(response, 'info', TYPES_URN):
+            if info.get('name') == 'firewallRuleId':
+                rule_id = info.get('value')
+        rule.id = rule_id
+        return rule
+
+    def ex_edit_firewall_rule(self, rule, position,
+                              relative_rule_for_position=None):
+        """
+        Edit a firewall rule
+
+        >>> from pprint import pprint
+        >>> from libcloud.compute.types import Provider
+        >>> from libcloud.compute.providers import get_driver
+        >>> import libcloud.security
+        >>>
+        >>> # Get dimension data driver
+        >>> libcloud.security.VERIFY_SSL_CERT = True
+        >>> cls = get_driver(Provider.DIMENSIONDATA)
+        >>> driver = cls('myusername','mypassword', region='dd-au')
+        >>>
+        >>> # Get location
+        >>> location = driver.ex_get_location_by_id(id='AU9')
+        >>>
+        >>> # Get network domain by location
+        >>> networkDomainName = "Baas QA"
+        >>> network_domains = driver.ex_list_network_domains(location=location)
+        >>> my_network_domain = [d for d in network_domains if d.name ==
+                              networkDomainName][0]
+        >>>
+        >>>
+        >>> # List firewall rules
+        >>> firewall_rules = driver.ex_list_firewall_rules(my_network_domain)
+        >>>
+        >>> # Get Firewall Rule by name
+        >>> pprint("List specific firewall rule by name")
+        >>> fire_rule_under_test = (list(filter(lambda x: x.name ==
+                                   'My_New_Firewall_Rule', firewall_rules))[0])
+        >>> pprint(fire_rule_under_test.source)
+        >>> pprint(fire_rule_under_test.destination)
+        >>>
+        >>> # Edit Firewall
+        >>> fire_rule_under_test.destination.address_list_id =
+                '5e7c323f-c885-4e4b-9a27-94c44217dbd3'
+        >>> fire_rule_under_test.destination.port_list_id =
+                'b6557c5a-45fa-4138-89bd-8fe68392691b'
+        >>> result = driver.ex_edit_firewall_rule(fire_rule_under_test, 'LAST')
+        >>> pprint(result)
+
+        :param rule: (required) The rule in which to create
+        :type  rule: :class:`DNttCisFirewallRule`
+
+        :param position: (required) There are two types of positions
+                         with position_relative_to_rule arg and without it
+                         With: 'BEFORE' or 'AFTER'
+                         Without: 'FIRST' or 'LAST'
+        :type  position: ``str``
+
+        :param relative_rule_for_position: (optional) The rule or rule name in
+                                           which to decide the relative rule
+                                           for positioning.
+        :type  relative_rule_for_position:
+            :class:`NttCisFirewallRule` or ``str``
+
+        :rtype: ``bool``
+        """
+
+        positions_without_rule = ('FIRST', 'LAST')
+        positions_with_rule = ('BEFORE', 'AFTER')
+
+        edit_node = ET.Element('editFirewallRule',
+                               {'xmlns': TYPES_URN, 'id': rule.id})
+        ET.SubElement(edit_node, "action").text = rule.action
+        ET.SubElement(edit_node, "protocol").text = rule.protocol
+
+        # Source address
+        source = ET.SubElement(edit_node, "source")
+        if rule.source.address_list_id is not None:
+            source_ip = ET.SubElement(source, 'ipAddressListId')
+            source_ip.text = rule.source.address_list_id
+        else:
+            source_ip = ET.SubElement(source, 'ip')
+            if rule.source.any_ip:
+                source_ip.set('address', 'ANY')
+            else:
+                source_ip.set('address', rule.source.ip_address)
+                if rule.source.ip_prefix_size is not None:
+                    source_ip.set('prefixSize',
+                                  str(rule.source.ip_prefix_size))
+
+        # Setup source port rule
+        if rule.source.port_list_id is not None:
+            source_port = ET.SubElement(source, 'portListId')
+            source_port.text = rule.source.port_list_id
+        else:
+            if rule.source.port_begin is not None:
+                source_port = ET.SubElement(source, 'port')
+                source_port.set('begin', rule.source.port_begin)
+            if rule.source.port_end is not None:
+                source_port.set('end', rule.source.port_end)
+        # Setup destination port rule
+        dest = ET.SubElement(edit_node, "destination")
+        if rule.destination.address_list_id is not None:
+            dest_ip = ET.SubElement(dest, 'ipAddressListId')
+            dest_ip.text = rule.destination.address_list_id
+        else:
+            dest_ip = ET.SubElement(dest, 'ip')
+            if rule.destination.any_ip:
+                dest_ip.set('address', 'ANY')
+            else:
+                dest_ip.set('address', rule.destination.ip_address)
+                if rule.destination.ip_prefix_size is not None:
+                    dest_ip.set('prefixSize', rule.destination.ip_prefix_size)
+        if rule.destination.port_list_id is not None:
+            dest_port = ET.SubElement(dest, 'portListId')
+            dest_port.text = rule.destination.port_list_id
+        else:
+            if rule.destination.port_begin is not None:
+                dest_port = ET.SubElement(dest, 'port')
+                dest_port.set('begin', rule.destination.port_begin)
+            if rule.destination.port_end is not None:
+                dest_port.set('end', rule.destination.port_end)
+        # Set up positioning of rule
+        ET.SubElement(edit_node, "enabled").text = str(rule.enabled).lower()
+        placement = ET.SubElement(edit_node, "placement")
+        if relative_rule_for_position is not None:
+            if position not in positions_with_rule:
+                raise ValueError("When position_relative_to_rule is specified"
+                                 " position must be %s"
+                                 % ', '.join(positions_with_rule))
+            if isinstance(relative_rule_for_position,
+                          NttCisFirewallRule):
+                rule_name = relative_rule_for_position.name
+            else:
+                rule_name = relative_rule_for_position
+            placement.set('relativeToRule', rule_name)
+        else:
+            if position not in positions_without_rule:
+                raise ValueError("When position_relative_to_rule is not"
+                                 " specified position must be %s"
+                                 % ', '.join(positions_without_rule))
+        placement.set('position', position)
+
+        response = self.connection.request_with_orgId_api_2(
+            'network/editFirewallRule',
+            method='POST',
+            data=ET.tostring(edit_node)).object
+
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def ex_get_firewall_rule(self, network_domain, rule_id):
+        locations = self.list_locations()
+        rule = self.connection.request_with_orgId_api_2(
+            'network/firewallRule/%s' % rule_id).object
+        return self._to_firewall_rule(rule, locations, network_domain)
+
+    def ex_set_firewall_rule_state(self, rule, state):
+        """
+        Change the state (enabled or disabled) of a rule
+
+        :param rule: The rule to delete
+        :type  rule: :class:`NttCisFirewallRule`
+
+        :param state: The desired state enabled (True) or disabled (False)
+        :type  state: ``bool``
+
+        :rtype: ``bool``
+        """
+        update_node = ET.Element('editFirewallRule', {'xmlns': TYPES_URN})
+        update_node.set('id', rule.id)
+        ET.SubElement(update_node, 'enabled').text = str(state).lower()
+        result = self.connection.request_with_orgId_api_2(
+            'network/editFirewallRule',
+            method='POST',
+            data=ET.tostring(update_node)).object
+
+        response_code = findtext(result, 'responseCode', TYPES_URN)
+        return 

<TRUNCATED>

Reply via email to