You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2016/11/14 23:51:17 UTC
[30/56] [abbrv] libcloud git commit: Removed sdist
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/dimensiondata.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/dimensiondata.py
deleted file mode 100644
index 19a3856..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/dimensiondata.py
+++ /dev/null
@@ -1,2311 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
-Dimension Data Driver
-"""
-
-try:
- from lxml import etree as ET
-except ImportError:
- from xml.etree import ElementTree as ET
-
-from libcloud.compute.base import NodeDriver, Node, NodeAuthPassword
-from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
-from libcloud.common.dimensiondata import dd_object_to_id
-from libcloud.common.dimensiondata import DimensionDataAPIException
-from libcloud.common.dimensiondata import (DimensionDataConnection,
- DimensionDataStatus)
-from libcloud.common.dimensiondata import DimensionDataNetwork
-from libcloud.common.dimensiondata import DimensionDataNetworkDomain
-from libcloud.common.dimensiondata import DimensionDataVlan
-from libcloud.common.dimensiondata import DimensionDataServerCpuSpecification
-from libcloud.common.dimensiondata import DimensionDataServerDisk
-from libcloud.common.dimensiondata import DimensionDataServerVMWareTools
-from libcloud.common.dimensiondata import DimensionDataPublicIpBlock
-from libcloud.common.dimensiondata import DimensionDataFirewallRule
-from libcloud.common.dimensiondata import DimensionDataFirewallAddress
-from libcloud.common.dimensiondata import DimensionDataNatRule
-from libcloud.common.dimensiondata import DimensionDataAntiAffinityRule
-from libcloud.common.dimensiondata import NetworkDomainServicePlan
-from libcloud.common.dimensiondata import API_ENDPOINTS, DEFAULT_REGION
-from libcloud.common.dimensiondata import TYPES_URN
-from libcloud.common.dimensiondata import SERVER_NS, NETWORK_NS, GENERAL_NS
-from libcloud.utils.py3 import urlencode
-from libcloud.utils.xml import fixxpath, findtext, findall
-from libcloud.utils.py3 import basestring
-from libcloud.compute.types import NodeState, Provider
-
-# 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', 'true', None):
- NodeState.RUNNING,
- ('NORMAL', 'false', None):
- NodeState.STOPPED,
- ('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,
-}
-
-
-class DimensionDataNodeDriver(NodeDriver):
- """
- DimensionData node driver.
- """
-
- selected_region = None
- connectionCls = DimensionDataConnection
- 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:
- raise ValueError('Invalid region: %s' % (region))
-
- self.selected_region = API_ENDPOINTS[region]
-
- super(DimensionDataNodeDriver, 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(DimensionDataNodeDriver,
- self)._ex_connection_class_kwargs()
- kwargs['region'] = self.selected_region
- return kwargs
-
- def create_node(self, name, image, auth, ex_description,
- ex_network=None, ex_network_domain=None,
- ex_vlan=None, ex_primary_ipv4=None,
- ex_memory_gb=None,
- ex_cpu_specification=None,
- ex_is_started=True, ex_additional_nics_vlan=None,
- ex_additional_nics_ipv4=None, **kwargs):
- """
- Create a new DimensionData 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:`DimensionDataNetwork` or ``str``
-
- :keyword ex_network_domain: Network Domain to create the node
- (required unless using network
- or ex_primary_ipv4)
- :type ex_network_domain: :class:`DimensionDataNetworkDomain`
- or ``str``
-
- :keyword ex_primary_ipv4: Primary nics IPv4 Address
- MCP1: (required unless ex_network)
- MCP2: (required unless ex_vlan)
- :type ex_primary_ipv4: ``str``
-
- :keyword ex_vlan: VLAN to create the node within
- (required unless using network)
- :type ex_vlan: :class:`DimensionDataVlan` 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_additional_nics_vlan: (MCP2 Only) List of additional
- nics to add by vlan
- :type ex_additional_nics_vlan: ``list`` of
- :class:`DimensionDataVlan` or ``list`` of ``str``
-
- :keyword ex_additional_nics_ipv4: (MCP2 Only) List of additional
- nics to add by ipv4 address
- :type ex_additional_nics_ipv4: ``list`` of ``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
-
- if (ex_network_domain is None and
- ex_network is None and
- ex_primary_ipv4 is None):
- raise ValueError("One of ex_network_domain, ex_network, "
- "or ex_ipv6_primary must be specified")
-
- 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
- elif ex_network_domain is None and ex_primary_ipv4 is not None:
- network_elm = ET.SubElement(server_elm, "network")
- ET.SubElement(network_elm, "privateIpv4").text = ex_primary_ipv4
- elif ex_network_domain is not None:
- net_domain_id = self._network_domain_to_network_domain_id(
- ex_network_domain)
- network_inf_elm = ET.SubElement(
- server_elm, "networkInfo",
- {'networkDomainId': net_domain_id}
- )
-
- if ex_vlan is not None:
- vlan_id = self._vlan_to_vlan_id(ex_vlan)
- pri_nic = ET.SubElement(network_inf_elm, "primaryNic")
- ET.SubElement(pri_nic, "vlanId").text = vlan_id
- elif ex_primary_ipv4 is not None:
- pri_nic = ET.SubElement(network_inf_elm, "primaryNic")
- ET.SubElement(pri_nic, "privateIpv4").text = ex_primary_ipv4
- else:
- raise ValueError("One of ex_vlan or ex_primary_ipv4 "
- "must be specified")
-
- if isinstance(ex_additional_nics_ipv4, (list, tuple)):
- for ipv4_nic in ex_additional_nics_ipv4:
- add_nic = ET.SubElement(network_inf_elm, "additionalNic")
- ET.SubElement(add_nic, "privateIpv4").text = ipv4_nic
- elif ex_additional_nics_ipv4 is not None:
- raise TypeError("ex_additional_nics_ipv4 must "
- "be None or a tuple/list")
-
- if isinstance(ex_additional_nics_vlan, (list, tuple)):
- for vlan_nic in ex_additional_nics_vlan:
- add_nic = ET.SubElement(network_inf_elm, "additionalNic")
- ET.SubElement(add_nic, "vlanId").text = vlan_nic
- elif ex_additional_nics_vlan is not None:
- raise TypeError("ex_additional_nics_vlan"
- "must be None or tuple/list")
-
- 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 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:`DimensionDataNetwork` or ``str``
-
- :keyword ex_network_domain: Filters the node list to nodes in this
- network domain
- :type ex_network_domain: :class:`DimensionDataNetworkDomain`
- 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 DimensionData. Customer images (snapshots)
- are not yet supported.
-
- :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 DimensionDataNetwork objects
- :rtype: ``list`` of :class:`DimensionDataNetwork`
- """
- 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 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:`DimensionDataVlan` 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:`DimensionDataNetwork` or ``str``
-
- :keyword network_domain: Filters the node list to nodes in this
- network domain
- :type network_domain: :class:`DimensionDataNetworkDomain`
- 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})
- 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)
- return response_code in ['IN_PROGRESS', 'OK']
-
- 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:`DimensionDataAntiAffinityRule` 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:`DimensionDataNetwork` 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:`DimensionDataNetworkDomain` 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:`DimensionDataAntiAffinityRule`
- """
- 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:`DimensionDataVlan`
-
- :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 DimensionDataNetwork objects
- :rtype: ``list`` of :class:`DimensionDataNetwork`
- """
- 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 `DimensionDataNetwork`
- :rtype: Instance of :class:`DimensionDataNetwork`
- """
- 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:`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
-
- :param network_domain_id: The identifier of the network domain
- :type network_domain_id: ``str``
-
- :rtype: :class:`DimensionDataNetworkDomain`
- """
- 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
- for your organization.
- The response includes the location of each network domain.
-
- :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 `DimensionDataNetwork` objects
- :rtype: ``list`` of :class:`DimensionDataNetwork`
- """
- 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 `DimensionDataNetworkDomain`
- :rtype: :class:`DimensionDataNetworkDomain`
- """
- 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 DimensionDataNetworkDomain(
- 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:`DimensionDataNetworkDomain`
-
- :return: an instance of `DimensionDataNetworkDomain`
- :rtype: :class:`DimensionDataNetworkDomain`
- """
- 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:`DimensionDataNetworkDomain`
-
- :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:`DimensionDataNetworkDomain`
-
- :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 `DimensionDataVlan`
- :rtype: :class:`DimensionDataVlan`
- """
- 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 `DimensionDataVlan`
- :rtype: :class:`DimensionDataVlan`
- """
- 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:`DimensionDataNetworkDomain`
-
- :return: an instance of `DimensionDataVlan`
- :rtype: :class:`DimensionDataVlan`
- """
- 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:`DimensionDataNetworkDomain`
-
- :return: an instance of `DimensionDataVlan`
- :rtype: :class:`DimensionDataVlan`
- """
- 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:`DimensionDataNetworkDomain`
-
- :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:`DimensionDataNetworkDomain`
-
- :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 DimensionDataVlan objects
- :rtype: ``list`` of :class:`DimensionDataVlan`
- """
- 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:`DimensionDataNetworkDomain` or ``str``
-
- :param rule: The rule in which to create
- :type rule: :class:`DimensionDataFirewallRule`
-
- :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:`DimensionDataFirewallRule` 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")
- 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_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")
- 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_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,
- DimensionDataFirewallRule):
- 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_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:`DimensionDataFirewallRule`
-
- :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 response_code in ['IN_PROGRESS', 'OK']
-
- def ex_delete_firewall_rule(self, rule):
- """
- Delete a firewall rule
-
- :param rule: The rule to delete
- :type rule: :class:`DimensionDataFirewallRule`
-
- :rtype: ``bool``
- """
- update_node = ET.Element('deleteFirewallRule', {'xmlns': TYPES_URN})
- update_node.set('id', rule.id)
- result = self.connection.request_with_orgId_api_2(
- 'network/deleteFirewallRule',
- method='POST',
- data=ET.tostring(update_node)).object
-
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_create_nat_rule(self, network_domain, internal_ip, external_ip):
- """
- Create a NAT rule
-
- :param network_domain: The network domain the rule belongs to
- :type network_domain: :class:`DimensionDataNetworkDomain`
-
- :param internal_ip: The IPv4 address internally
- :type internal_ip: ``str``
-
- :param external_ip: The IPv4 address externally
- :type external_ip: ``str``
-
- :rtype: :class:`DimensionDataNatRule`
- """
- create_node = ET.Element('createNatRule', {'xmlns': TYPES_URN})
- ET.SubElement(create_node, 'networkDomainId').text = network_domain.id
- ET.SubElement(create_node, 'internalIp').text = internal_ip
- ET.SubElement(create_node, 'externalIp').text = external_ip
- result = self.connection.request_with_orgId_api_2(
- 'network/createNatRule',
- method='POST',
- data=ET.tostring(create_node)).object
-
- rule_id = None
- for info in findall(result, 'info', TYPES_URN):
- if info.get('name') == 'natRuleId':
- rule_id = info.get('value')
-
- return DimensionDataNatRule(
- id=rule_id,
- network_domain=network_domain,
- internal_ip=internal_ip,
- external_ip=external_ip,
- status=NodeState.RUNNING
- )
-
- def ex_list_nat_rules(self, network_domain):
- """
- Get NAT rules for the network domain
-
- :param network_domain: The network domain the rules belongs to
- :type network_domain: :class:`DimensionDataNetworkDomain`
-
- :rtype: ``list`` of :class:`DimensionDataNatRule`
- """
- params = {}
- params['networkDomainId'] = network_domain.id
-
- response = self.connection \
- .request_with_orgId_api_2('network/natRule',
- params=params).object
- return self._to_nat_rules(response, network_domain)
-
- def ex_get_nat_rule(self, network_domain, rule_id):
- """
- Get a NAT rule by ID
-
- :param network_domain: The network domain the rule belongs to
- :type network_domain: :class:`DimensionDataNetworkDomain`
-
- :param rule_id: The ID of the NAT rule to fetch
- :type rule_id: ``str``
-
- :rtype: :class:`DimensionDataNatRule`
- """
- rule = self.connection.request_with_orgId_api_2(
- 'network/natRule/%s' % rule_id).object
- return self._to_nat_rule(rule, network_domain)
-
- def ex_delete_nat_rule(self, rule):
- """
- Delete an existing NAT rule
-
- :param rule: The rule to delete
- :type rule: :class:`DimensionDataNatRule`
-
- :rtype: ``bool``
- """
- update_node = ET.Element('deleteNatRule', {'xmlns': TYPES_URN})
- update_node.set('id', rule.id)
- result = self.connection.request_with_orgId_api_2(
- 'network/deleteNatRule',
- method='POST',
- data=ET.tostring(update_node)).object
-
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_get_location_by_id(self, id):
- """
- Get location by ID.
-
- :param id: ID of the node location which should be used
- :type id: ``str``
-
- :rtype: :class:`NodeLocation`
- """
- location = None
- if id is not None:
- location = self.list_locations(ex_id=id)[0]
- return location
-
- def ex_wait_for_state(self, state, func, poll_interval=2,
- timeout=60, *args, **kwargs):
- """
- Wait for the function which returns a instance
- with field status to match
-
- Keep polling func until one of the desired states is matched
-
- :param state: Either the desired state (`str`) or a `list` of states
- :type state: ``str`` or ``list``
-
- :param func: The function to call, e.g. ex_get_vlan
- :type func: ``function``
-
- :param poll_interval: The number of seconds to wait between checks
- :type poll_interval: `int`
-
- :param timeout: The total number of seconds to wait to reach a state
- :type timeout: `int`
-
- :param args: The arguments for func
- :type args: Positional arguments
-
- :param kwargs: The arguments for func
- :type kwargs: Keyword arguments
- """
- return self.connection.wait_for_state(state, func, poll_interval,
- timeout, *args, **kwargs)
-
- def ex_enable_monitoring(self, node, service_plan="ESSENTIALS"):
- """
- Enables cloud monitoring on a node
-
- :param node: The node to monitor
- :type node: :class:`Node`
-
- :param service_plan: The service plan, one of ESSENTIALS or
- ADVANCED
- :type service_plan: ``str``
-
- :rtype: ``bool``
- """
- update_node = ET.Element('enableServerMonitoring',
- {'xmlns': TYPES_URN})
- update_node.set('id', node.id)
- ET.SubElement(update_node, 'servicePlan').text = service_plan
- result = self.connection.request_with_orgId_api_2(
- 'server/enableServerMonitoring',
- method='POST',
- data=ET.tostring(update_node)).object
-
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_update_monitoring_plan(self, node, service_plan="ESSENTIALS"):
- """
- Updates the service plan on a node with monitoring
-
- :param node: The node to monitor
- :type node: :class:`Node`
-
- :param service_plan: The service plan, one of ESSENTIALS or
- ADVANCED
- :type service_plan: ``str``
-
- :rtype: ``bool``
- """
- update_node = ET.Element('changeServerMonitoringPlan',
- {'xmlns': TYPES_URN})
- update_node.set('id', node.id)
- ET.SubElement(update_node, 'servicePlan').text = service_plan
- result = self.connection.request_with_orgId_api_2(
- 'server/changeServerMonitoringPlan',
- method='POST',
- data=ET.tostring(update_node)).object
-
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_disable_monitoring(self, node):
- """
- Disables cloud monitoring for a node
-
- :param node: The node to stop monitoring
- :type node: :class:`Node`
-
- :rtype: ``bool``
- """
- update_node = ET.Element('disableServerMonitoring',
- {'xmlns': TYPES_URN})
- update_node.set('id', node.id)
- result = self.connection.request_with_orgId_api_2(
- 'server/disableServerMonitoring',
- method='POST',
- data=ET.tostring(update_node)).object
-
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_add_storage_to_node(self, node, amount, speed='STANDARD'):
- """
- Add storage to the node
-
- :param node: The server to add storage to
- :type node: :class:`Node`
-
- :param amount: The amount of storage to add, in GB
- :type amount: ``int``
-
- :param speed: The disk speed type
- :type speed: ``str``
-
- :rtype: ``bool``
- """
- result = self.connection.request_with_orgId_api_1(
- 'server/%s?addLocalStorage&amount=%s&speed=%s' %
- (node.id, amount, speed)).object
- response_code = findtext(result, 'result', GENERAL_NS)
- return response_code in ['IN_PROGRESS', 'SUCCESS']
-
- def ex_remove_storage_from_node(self, node, disk_id):
- """
- Remove storage from a node
-
- :param node: The server to add storage to
- :type node: :class:`Node`
-
- :param disk_id: The ID of the disk to remove
- :type disk_id: ``str``
-
- :rtype: ``bool``
- """
- result = self.connection.request_with_orgId_api_1(
- 'server/%s/disk/%s?delete' %
- (node.id, disk_id)).object
- response_code = findtext(result, 'result', GENERAL_NS)
- return response_code in ['IN_PROGRESS', 'SUCCESS']
-
- def ex_change_storage_speed(self, node, disk_id, speed):
- """
- Change the speed (disk tier) of a disk
-
- :param node: The server to change the disk speed of
- :type node: :class:`Node`
-
- :param disk_id: The ID of the disk to change
- :type disk_id: ``str``
-
- :param speed: The disk speed type e.g. STANDARD
- :type speed: ``str``
-
- :rtype: ``bool``
- """
- create_node = ET.Element('ChangeDiskSpeed', {'xmlns': SERVER_NS})
- ET.SubElement(create_node, 'speed').text = speed
- result = self.connection.request_with_orgId_api_1(
- 'server/%s/disk/%s/changeSpeed' %
- (node.id, disk_id),
- method='POST',
- data=ET.tostring(create_node)).object
- response_code = findtext(result, 'result', GENERAL_NS)
- return response_code in ['IN_PROGRESS', 'SUCCESS']
-
- def ex_change_storage_size(self, node, disk_id, size):
- """
- Change the size of a disk
-
- :param node: The server to change the disk of
- :type node: :class:`Node`
-
- :param disk_id: The ID of the disk to resize
- :type disk_id: ``str``
-
- :param size: The disk size in GB
- :type size: ``int``
-
- :rtype: ``bool``
- """
- create_node = ET.Element('ChangeDiskSize', {'xmlns': SERVER_NS})
- ET.SubElement(create_node, 'newSizeGb').text = str(size)
- result = self.connection.request_with_orgId_api_1(
- 'server/%s/disk/%s/changeSize' %
- (node.id, disk_id),
- method='POST',
- data=ET.tostring(create_node)).object
- response_code = findtext(result, 'result', GENERAL_NS)
- return response_code in ['IN_PROGRESS', 'SUCCESS']
-
- def ex_reconfigure_node(self, node, memory_gb, cpu_count, cores_per_socket,
- cpu_performance):
- """
- Reconfigure the virtual hardware specification of a node
-
- :param node: The server to change
- :type node: :class:`Node`
-
- :param memory_gb: The amount of memory in GB (optional)
- :type memory_gb: ``int``
-
- :param cpu_count: The number of CPU (optional)
- :type cpu_count: ``int``
-
- :param cores_per_socket: Number of CPU cores per socket (optional)
- :type cores_per_socket: ``int``
-
- :param cpu_performance: CPU Performance type (optional)
- :type cpu_performance: ``str``
-
- :rtype: ``bool``
- """
- update = ET.Element('reconfigureServer', {'xmlns': TYPES_URN})
- update.set('id', node.id)
- if memory_gb is not None:
- ET.SubElement(update, 'memoryGb').text = str(memory_gb)
- if cpu_count is not None:
- ET.SubElement(update, 'cpuCount').text = str(cpu_count)
- if cpu_performance is not None:
- ET.SubElement(update, 'cpuSpeed').text = cpu_performance
- if cores_per_socket is not None:
- ET.SubElement(update, 'coresPerSocket').text = \
- str(cores_per_socket)
- result = self.connection.request_with_orgId_api_2(
- 'server/reconfigureServer',
- method='POST',
- data=ET.tostring(update)).object
- response_code = findtext(result, 'responseCode', TYPES_URN)
- return response_code in ['IN_PROGRESS', 'OK']
-
- def ex_clone_node_to_image(self, node, image_name, image_description=None):
- """
- Clone a server into a customer image.
-
- :param node: The server to clone
- :type node: :class:`Node`
-
- :param image_name: The name of the clone image
- :type image_name: ``str``
-
- :param description: The description of the image
- :type description: ``str``
-
- :rtype: ``bool``
- """
- if image_description is None:
- image_description = ''
- result = self.connection.request_with_orgId_api_1(
- 'server/%s?clone=%s&desc=%s' %
- (node.id, image_name, image_description)).object
- response_code = findtext(result, 'result', GENERAL_NS)
- return response_code in ['IN_PROGRESS', 'SUCCESS']
-
- def ex_list_customer_images(self, location=None):
- """
- Return a list of customer imported images
-
- :param location: The target location
- :type location: :class:`NodeLocation` or ``str``
-
- :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/customerImage',
- params=params)
- .object, 'customerImage')
-
- def ex_get_base_image_by_id(self, id):
- """
- Gets a Base image in the Dimension Data Cloud given the id
-
- :param id: The id of the image
- :type id: ``str``
-
- :rtype: :class:`NodeImage`
- """
- image = self.connection.request_with_orgId_api_2(
- 'image/osImage/%s' % id).object
- return self._to_image(image)
-
- def ex_get_customer_image_by_id(self, id):
- """
- Gets a Customer image in the Dimension Data Cloud given the id
-
- :param id: The id of the image
- :type id: ``str``
-
- :rtype: :class:`NodeImage`
- """
- image = self.connection.request_with_orgId_api_2(
- 'image/customerImage/%s' % id).object
- return self._to_image(image)
-
- def ex_get_image_by_id(self, id):
- """
- Gets a Base/Customer image in the Dimension Data Cloud given the id
-
- Note: This first checks the base image
- If it is not a base image we check if it is a customer image
- If it is not in either of these a DimensionDataAPIException
- is thrown
-
- :param id: The id of the image
- :type id: ``str``
-
- :rtype: :class:`NodeImage`
- """
- try:
- return self.ex_get_base_image_by_id(id)
- except DimensionDataAPIException as e:
- if e.code != 'RESOURCE_NOT_FOUND':
- raise e
- return self.ex_get_customer_image_by_id(id)
-
- def _list_nodes_single_page(self, params={}):
- return self.connection.request_with_orgId_api_2(
- 'server/server', params=params).object
-
- def _to_images(self, object, el_name='osImage'):
- images = []
- locations = self.list_locations()
-
- for element in object.findall(fixxpath(el_name, TYPES_URN)):
- images.append(self._to_image(element, locations))
-
- return images
-
- def _to_image(self, element, locations=None):
- location_id = element.get('datacenterId')
- if locations is None:
- locations = self.list_locations(location_id)
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
- cpu_spec = self._to_cpu_spec(element.find(fixxpath('cpu', TYPES_URN)))
- os_el = element.find(fixxpath('operatingSystem', TYPES_URN))
- if element.tag.endswith('customerImage'):
- is_customer_image = True
- else:
- is_customer_image = False
- extra = {
- 'description': findtext(element, 'description', TYPES_URN),
- 'OS_type': os_el.get('family'),
- 'OS_displayName': os_el.get('displayName'),
- 'cpu': cpu_spec,
- 'memoryGb': findtext(element, 'memoryGb', TYPES_URN),
- 'osImageKey': findtext(element, 'osImageKey', TYPES_URN),
- 'created': findtext(element, 'createTime', TYPES_URN),
- 'location': location,
- 'isCustomerImage': is_customer_image
- }
-
- return NodeImage(id=element.get('id'),
- name=str(findtext(element, 'name', TYPES_URN)),
- extra=extra,
- driver=self.connection.driver)
-
- def _to_nat_rules(self, object, network_domain):
- rules = []
- for element in findall(object, 'natRule', TYPES_URN):
- rules.append(
- self._to_nat_rule(element, network_domain))
-
- return rules
-
- def _to_nat_rule(self, element, network_domain):
- return DimensionDataNatRule(
- id=element.get('id'),
- network_domain=network_domain,
- internal_ip=findtext(element, 'internalIp', TYPES_URN),
- external_ip=findtext(element, 'externalIp', TYPES_URN),
- status=findtext(element, 'state', TYPES_URN))
-
- def _to_anti_affinity_rules(self, object):
- rules = []
- for element in findall(object, 'antiAffinityRule', TYPES_URN):
- rules.append(
- self._to_anti_affinity_rule(element))
- return rules
-
- def _to_anti_affinity_rule(self, element):
- node_list = []
- for node in findall(element, 'serverSummary', TYPES_URN):
- node_list.append(node.get('id'))
- return DimensionDataAntiAffinityRule(
- id=element.get('id'),
- node_list=node_list
- )
-
- def _to_firewall_rules(self, object, network_domain):
- rules = []
- locations = self.list_locations()
- for element in findall(object, 'firewallRule', TYPES_URN):
- rules.append(
- self._to_firewall_rule(element, locations, network_domain))
-
- return rules
-
- def _to_firewall_rule(self, element, locations, network_domain):
- location_id = element.get('datacenterId')
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
-
- return DimensionDataFirewallRule(
- id=element.get('id'),
- network_domain=network_domain,
- name=findtext(element, 'name', TYPES_URN),
- action=findtext(element, 'action', TYPES_URN),
- ip_version=findtext(element, 'ipVersion', TYPES_URN),
- protocol=findtext(element, 'protocol', TYPES_URN),
- enabled=findtext(element, 'enabled', TYPES_URN),
- source=self._to_firewall_address(
- element.find(fixxpath('source', TYPES_URN))),
- destination=self._to_firewall_address(
- element.find(fixxpath('destination', TYPES_URN))),
- location=location,
- status=findtext(element, 'state', TYPES_URN))
-
- def _to_firewall_address(self, element):
- ip = element.find(fixxpath('ip', TYPES_URN))
- port = element.find(fixxpath('port', TYPES_URN))
- return DimensionDataFirewallAddress(
- any_ip=ip.get('address') == 'ANY',
- ip_address=ip.get('address'),
- ip_prefix_size=ip.get('prefixSize'),
- port_begin=port.get('begin') if port is not None else None,
- port_end=port.get('end') if port is not None else None
- )
-
- def _to_ip_blocks(self, object):
- blocks = []
- locations = self.list_locations()
- for element in findall(object, 'publicIpBlock', TYPES_URN):
- blocks.append(self._to_ip_block(element, locations))
-
- return blocks
-
- def _to_ip_block(self, element, locations):
- location_id = element.get('datacenterId')
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
-
- return DimensionDataPublicIpBlock(
- id=element.get('id'),
- network_domain=self.ex_get_network_domain(
- findtext(element, 'networkDomainId', TYPES_URN)
- ),
- base_ip=findtext(element, 'baseIp', TYPES_URN),
- size=findtext(element, 'size', TYPES_URN),
- location=location,
- status=findtext(element, 'state', TYPES_URN))
-
- def _to_networks(self, object):
- networks = []
- locations = self.list_locations()
- for element in findall(object, 'network', NETWORK_NS):
- networks.append(self._to_network(element, locations))
-
- return networks
-
- def _to_network(self, element, locations):
- multicast = False
- if findtext(element, 'multicast', NETWORK_NS) == 'true':
- multicast = True
-
- status = self._to_status(element.find(fixxpath('status', NETWORK_NS)))
-
- location_id = findtext(element, 'location', NETWORK_NS)
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
-
- return DimensionDataNetwork(
- id=findtext(element, 'id', NETWORK_NS),
- name=findtext(element, 'name', NETWORK_NS),
- description=findtext(element, 'description',
- NETWORK_NS),
- location=location,
- private_net=findtext(element, 'privateNet',
- NETWORK_NS),
- multicast=multicast,
- status=status)
-
- def _to_network_domains(self, object):
- network_domains = []
- locations = self.list_locations()
- for element in findall(object, 'networkDomain', TYPES_URN):
- network_domains.append(self._to_network_domain(element, locations))
-
- return network_domains
-
- def _to_network_domain(self, element, locations):
- location_id = element.get('datacenterId')
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
- plan = findtext(element, 'type', TYPES_URN)
- if plan is 'ESSENTIALS':
- plan_type = NetworkDomainServicePlan.ESSENTIALS
- else:
- plan_type = NetworkDomainServicePlan.ADVANCED
- return DimensionDataNetworkDomain(
- id=element.get('id'),
- name=findtext(element, 'name', TYPES_URN),
- description=findtext(element, 'description', TYPES_URN),
- plan=plan_type,
- location=location,
- status=findtext(element, 'state', TYPES_URN))
-
- def _to_vlans(self, object):
- vlans = []
- locations = self.list_locations()
- for element in findall(object, 'vlan', TYPES_URN):
- vlans.append(self._to_vlan(element, locations=locations))
-
- return vlans
-
- def _to_vlan(self, element, locations):
- location_id = element.get('datacenterId')
- location = list(filter(lambda x: x.id == location_id,
- locations))[0]
- ip_range = element.find(fixxpath('privateIpv4Range', TYPES_URN))
- ip6_range = element.find(fixxpath('ipv6Range', TYPES_URN))
- network_domain_el = element.find(
- fixxpath('networkDomain', TYPES_URN))
- network_domain = self.ex_get_network_domain(
- network_domain_el.get('id'))
- return DimensionDataVlan(
- id=element.get('id'),
- name=findtext(element, 'name', TYPES_URN),
- description=findtext(element, 'description',
- TYPES_URN),
- network_domain=network_domain,
- private_ipv4_range_address=ip_range.get('address'),
- private_ipv4_range_size=int(ip_range.get('prefixSize')),
- ipv6_range_address=ip6_range.get('address'),
- ipv6_range_size=int(ip6_range.get('prefixSize')),
- ipv4_gateway=findtext(
- element,
- 'ipv4GatewayAddress',
- TYPES_URN),
- ipv6_gateway=findtext(
- element,
- 'ipv6GatewayAddress',
- TYPES_URN),
- location=location,
- status=findtext(element, 'state', TYPES_URN))
-
- def _to_locations(self, object):
- locations = []
- for element in object.findall(fixxpath('datacenter', TYPES_URN)):
- locations.append(self._to_location(element))
-
- return locations
-
- def _to_location(self, element):
- l = NodeLocation(id=element.get('id'),
- name=findtext(element, 'displayName', TYPES_URN),
- country=findtext(element, 'country', TYPES_URN),
- driver=self)
- return l
-
- def _to_cpu_spec(self, element):
- return DimensionDataServerCpuSpecification(
- cpu_count=int(element.get('count')),
- cores_per_socket=int(element.get('coresPerSocket')),
- performance=element.get('speed'))
-
- def _to_vmware_tools(self, element):
- return DimensionDataServerVMWareTools(
- status=element.get('runningStatus'),
- version_status=element.get('versionStatus'),
- api_version=element.get('apiVersion'))
-
- def _to_disks(self, object):
- disk_elements = object.findall(fixxpath('disk', TYPES_URN))
- return [self._to_disk(el) for el in disk_elements]
-
- def _to_disk(self, element):
- return DimensionDataServerDisk(
- id=element.get('id'),
- scsi_id=int(element.get('scsiId')),
- size_gb=int(element.get('sizeGb')),
- speed=element.get('speed'),
- state=element.get('state')
- )
-
- def _to_nodes(self, object):
- node_elements = object.findall(fixxpath('server', TYPES_URN))
- return [self._to_node(el) for el in node_elements]
-
- def _to_node(self, element):
- started = findtext(element, 'started', TYPES_URN)
- status = self._to_status(element.find(fixxpath('progress', TYPES_URN)))
- dd_state = findtext(element, 'state', TYPES_URN)
-
- node_state = self._get_node_state(dd_state, started, status.action)
-
- has_network_info \
- = element.find(fixxpath('networkInfo', TYPES_URN)) is not None
- cpu_spec = self._to_cpu_spec(element.find(fixxpath('cpu', TYPES_URN)))
- disks = self._to_disks(element)
- vmware_tools = self._to_vmware_tools(
- element.find(fixxpath('vmwareTools', TYPES_URN)))
- extra = {
- 'description': findtext(element, 'description', TYPES_URN),
- 'sourceImageId': findtext(element, 'sourceImageId', TYPES_URN),
- 'networkId': findtext(element, 'networkId', TYPES_URN),
- 'networkDomainId':
- element.find(fixxpath('networkInfo', TYPES_URN))
- .get('networkDomainId')
- if has_network_info else None,
- 'datacenterId': element.get('datacenterId'),
- 'deployedTime': findtext(element, 'createTime', TYPES_URN),
- 'cpu': cpu_spec,
- 'memoryMb': int(findtext(
- element,
- 'memoryGb',
- TYPES_URN)) * 1024,
- 'OS_id': element.find(fixxpath(
- 'operatingSystem',
- TYPES_URN)).get('id'),
- 'OS_type': element.find(fixxpath(
- 'operatingSystem',
- TYPES_URN)).get('family'),
- 'OS_displayName': element.find(fixxpath(
- 'operatingSystem',
- TYPES_URN)).get('displayName'),
- 'status': status,
- 'disks': disks,
- 'vmWareTools': vmware_tools
- }
-
- public_ip = findtext(element, 'publicIpAddress', TYPES_URN)
-
- private_ip = element.find(
- fixxpath('networkInfo/primaryNic', TYPES_URN)) \
- .get('privateIpv4') \
- if has_network_info else \
- element.find(fixxpath('nic', TYPES_URN)).get('privateIpv4')
-
- extra['ipv6'] = element.find(
- fixxpath('networkInfo/primaryNic', TYPES_URN)) \
- .get('ipv6') \
- if has_network_info else \
- element.find(fixxpath('nic', TYPES_URN)).get('ipv6')
-
- n = Node(id=element.get('id'),
- name=findtext(element, 'name', TYPES_URN),
- state=node_state,
- public_ips=[public_ip] if public_ip is not None else [],
- private_ips=[private_ip] if private_ip is not None else [],
- driver=self.connection.d
<TRUNCATED>