--- Desktop/libcloud-trunk-1/libcloud/compute/drivers/vcloud.py 2013-04-25 23:53:32.000000000 +0100 +++ /a/Apache-libcloud/src/libcloud/libcloud/compute/drivers/vcloud.py 2013-04-29 08:14:29.000000000 +0100 @@ -1925,3 +1925,159 @@ #The vcd 5.1 virtual machine memory size must be a multiple of 4 MB raise ValueError( '%s is not a valid vApp VM memory value' % (vm_memory)) + + @staticmethod + def _validate_vm_ipmode(vm_ipmode): + if vm_ipmode is None: + return + elif vm_ipmode not in IP_MODE_VALS_1_5: + raise ValueError('%s is not a valid IP address allocation mode value' % vm_ipmode) + + def _change_vm_ipmode(self, vapp_or_vm_id, vm_ipmode, vm_ip_address): + if vm_ipmode is None: + return + elif vm_ipmode == 'MANUAL': + set_vm_ipmode = 'MANUAL' + + vms = self._get_vm_elements(vapp_or_vm_id) + + for vm in vms: + res = self.connection.request( + '%s/networkConnectionSection' % get_url_path(vm.get('href'))) + net_conns = res.object.findall( + fixxpath(res.object, 'NetworkConnection')) + for c in net_conns: + c.find(fixxpath(c, 'IpAddressAllocationMode')).text = set_vm_ipmode + if (vm_ip_address and set_vm_ipmode == 'MANUAL'): + ip_element_tag = fixxpath(res.object, 'IpAddress') + root = net_conns[0] + ip_elem = ET.Element(ip_element_tag) + root.insert(1, ip_elem) + ip_elem.text = vm_ip_address + else: + raise ValueError("IP address is required if IP Mode is set to %s" % vm_ipmode) + + res = self.connection.request( + '%s/networkConnectionSection' % get_url_path(vm.get('href')), + data=ET.tostring(res.object), + method='PUT', + headers={'Content-Type': 'application/vnd.vmware.vcloud.networkConnectionSection+xml'} + ) + self._wait_for_task_completion(res.object.get('href')) + + def create_node(self, **kwargs): + """Creates and returns node. If the source image is: + - vApp template - a new vApp is instantiated from template + - existing vApp - a new vApp is cloned from the source vApp. Can not clone more vApps is parallel otherwise + resource busy error is raised. + - ipaddress - only works with vAPP with single VM for now. + + @inherits: L{NodeDriver.create_node} + + @keyword image: OS Image to boot on node. (required). Can be a NodeImage or existing Node that will be + cloned. + @type image: L{NodeImage} or L{Node} + + @keyword ex_network: Organisation's network name for attaching vApp VMs to. + @type ex_network: C{str} + + @keyword ex_vdc: Name of organisation's virtual data center where vApp VMs will be deployed. + @type ex_vdc: C{str} + + @keyword ex_vm_names: list of names to be used as a VM and computer name. The name must be max. 15 characters + long and follow the host name requirements. + @type ex_vm_names: C{list} of C{str} + + @keyword ex_vm_cpu: number of virtual CPUs/cores to allocate for each vApp VM. + @type ex_vm_cpu: C{int} + + @keyword ex_vm_memory: amount of memory in MB to allocate for each vApp VM. + @type ex_vm_memory: C{int} + + @keyword ex_vm_script: full path to file containing guest customisation script for each vApp VM. + Useful for creating users & pushing out public SSH keys etc. + @type ex_vm_script: C{str} + + @keyword ex_vm_network: Override default vApp VM network name. Useful for when you've imported an OVF + originating from outside of the vCloud. + @type ex_vm_network: C{str} + + @keyword ex_vm_fence: Fence mode for connecting the vApp VM network (ex_vm_network) to the parent + organisation network (ex_network). + @type ex_vm_fence: C{str} + + @keyword ex_vm_ipaddress: IP address for vApp VM (single VM in vAPP). + @type ex_vm_ipaddress: C{str} + + @keyword ex_vm_ipmode: IP address allocation mode for all vApp VM network connections. + @type ex_vm_ipmode: C{str} + + @keyword ex_deploy: set to False if the node shouldn't be deployed (started) after creation + @type ex_deploy: C{bool} + """ + name = kwargs['name'] + image = kwargs['image'] + ex_vm_names = kwargs.get('ex_vm_names') + ex_vm_cpu = kwargs.get('ex_vm_cpu') + ex_vm_memory = kwargs.get('ex_vm_memory') + ex_vm_script = kwargs.get('ex_vm_script') + ex_vm_fence = kwargs.get('ex_vm_fence', None) + ex_network = kwargs.get('ex_network', None) + ex_vm_network = kwargs.get('ex_vm_network', None) + ex_vm_ipaddress = kwargs.get('ex_vm_ipaddress', None) + ex_vm_ipmode = kwargs.get('ex_vm_ipmode', None) + ex_deploy = kwargs.get('ex_deploy', True) + ex_vdc = kwargs.get('ex_vdc', None) + + self._validate_vm_names(ex_vm_names) + self._validate_vm_cpu(ex_vm_cpu) + self._validate_vm_memory(ex_vm_memory) + self._validate_vm_fence(ex_vm_fence) + self._validate_vm_ipmode(ex_vm_ipmode) + ex_vm_script = self._validate_vm_script(ex_vm_script) + + # Some providers don't require a network link + if ex_network: + network_href = self._get_network_href(ex_network) + network_elem = self.connection.request( + get_url_path(network_href)).object + else: + network_elem = None + + vdc = self._get_vdc(ex_vdc) + + if self._is_node(image): + vapp_name, vapp_href = self._clone_node(name, image, vdc) + else: + vapp_name, vapp_href = self._instantiate_node(name, image, + network_elem, + vdc, ex_vm_network, + ex_vm_fence) + + self._change_vm_names(vapp_href, ex_vm_names) + self._change_vm_cpu(vapp_href, ex_vm_cpu) + self._change_vm_memory(vapp_href, ex_vm_memory) + self._change_vm_script(vapp_href, ex_vm_script) + self._change_vm_ipmode(vapp_href, ex_vm_ipmode, ex_vm_ipaddress) + + # Power on the VM. + if ex_deploy: + # Retry 3 times: when instantiating large number of VMs at the same time some may fail on resource allocation + retry = 3 + while True: + try: + res = self.connection.request( + '%s/power/action/powerOn' % get_url_path(vapp_href), + method='POST') + self._wait_for_task_completion(res.object.get('href')) + break + except Exception: + if retry <= 0: + raise + retry -= 1 + time.sleep(10) + + res = self.connection.request(get_url_path(vapp_href)) + node = self._to_node(res.object) + return node +