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/12/27 08:26:47 UTC
[05/11] libcloud git commit: Deploy server uncustomized
Deploy server uncustomized
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/9d631881
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/9d631881
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/9d631881
Branch: refs/heads/trunk
Commit: 9d631881d997a40c62f15e347d8fe9b25cd881f8
Parents: a094ac7
Author: Samuel Chong <sa...@gmail.com>
Authored: Tue Dec 20 16:35:49 2016 +1100
Committer: Anthony Shaw <an...@apache.org>
Committed: Tue Dec 27 19:22:04 2016 +1100
----------------------------------------------------------------------
libcloud/compute/drivers/dimensiondata.py | 307 ++++++++++++++++++++++++-
1 file changed, 302 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/9d631881/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index be471f0..8dbcb14 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -57,6 +57,7 @@ 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:
@@ -1838,10 +1839,10 @@ class DimensionDataNodeDriver(NodeDriver):
response_code = findtext(result, 'responseCode', TYPES_URN)
return response_code in ['IN_PROGRESS', 'OK']
- def ex_get_node_by_id(self, id):
+ def ex_get_node_by_id(self, id, os_customization=True):
node = self.connection.request_with_orgId_api_2(
'server/server/%s' % id).object
- return self._to_node(node)
+ return self._to_node(node, os_customization)
def ex_list_firewall_rules(self, network_domain, page_size=50,
page_number=1):
@@ -3804,6 +3805,297 @@ class DimensionDataNodeDriver(NodeDriver):
response_code = findtext(response, 'responseCode', TYPES_URN)
return response_code in ['IN_PROGRESS', 'OK']
+ def ex_create_node_uncustomized(self,
+ name,
+ image,
+ ex_network_domain,
+ ex_is_started=True,
+ ex_description=None,
+ ex_cluster_id=None,
+ ex_cpu_specification=None,
+ ex_memory_gb=None,
+ ex_primary_nic_private_ipv4=None,
+ ex_primary_nic_vlan=None,
+ ex_primary_nic_network_adapter=None,
+ ex_additional_nics=None,
+ ex_disks=None,
+ ex_tagid_value_pairs=None,
+ ex_tagname_value_pairs=None
+ ):
+
+ """
+ This MCP 2.0 only function deploys a new Cloud Server from a
+ CloudControl compatible Server Image, which does not utilize
+ VMware Guest OS Customization process.
+
+ Create Node in MCP2 Data Center
+
+
+ :keyword name: (required) String with a name for this new node
+ :type name: ``str``
+
+ :keyword image: (UUID of the Server Image being used as the target
+ for the new Server deployment. The source Server
+ Image (OS Image or Customer Image) must have
+ osCustomization set to true. See Get/List OS
+ Image(s) and Get/List Customer Image(s).
+ :type image: :class:`NodeImage` or ``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_description: (optional) description for this node
+ :type ex_description: ``str``
+
+ :keyword ex_cluster_id: (optional) For multiple cluster
+ environments, it is possible to set a destination cluster for the new
+ Customer Image. Note that performance of this function is optimal when
+ either the Server cluster and destination are the same or when shared
+ data storage is in place for the multiple clusters.
+ :type ex_cluster_id: ``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:'DimensionDataNic' or None
+ :type ex_additional_nics: ``list`` of :class:'DimensionDataNic'
+ 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_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_tagid_value_pairs:
+ (Optional) up to 10 tag elements may be provided.
+ A combination of tagById and tag name cannot be
+ supplied in the same request.
+ Note: ex_tagid_value_pairs and
+ ex_tagname_value_pairs is
+ mutually exclusive. Use one or other.
+
+ :type ex_tagname_value_pairs: ``list`` of dictionary of tag name
+ and value pair. Value can be None.
+
+ :keyword ex_tagname_value_pairs:
+ (Optional) up to 10 tag elements may be provided.
+ A combination of tagById and tag name cannot be
+ supplied in the same request.
+ Note: ex_tagid_value_pairs and
+ ex_tagname_value_pairs is
+ mutually exclusive. Use one or other.
+
+ :type ex_tagname_value_pairs: ``list`` of dictionary of tag name
+ and value pair. Value can be None.
+
+ :return: The newly created :class:`Node`.
+ :rtype: :class:`Node`
+ """
+
+ # Unsupported for version lower than 2.4
+ if LooseVersion(self.connection.active_api_version) < LooseVersion(
+ '2.4'):
+ raise Exception("This feature is NOT supported in "
+ "earlier api version of 2.4")
+
+ # Default start to true if input is invalid
+ if not isinstance(ex_is_started, bool):
+ ex_is_started = True
+ print("Warning: ex_is_started input value is invalid. Default"
+ "to True")
+
+ server_elm = ET.Element('deployUncustomizedServer',
+ {'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
+
+ if ex_cluster_id:
+ dns_elm = ET.SubElement(server_elm, "primaryDns")
+ dns_elm.text = ex_cluster_id
+
+ if ex_is_started is not None:
+ ET.SubElement(server_elm, "start").text = str(
+ ex_is_started).lower()
+
+ 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 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")
+
+ # tagid and tagname value pair should not co-exists
+ if ex_tagid_value_pairs is not None and ex_tagname_value_pairs is \
+ not None:
+ raise ValueError("ex_tagid_value_pairs and ex_tagname_value_pairs"
+ "is mutually exclusive. Use one or the other.")
+
+ # Tag by ID
+ if ex_tagid_value_pairs is not None:
+ if not isinstance(ex_tagid_value_pairs, (list, tuple)):
+ raise ValueError(
+ "ex_tagid_value_pairs should be a list of tag ID and "
+ "value dictionary."
+ )
+
+ tag_elem = ET.SubElement(server_elm, 'tagById')
+
+ for k, v in ex_tagid_value_pairs.items():
+ ET.SubElement(tag_elem, 'tagKeyId').text = k
+
+ if v is not None:
+ ET.SubElement(tag_elem, 'value').text = v
+
+ if ex_tagname_value_pairs is not None:
+ if not isinstance(ex_tagname_value_pairs, (list, tuple)):
+ raise ValueError(
+ "ex_tagname_value_pairs should be a list of tag ID and "
+ "value dictionary."
+ )
+
+ tag_elem = ET.SubElement(server_elm, 'tag')
+
+ for k, v in ex_tagid_value_pairs.items():
+ ET.SubElement(tag_elem, 'tagKeyName').text = k
+
+ if v is not None:
+ ET.SubElement(tag_elem, 'value').text = v
+
+ response = self.connection.request_with_orgId_api_2(
+ 'server/deployUncustomizedServer',
+ 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, os_customization=False)
+
+ return new_node
+
def _format_csv(self, http_response):
text = http_response.read()
lines = str.splitlines(ensure_string(text))
@@ -4158,7 +4450,7 @@ class DimensionDataNodeDriver(NodeDriver):
node_elements = object.findall(fixxpath('server', TYPES_URN))
return [self._to_node(el) for el in node_elements]
- def _to_node(self, element):
+ def _to_node(self, element, os_customization=True):
started = findtext(element, 'started', TYPES_URN)
status = self._to_status(element.find(fixxpath('progress', TYPES_URN)))
dd_state = findtext(element, 'state', TYPES_URN)
@@ -4170,6 +4462,9 @@ class DimensionDataNodeDriver(NodeDriver):
cpu_spec = self._to_cpu_spec(element.find(fixxpath('cpu', TYPES_URN)))
disks = self._to_disks(element)
+ # Vmware Tools
+ vmware_tools = None
+
# Version 2.3 or earlier
if LooseVersion(self.connection.active_api_version) < LooseVersion(
'2.4'):
@@ -4177,9 +4472,11 @@ class DimensionDataNodeDriver(NodeDriver):
element.find(fixxpath('vmwareTools', TYPES_URN)))
operation_system = element.find(fixxpath(
'operatingSystem', TYPES_URN))
+ # Version 2.4 or later
else:
- vmware_tools = self._to_vmware_tools(
- element.find(fixxpath('guest/vmTools', TYPES_URN)))
+ if os_customization:
+ vmware_tools = self._to_vmware_tools(
+ element.find(fixxpath('guest/vmTools', TYPES_URN)))
operation_system = element.find(fixxpath(
'guest/operatingSystem', TYPES_URN))