@@ -241,8 +241,13 @@ def instantiate_vapp(self,
241241 If customization parameters are provided, it will customize the vm and
242242 guest OS, taking some assumptions.
243243
244- A general assumption is made by this method that there is only one vm
245- in the vApp. And the vm has only one NIC.
244+ A general assumption is made by this method that customization
245+ parameters are applicable only if there is only one vm in the vApp.
246+ And, the vm has a single NIC.
247+
248+ In case of a vApp template having multiple VMs having multiple NICs in
249+ any of the VM, none of the optional paramters will be considered. vApp
250+ template will be instantiated with default settings.
246251
247252 :param str name: name of the new vApp.
248253 :param str catalog: name of the catalog.
@@ -296,103 +301,190 @@ def instantiate_vapp(self,
296301 template_resource = self .client .get_resource (
297302 catalog_item .Entity .get ('href' ))
298303
299- # If network is not specified by user then default to
300- # vApp network name specified in the template
301- is_template_vapp_network = False
302- template_networks = template_resource .xpath (
303- '//ovf:NetworkSection/ovf:Network' ,
304- namespaces = {'ovf' : NSMAP ['ovf' ]})
305- # assert len(template_networks) > 0
306- if len (template_networks ) > 0 :
307- network_name_from_template = template_networks [0 ].get (
308- '{' + NSMAP ['ovf' ] + '}name' )
309- if ((network is None ) and (network_name_from_template != 'none' )):
310- network = network_name_from_template
311- is_template_vapp_network = True
312-
313- # Find the network in vdc referred to by user, using
314- # name of the network, ignoring template vApp networks
315- network_href = network_name = None
316- if network is not None :
317- if hasattr (self .resource , 'AvailableNetworks' ) and \
318- hasattr (self .resource .AvailableNetworks , 'Network' ):
319- for n in self .resource .AvailableNetworks .Network :
320- if network == n .get ('name' ):
321- network_href = n .get ('href' )
322- network_name = n .get ('name' )
323- break
324- if network_href is None :
325- if is_template_vapp_network :
326- pass
327- else :
328- raise EntityNotFoundException (
329- 'Network \' %s\' not found in the Virtual Datacenter.' %
330- network )
331-
332- # Configure the network of the vApp
333- vapp_instantiation_param = None
334- if network_name is not None :
335- network_configuration = E .Configuration (
336- E .ParentNetwork (href = network_href ), E .FenceMode (fence_mode ))
337-
338- if fence_mode == 'natRouted' :
339- # TODO(need to find the vm_id)
340- vm_id = None
341- network_configuration .append (
342- E .Features (
343- E .NatService (
344- E .IsEnabled ('true' ), E .NatType ('ipTranslation' ),
345- E .Policy ('allowTraffic' ),
346- E .NatRule (
347- E .OneToOneVmRule (
348- E .MappingMode ('automatic' ),
349- E .VAppScopedVmId (vm_id ), E .VmNicId (0 ))))))
350-
351- vapp_instantiation_param = E .InstantiationParams (
352- E .NetworkConfigSection (
353- E_OVF .Info ('Configuration for logical networks' ),
354- E .NetworkConfig (
355- network_configuration , networkName = network_name )))
356-
357304 # Get all vms in the vapp template
358305 vms = template_resource .xpath (
359306 '//vcloud:VAppTemplate/vcloud:Children/vcloud:Vm' ,
360307 namespaces = NSMAP )
361308 assert len (vms ) > 0
362309
363- vm_instantiation_param = E .InstantiationParams ()
310+ if len (vms ) > 1 :
311+ # Reset any customization parameters if provided
312+ network = memory = cpu = disk_size = password = cust_script = \
313+ vm_name = hostname = ip_address = storage_profile = \
314+ network_adapter_type = None
315+
316+ template_vdc_networks = []
317+ # If provided, only given network will be configured
318+ if network is not None :
319+ template_vdc_networks .append (network )
320+ # Get all vDC networks from vapp template
321+ elif hasattr (template_resource , 'NetworkConfigSection' ) and hasattr (
322+ template_resource .NetworkConfigSection , 'NetworkConfig' ):
323+ for net in template_resource .NetworkConfigSection \
324+ .NetworkConfig :
325+ if hasattr (net .Configuration , 'ParentNetwork' ):
326+ template_vdc_networks .append (net .get ('networkName' ))
327+
328+ vdc_networks = {}
329+ # Get all networks in vDC
330+ if hasattr (self .resource , 'AvailableNetworks' ) and hasattr (
331+ self .resource .AvailableNetworks , 'Network' ):
332+ for net in self .resource .AvailableNetworks .Network :
333+ vdc_networks [net .get ('name' )] = net .get ('href' )
334+
335+ # Check if networks used in vapp template are found in vDC
336+ for net in template_vdc_networks :
337+ if net not in vdc_networks :
338+ raise EntityNotFoundException (
339+ 'Network \' %s\' not found in the Virtual Datacenter.' %
340+ net )
341+
342+ vapp_instantiation_param = E .InstantiationParams ()
343+ if network is not None :
344+ self ._configure_vapp_network (vapp_instantiation_param , network ,
345+ vdc_networks .get (network ), fence_mode )
346+
347+ # Cook the entire vApp Template instantiation element
348+ deploy_param = 'true' if deploy else 'false'
349+ power_on_param = 'true' if power_on else 'false'
350+ all_eulas_accepted = 'true' if accept_all_eulas else 'false'
351+
352+ vapp_template_params = E .InstantiateVAppTemplateParams (
353+ name = name , deploy = deploy_param , powerOn = power_on_param )
354+
355+ if description is not None :
356+ vapp_template_params .append (E .Description (description ))
357+
358+ if vapp_instantiation_param is not None :
359+ vapp_template_params .append (vapp_instantiation_param )
360+
361+ vapp_template_params .append (
362+ E .Source (href = catalog_item .Entity .get ('href' )))
363+
364+ for vm in vms :
365+ vm_instantiation_param = E .InstantiationParams ()
366+
367+ # Configure network of vms
368+ self ._configure_vm_netowrk (vm_instantiation_param , vm , network ,
369+ ip_address , ip_allocation_mode ,
370+ network_adapter_type )
371+
372+ # Configure cpu, memory, disk of the first vm
373+ self ._configure_vm_compute (vm_instantiation_param , vm , cpu , memory ,
374+ disk_size )
375+
376+ # Configure guest customization for the vm
377+ self ._configure_vm_guest_cust (vm_instantiation_param , password ,
378+ cust_script , hostname )
379+
380+ # Craft the <SourcedItem> element for the vm
381+ sourced_item = E .SourcedItem (
382+ E .Source (href = vm .get ('href' ),
383+ id = vm .get ('id' ),
384+ name = vm .get ('name' ),
385+ type = vm .get ('type' )))
386+
387+ vm_general_params = E .VmGeneralParams ()
388+ if vm_name is not None :
389+ vm_general_params .append (E .Name (vm_name ))
390+
391+ # TODO(check if it needs customization if network, cpu or memory..)
392+ if disk_size is None \
393+ and password is None \
394+ and cust_script is None \
395+ and hostname is None :
396+ needs_customization = 'false'
397+ else :
398+ needs_customization = 'true'
399+ vm_general_params .append (E .NeedsCustomization (needs_customization ))
400+ sourced_item .append (vm_general_params )
401+ sourced_item .append (vm_instantiation_param )
402+
403+ if storage_profile is not None :
404+ sp = self .get_storage_profile (storage_profile )
405+ vapp_storage_profile = E .StorageProfile (
406+ href = sp .get ('href' ),
407+ id = sp .get ('href' ).split ('/' )[- 1 ],
408+ type = sp .get ('type' ),
409+ name = sp .get ('name' ))
410+ sourced_item .append (vapp_storage_profile )
411+
412+ vapp_template_params .append (sourced_item )
413+
414+ vapp_template_params .append (E .AllEULAsAccepted (all_eulas_accepted ))
415+ non_admin_resource = self .resource
416+ if self .is_admin :
417+ alternate_href = find_link (self .resource ,
418+ rel = RelationType .ALTERNATE ,
419+ media_type = EntityType .VDC .value ).href
420+ non_admin_resource = self .client .get_resource (
421+ alternate_href )
422+
423+ return self .client .post_linked_resource (
424+ non_admin_resource , RelationType .ADD ,
425+ EntityType .INSTANTIATE_VAPP_TEMPLATE_PARAMS .value ,
426+ vapp_template_params )
427+
428+ def _configure_vapp_network (self , vapp_instantiation_param , network ,
429+ network_href , fence_mode ):
430+ # Configure the network of the vApp
431+ config = E .Configuration (E .ParentNetwork (href = network_href ),
432+ E .FenceMode (fence_mode ))
433+ if fence_mode == 'natRouted' :
434+ # TODO(need to find the vm_id)
435+ vm_id = None
436+ config .append (
437+ E .Features (
438+ E .NatService (
439+ E .IsEnabled ('true' ), E .NatType ('ipTranslation' ),
440+ E .Policy ('allowTraffic' ),
441+ E .NatRule (
442+ E .OneToOneVmRule (E .MappingMode ('automatic' ),
443+ E .VAppScopedVmId (vm_id ),
444+ E .VmNicId (0 ))))))
445+ network_config = E .NetworkConfig (config , networkName = network )
446+ network_config_section = E .NetworkConfigSection (
447+ E_OVF .Info ('Configuration for logical networks' ), network_config )
448+ vapp_instantiation_param .append (network_config_section )
449+
450+ def _configure_vm_netowrk (self , vm_instantiation_param , vm , network ,
451+ ip_address , ip_allocation_mode ,
452+ network_adapter_type ):
453+ if network is None :
454+ return
455+
456+ primary_index = int (
457+ vm .NetworkConnectionSection .PrimaryNetworkConnectionIndex .text )
458+ network_connection = E .NetworkConnection (
459+ E .NetworkConnectionIndex (primary_index ), network = network )
460+
461+ if ip_address is not None :
462+ network_connection .append (E .IpAddress (ip_address ))
463+ network_connection .append (E .IsConnected ('true' ))
364464
365465 if ip_allocation_mode == 'static' :
366466 ip_allocation_mode = 'manual'
467+ network_connection .append (
468+ E .IpAddressAllocationMode (ip_allocation_mode .upper ()))
367469
368- # Configure network of the first vm
369- if network_name is not None :
370- primary_index = int (vms [0 ].NetworkConnectionSection .
371- PrimaryNetworkConnectionIndex .text )
372- network_connection_param = E .NetworkConnection (
373- E .NetworkConnectionIndex (primary_index ), network = network_name )
374- if ip_address is not None :
375- network_connection_param .append (E .IpAddress (ip_address ))
376- network_connection_param .append (E .IsConnected ('true' ))
377- network_connection_param .append (
378- E .IpAddressAllocationMode (ip_allocation_mode .upper ()))
379- if network_adapter_type is not None :
380- network_connection_param .append (
381- E .NetworkAdapterType (network_adapter_type ))
382- vm_instantiation_param .append (
383- E .NetworkConnectionSection (
384- E_OVF .Info (
385- 'Specifies the available VM network connections' ),
386- network_connection_param ))
387-
388- # Configure cpu, memory, disk of the first vm
470+ if network_adapter_type is not None :
471+ network_connection .append (
472+ E .NetworkAdapterType (network_adapter_type ))
473+
474+ network_connection_section = E .NetworkConnectionSection (
475+ E_OVF .Info ('Specifies the available VM network connections' ))
476+ network_connection_section .append (network_connection )
477+ vm_instantiation_param .append (network_connection_section )
478+
479+ def _configure_vm_compute (self , vm_instantiation_param , vm , cpu , memory ,
480+ disk_size ):
481+ # Configure cpu, memory, disk of the vm
389482 cpu_params = memory_params = disk_params = None
390483 if memory is not None or cpu is not None or disk_size is not None :
391484 virtual_hardware_section = E_OVF .VirtualHardwareSection (
392485 E_OVF .Info ('Virtual hardware requirements' ))
393- items = vms [0 ].xpath (
394- '//ovf:VirtualHardwareSection/ovf:Item' ,
395- namespaces = {'ovf' : NSMAP ['ovf' ]})
486+ items = vm .xpath ('//ovf:VirtualHardwareSection/ovf:Item' ,
487+ namespaces = {'ovf' : NSMAP ['ovf' ]})
396488 for item in items :
397489 if memory is not None and memory_params is None :
398490 if item ['{' + NSMAP ['rasd' ] + '}ResourceType' ] == 4 :
@@ -422,9 +514,10 @@ def instantiate_vapp(self,
422514 virtual_hardware_section .append (disk_params )
423515 vm_instantiation_param .append (virtual_hardware_section )
424516
425- # Configure guest customization for the vm
426- if password is not None or cust_script is not None or \
427- hostname is not None :
517+ def _configure_vm_guest_cust (self , vm_instantiation_param , password ,
518+ cust_script , hostname ):
519+ if password is not None or cust_script is not None \
520+ or hostname is not None :
428521 guest_customization_param = E .GuestCustomizationSection (
429522 E_OVF .Info ('Specifies Guest OS Customization Settings' ),
430523 E .Enabled ('true' ),
@@ -446,72 +539,6 @@ def instantiate_vapp(self,
446539 guest_customization_param .append (E .ComputerName (hostname ))
447540 vm_instantiation_param .append (guest_customization_param )
448541
449- # Craft the <SourcedItem> element for the first vm
450- sourced_item = E .SourcedItem (
451- E .Source (
452- href = vms [0 ].get ('href' ),
453- id = vms [0 ].get ('id' ),
454- name = vms [0 ].get ('name' ),
455- type = vms [0 ].get ('type' )))
456-
457- vm_general_params = E .VmGeneralParams ()
458- if vm_name is not None :
459- vm_general_params .append (E .Name (vm_name ))
460-
461- # TODO(check if it needs customization if network, cpu or memory...)
462- if disk_size is None and \
463- password is None and \
464- cust_script is None and \
465- hostname is None :
466- needs_customization = 'false'
467- else :
468- needs_customization = 'true'
469- vm_general_params .append (E .NeedsCustomization (needs_customization ))
470- sourced_item .append (vm_general_params )
471- sourced_item .append (vm_instantiation_param )
472-
473- if storage_profile is not None :
474- sp = self .get_storage_profile (storage_profile )
475- vapp_storage_profile = E .StorageProfile (
476- href = sp .get ('href' ),
477- id = sp .get ('href' ).split ('/' )[- 1 ],
478- type = sp .get ('type' ),
479- name = sp .get ('name' ))
480- sourced_item .append (vapp_storage_profile )
481-
482- # Cook the entire vApp Template instantiation element
483- deploy_param = 'true' if deploy else 'false'
484- power_on_param = 'true' if power_on else 'false'
485- all_eulas_accepted = 'true' if accept_all_eulas else 'false'
486-
487- vapp_template_params = E .InstantiateVAppTemplateParams (
488- name = name , deploy = deploy_param , powerOn = power_on_param )
489-
490- if description is not None :
491- vapp_template_params .append (E .Description (description ))
492-
493- if vapp_instantiation_param is not None :
494- vapp_template_params .append (vapp_instantiation_param )
495-
496- vapp_template_params .append (
497- E .Source (href = catalog_item .Entity .get ('href' )))
498-
499- vapp_template_params .append (sourced_item )
500-
501- vapp_template_params .append (E .AllEULAsAccepted (all_eulas_accepted ))
502- non_admin_resource = self .resource
503- if self .is_admin :
504- alternate_href = find_link (self .resource ,
505- rel = RelationType .ALTERNATE ,
506- media_type = EntityType .VDC .value ).href
507- non_admin_resource = self .client .get_resource (
508- alternate_href )
509-
510- return self .client .post_linked_resource (
511- non_admin_resource , RelationType .ADD ,
512- EntityType .INSTANTIATE_VAPP_TEMPLATE_PARAMS .value ,
513- vapp_template_params )
514-
515542 def list_resources (self , entity_type = None ):
516543 """Fetch information about all resources in the current org vdc.
517544
0 commit comments