Author: arkurth
Date: Tue Oct  2 18:15:59 2012
New Revision: 1393075

URL: http://svn.apache.org/viewvc?rev=1393075&view=rev
Log:
VCL-638
Added get_host_network_info and add_ethernet_adapter to vSphere_SDK.pm. This 
code detects whether a dvSwitch or regular network switch is being used on the 
VM host and adds an ethernet adapter accordingly.

Added code to VMware.pm to check if the API object implements 
add_ethernet_adapter. If it does, the ethernet info isn't added to the .vmx 
file before it is registered. After being registered, add_ethernet_adapter is 
called.

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
    vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm

Modified: vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=1393075&r1=1393074&r2=1393075&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm 
(original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm Tue 
Oct  2 18:15:59 2012
@@ -504,6 +504,17 @@ sub load {
                return;
        }
        
+       # If API implements 'add_ethernet_adapter' the adapters were not added 
to the vmx, add them now
+       if ($self->api->can('add_ethernet_adapter')) {
+               (my @vm_ethernet_adapter_configuration = 
$self->get_vm_ethernet_adapter_configuration()) || return;
+               for my $adapter (@vm_ethernet_adapter_configuration) {
+                       if (!$self->api->add_ethernet_adapter($vmx_file_path, 
$adapter)) {
+                               notify($ERRORS{'WARNING'}, 0, "failed to add 
ethernet adapter to VM $computer_name on VM host: $vmhost_name\n" . 
format_data($adapter));
+                               return;
+                       }
+               }
+       }
+       
        # Create a snapshot of the VM
        if (!$self->snapshot('register')) {
                notify($ERRORS{'WARNING'}, 0, "failed to create snapshot before 
powering on VM $computer_name on VM host: $vmhost_name, attempting to delete VM 
to prevent the possibility of writing to the shared vmdk if the VM is powered 
on");
@@ -516,7 +527,6 @@ sub load {
                return;
        }
        
-       
        # Power on the VM
        if (!$self->power_on($vmx_file_path)) {
                notify($ERRORS{'WARNING'}, 0, "failed to power on VM 
$computer_name on VM host: $vmhost_name");
@@ -1835,107 +1845,59 @@ sub prepare_vmx {
        # ide needed for boot
        # usb needed for mouse
        # monitor, ich7m, smc for darwin
-       if ($image_os_type =~ /osx/i) {
-                 %vmx_parameters = (%vmx_parameters, (
-                 "ide1:0.clientDevice" => "TRUE",
-        "ide1:0.deviceType" => "atapi-cdrom",
-        "ide1:0.fileName" => "",           
-        "ide1:0.present" => "TRUE", 
-        "ide1:0.startConnected" => "FALSE",
-        "usb.present" => "TRUE",                              
-        "usb:1.deviceType" => "hub",      
-        "usb:1.present" => "TRUE",    
-        "usb:2.deviceType" => "mouse",    
-        "usb:2.present" => "TRUE", 
-        "monitor.virtual_exec" => "hardware",
-        "monitor.virtual_mmu" => "software",
-        "ich7m.present" => "TRUE",
-        "smc.present" => "FALSE",
-        "keyboard.vusb.enable" => "TRUE",
-        "mouse.vusb.enable" => "TRUE",
-         ));
+       if ($image_os_type =~ /osx/i) {
+               %vmx_parameters = (%vmx_parameters, (
+                       "ide1:0.clientDevice" => "TRUE",
+                       "ide1:0.deviceType" => "atapi-cdrom",
+                       "ide1:0.fileName" => "",           
+                       "ide1:0.present" => "TRUE", 
+                       "ide1:0.startConnected" => "FALSE",
+                       "usb.present" => "TRUE",                              
+                       "usb:1.deviceType" => "hub",      
+                       "usb:1.present" => "TRUE",    
+                       "usb:2.deviceType" => "mouse",    
+                       "usb:2.present" => "TRUE", 
+                       "monitor.virtual_exec" => "hardware",
+                       "monitor.virtual_mmu" => "software",
+                       "ich7m.present" => "TRUE",
+                       "smc.present" => "FALSE",
+                       "keyboard.vusb.enable" => "TRUE",
+                       "mouse.vusb.enable" => "TRUE",
+               ));
        }
 
-       
-       # Get a list of all the network names configured on the VMware host
-       my @network_names = $self->api->get_network_names();
-       notify($ERRORS{'DEBUG'}, 0, "retrieved network names configured on the 
VM host: " . join(", ", @network_names));
-       
-       # Add ethernet adapter definitions to the hash
-       my $interface_index = 0;
-       
-       if ($virtual_switch_0) {
-               if (!grep(/^$virtual_switch_0$/, @network_names)) {
-                       notify($ERRORS{'WARNING'}, 0, "VM network 0 
'$virtual_switch_0' configured in the VM profile does not match any network 
names on the VM host:\n" . join("\n", sort @network_names));
-                       return;
-               }
-               
-               if ($vm_eth0_generated) {
-                       %vmx_parameters = (%vmx_parameters, 
%{$self->get_generated_ethernet_vmx_definition($interface_index, 
$virtual_switch_0)});
-               }
-               else {
-                       my $vm_eth0_mac = 
$self->data->get_computer_eth0_mac_address();
-                       %vmx_parameters = (%vmx_parameters, 
%{$self->get_static_ethernet_vmx_definition($interface_index, 
$virtual_switch_0, $vm_eth0_mac)});
-               }
-               $interface_index++;
-       }
-       
-       if ($virtual_switch_1) {
-               if (!grep(/^$virtual_switch_1$/, @network_names)) {
-                       notify($ERRORS{'WARNING'}, 0, "VM network 1 
'$virtual_switch_1' configured in the VM profile does not match any network 
names on the VM host:\n" . join("\n", sort @network_names));
-                       return;
-               }
-               
-               if ($vm_eth1_generated) {
-                       %vmx_parameters = (%vmx_parameters, 
%{$self->get_generated_ethernet_vmx_definition($interface_index, 
$virtual_switch_1)});
-               }
-               else {
-                       my $vm_eth1_mac = 
$self->data->get_computer_eth1_mac_address();
-                       %vmx_parameters = (%vmx_parameters, 
%{$self->get_static_ethernet_vmx_definition($interface_index, 
$virtual_switch_1, $vm_eth1_mac)});
-               }
-               $interface_index++;
-       }
-       
-       # If vmprofile.virtualswitch2 or vmprofile.virtualswitch3 are defined 
in the database, add autogenerated interfaces
-       if ($virtual_switch_2) {
-               if (!grep(/^$virtual_switch_2$/, @network_names)) {
-                       notify($ERRORS{'WARNING'}, 0, "VM network 2 
'$virtual_switch_2' configured in the VM profile does not match any network 
names on the VM host:\n" . join("\n", sort @network_names));
-                       return;
-               }
-               
-               %vmx_parameters = (%vmx_parameters, 
%{$self->get_generated_ethernet_vmx_definition($interface_index, 
$virtual_switch_2)});
-               $interface_index++;
-       }
-       if ($virtual_switch_3) {
-               if (!grep(/^$virtual_switch_3$/, @network_names)) {
-                       notify($ERRORS{'WARNING'}, 0, "VM network 3 
'$virtual_switch_3' configured in the VM profile does not match any network 
names on the VM host:\n" . join("\n", sort @network_names));
-                       return;
-               }
-               
-               %vmx_parameters = (%vmx_parameters, 
%{$self->get_generated_ethernet_vmx_definition($interface_index, 
$virtual_switch_3)});
-               $interface_index++;
-       }
-       
-       # Add additional Ethernet interfaces if the image project name is not 
vcl
-       if ($image_project !~ /^vcl$/i && $self->api->can('get_network_names')) 
{
-               notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, 
checking if additional network adapters should be configured");
-               
-               # Check each network name
-               # Begin the index at 2 for additional interfaces added because 
ethernet0 and ethernet1 have already been added
-               for my $network_name (@network_names) {
-                       if ($network_name =~ /$image_project/i || 
$image_project =~ /$network_name/i) {
-                               notify($ERRORS{'DEBUG'}, 0, "network name 
($network_name) and image project name ($image_project) intersect, adding 
network interface to VM for network $network_name");
-                               %vmx_parameters = (%vmx_parameters, 
%{$self->get_generated_ethernet_vmx_definition($interface_index, 
$network_name)});
-                               $interface_index++;
+       # Check if the API implements 'add_ethernet_adapter'
+       # This is necessary if the host is using dvSwitches/dvPorts
+       # Adding the info to the vmx before it is registered will not work
+       if ($self->api->can('add_ethernet_adapter')) {
+               notify($ERRORS{'DEBUG'}, 0, "ethernet adapters not added to vmx 
file, they will be added after the VM is registered");
+       }
+       else {
+               (my @vm_ethernet_adapter_configuration = 
$self->get_vm_ethernet_adapter_configuration()) || return;
+               
+               my $interface_index = 0;
+               for my $adapter (@vm_ethernet_adapter_configuration) {
+                       if ($adapter->{address_type} =~ /Manual/i) {
+                               %vmx_parameters = (%vmx_parameters, (
+                                       "ethernet$interface_index.present" => 
"TRUE",
+                                       
"ethernet$interface_index.connectionType" => "custom",
+                                       "ethernet$interface_index.virtualDev" 
=> $adapter->{adapter_type},
+                                       "ethernet$interface_index.networkName" 
=> $adapter->{network_name},
+                                       "ethernet$interface_index.addressType" 
=> "static",
+                                       "ethernet$interface_index.address" => 
$adapter->{address},
+                               ));
                        }
                        else {
-                               notify($ERRORS{'DEBUG'}, 0, "network name 
($network_name) and image project name ($image_project) do not intersect, 
network interface will not be added to VM for network $network_name");
+                               %vmx_parameters = (%vmx_parameters, (
+                                       "ethernet$interface_index.present" => 
"TRUE",
+                                       
"ethernet$interface_index.connectionType" => "custom",
+                                       "ethernet$interface_index.virtualDev" 
=> $adapter->{adapter_type},
+                                       "ethernet$interface_index.networkName" 
=> $adapter->{network_name},
+                                       "ethernet$interface_index.addressType" 
=> "generated",
+                               ));
                        }
+                       $interface_index++;
                }
-               
-       }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, 
additional network adapters will not be configured");
        }
        
        notify($ERRORS{'DEBUG'}, 0, "vmx parameters:\n" . 
format_data(\%vmx_parameters));
@@ -1976,96 +1938,110 @@ sub prepare_vmx {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_static_ethernet_vmx_definition
+=head2 get_vm_ethernet_adapter_configuration
 
- Parameters  : $interface_index, $network_name, $mac_address
- Returns     : hash reference
- Description : Generates a hash containing keys and values which correlate to
-               the vmx file parameters necessary to define an ethernet 
interface
-               with a static MAC address.
+ Parameters  : none
+ Returns     : array of hashes
+ Description : Assembles a data structure containing the ethernet adapter
+ configuration for the VM.
 
 =cut
 
-sub get_static_ethernet_vmx_definition {
+sub get_vm_ethernet_adapter_configuration {
        my $self = shift;
        if (ref($self) !~ /vmware/i) {
                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
                return;
        }
        
-       my $interface_index = shift;
-       if (!defined($interface_index)) {
-               notify($ERRORS{'WARNING'}, 0, "interface index argument was not 
supplied");
-               return;
-       }
+       my $image_project = $self->data->get_image_project();
+       my $virtual_switch_0 = 
$self->data->get_vmhost_profile_virtualswitch0(0);
+       my $virtual_switch_1 = 
$self->data->get_vmhost_profile_virtualswitch1(0);
+       my $virtual_switch_2 = 
$self->data->get_vmhost_profile_virtualswitch2(0);
+       my $virtual_switch_3 = 
$self->data->get_vmhost_profile_virtualswitch3(0);
+       my $vm_ethernet_adapter_type = $self->get_vm_ethernet_adapter_type() || 
return;
        
-       my $network_name = shift;
-       if (!defined($network_name)) {
-               notify($ERRORS{'WARNING'}, 0, "network name argument was not 
supplied");
+       # Get a list of all the network names configured on the VMware host
+       my @network_names = $self->api->get_network_names();
+       if (!@network_names) {
+               notify($ERRORS{'WARNING'}, 0, "unable to assemble ethernet 
adapter configuration, network names could not be retrieved from the VM host");
                return;
        }
        
-       my $mac_address = shift;
-       if (!defined($mac_address)) {
-               notify($ERRORS{'WARNING'}, 0, "MAC address argument was not 
supplied");
-               return;
+       # Make sure all network names configured in the VM host profile 
actually exist on the host
+       for my $network_name ($virtual_switch_0, $virtual_switch_1, 
$virtual_switch_2, $virtual_switch_3) {
+               if ($network_name && !grep(/^$network_name$/, @network_names)) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to assemble 
ethernet adapter configuration, network name '$network_name' configured in the 
VM profile does not match any network names on the VM host:\n" . join("\n", 
sort @network_names));
+                       return;
+               }
        }
        
-       my $vm_ethernet_adapter_type  = $self->get_vm_ethernet_adapter_type() 
|| return;
-       
-       my %vmx_parameters = (
-               "ethernet$interface_index.present" => "TRUE",
-               "ethernet$interface_index.connectionType" => "custom",
-               "ethernet$interface_index.addressType" => "static",
-               "ethernet$interface_index.address" => "$mac_address",
-               "ethernet$interface_index.virtualDev" => 
"$vm_ethernet_adapter_type",
-               "ethernet$interface_index.networkName" => "$network_name",
-       );
+       my @adapters;
        
-       return \%vmx_parameters;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_generated_ethernet_vmx_definition
-
- Parameters  : $interface_index, $network_name
- Returns     : hash reference
- Description : Generates a hash containing keys and values which correlate to
-               the vmx file parameters necessary to define an ethernet 
interface
-               with an auto-generated MAC address.
-
-=cut
-
-sub get_generated_ethernet_vmx_definition {
-       my $self = shift;
-       if (ref($self) !~ /vmware/i) {
-               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
-               return;
+       if ($virtual_switch_0) {
+               my $adapter_configuration = {
+                       network_name => $virtual_switch_0,
+                       adapter_type => $vm_ethernet_adapter_type,
+               };
+               if ($self->data->get_vmhost_profile_eth0generated(0)) {
+                       $adapter_configuration->{address_type} = 'Generated',
+               }
+               else {
+                       $adapter_configuration->{address_type} = 'Manual';
+                       $adapter_configuration->{address} = 
$self->data->get_computer_eth0_mac_address();
+               }
+               push @adapters, $adapter_configuration;
        }
        
-       my $interface_index = shift;
-       if (!defined($interface_index)) {
-               notify($ERRORS{'WARNING'}, 0, "interface index argument was not 
supplied");
-               return;
+       if ($virtual_switch_1) {
+               my $adapter_configuration = {
+                       network_name => $virtual_switch_1,
+                       adapter_type => $vm_ethernet_adapter_type,
+               };
+               if ($self->data->get_vmhost_profile_eth1generated(0)) {
+                       $adapter_configuration->{address_type} = 'Generated',
+               }
+               else {
+                       $adapter_configuration->{address_type} = 'Manual';
+                       $adapter_configuration->{address} = 
$self->data->get_computer_eth1_mac_address();
+               }
+               push @adapters, $adapter_configuration;
        }
        
-       my $network_name = shift;
-       if (!defined($interface_index)) {
-               notify($ERRORS{'WARNING'}, 0, "network name argument was not 
supplied");
-               return;
-       }
+       my @additional_network_names;
+       push @additional_network_names, $virtual_switch_2 if $virtual_switch_2;
+       push @additional_network_names, $virtual_switch_3 if $virtual_switch_3;
        
-       my $vm_ethernet_adapter_type  = $self->get_vm_ethernet_adapter_type() 
|| return;
+       # Add additional Ethernet interfaces if the image project name is not 
vcl
+       if ($image_project !~ /^vcl$/i) {
+               notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, 
checking if additional network adapters should be configured");
+               
+               # Check each network name
+               for my $network_name (@network_names) {
+                       if ($network_name =~ /$image_project/i || 
$image_project =~ /$network_name/i) {
+                               notify($ERRORS{'DEBUG'}, 0, "network name 
($network_name) and image project name ($image_project) intersect, adding 
network interface to VM for network $network_name");
+                               push @additional_network_names, $network_name;
+                       }
+                       else {
+                               notify($ERRORS{'DEBUG'}, 0, "network name 
($network_name) and image project name ($image_project) do not intersect, 
network interface will not be added to VM for network $network_name");
+                       }
+               }
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, 
no additional network adapters will be configured");
+       }
        
-       my %vmx_parameters = (
-               "ethernet$interface_index.addressType" => "generated",
-               "ethernet$interface_index.present" => "TRUE",
-               "ethernet$interface_index.virtualDev" => 
"$vm_ethernet_adapter_type",
-               "ethernet$interface_index.networkName" => "$network_name",
-       );
+       for my $network_name (@additional_network_names) {
+               my $adapter_configuration = {
+                       network_name => $network_name,
+                       adapter_type => $vm_ethernet_adapter_type,
+                       address_type => 'Generated',
+               };
+               push @adapters, $adapter_configuration;
+       }
        
-       return \%vmx_parameters;
+       notify($ERRORS{'DEBUG'}, 0, "VM ethernet adapter configuration:\n" . 
format_data(\@adapters));
+       return @adapters;
 }
 
 #/////////////////////////////////////////////////////////////////////////////

Modified: 
vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm?rev=1393075&r1=1393074&r2=1393075&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm 
(original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm 
Tue Oct  2 18:15:59 2012
@@ -1364,8 +1364,8 @@ sub get_virtual_disk_hardware_version {
  Returns     : string
  Description : Returns the full VMware product name installed on the VM host.
                Examples:
-                                       VMware Server 2.0.2 build-203138
-                                       VMware ESXi 4.0.0 build-208167
+               VMware Server 2.0.2 build-203138
+               VMware ESXi 4.0.0 build-208167
 
 =cut
 
@@ -1431,35 +1431,6 @@ sub get_vmware_product_version {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_network_names
-
- Parameters  : none
- Returns     : array
- Description : Retrieves the network names configured on the VM host.
-
-=cut
-
-sub get_network_names {
-       my $self = shift;
-       if (ref($self) !~ /VCL::Module/i) {
-               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
-               return;
-       }
-       
-       my $datacenter_view = $self->_get_datacenter_view();
-       
-       # Retrieve the network info, check if each network is accessible
-       my @network_names;
-       for my $network (@{Vim::get_views(mo_ref_array => 
$datacenter_view->network)}) {
-               push @network_names, $network->name;
-       }
-       
-       notify($ERRORS{'DEBUG'}, 0, "retrieved network names:\n" . join("\n", 
@network_names));
-       return @network_names;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 is_restricted
 
  Parameters  : none
@@ -3470,6 +3441,321 @@ sub _is_vcenter {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 _mo_ref_to_string
+
+ Parameters  : $mo_ref
+ Returns     : string
+ Description : Formats the information in a managed object reference. Filters
+               out a lot of information which is contained in every mo_ref such
+               as the vim key.
+
+=cut
+
+sub _mo_ref_to_string {
+       my $mo_ref = shift;
+       
+       # Check the argument, either a mo_ref or view can be supplied
+       if (!ref($mo_ref)) {
+               notify($ERRORS{'WARNING'}, 0, "argument is not a reference: 
$mo_ref");
+               return;
+       }
+       elsif (ref($mo_ref) eq 'ManagedObjectReference') {
+               $mo_ref = Vim::get_view(mo_ref => $mo_ref)
+       }
+       
+       my $return_string = '';
+       for my $key (sort keys %$mo_ref) {
+               # Ignore keys which only contain general info
+               next if $key =~ 
/(vim|alarmActionsEnabled|permission|recentTask|triggeredAlarmState|declaredAlarmState|tag|overallStatus|availableField|configIssue|configStatus|customValue|disabledMethod)/;
+               
+               my $value = $mo_ref->{$key};
+               if (!defined($value)) {
+                       $return_string .= "KEY '$key': <undefined>\n";
+               }
+               elsif (my $type = ref($value)) {
+                       $return_string .=  "KEY '$key' <$type>:\n";
+                       $return_string .= format_data($value) . "\n";
+               }
+               else {
+                       $return_string .= "KEY '$key' <scalar>: '$value'\n";
+               }
+       }
+       return $return_string;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_host_network_info
+
+ Parameters  : none
+ Returns     : hash reference
+ Description : Retrieves information about the networks defined on the VM host.
+               A hash reference is returned. The hash keys are the network
+               names. The data contained in the hash differs based on whether
+               its a dvPortgroup or regular network.
+               {
+                  "dv-net-vlan2148" => {
+                     "portgroupKey" => "dvportgroup-125",
+                     "switchUuid" => "4d 12 08 50 01 69 a8 6b-01 9c 43 69 92 
7e ad f1",
+                     "type" => "DistributedVirtualPortgroup",
+                     "value" => "dvportgroup-125"
+                  },
+                  "regular-net-public" => {
+                     "network" => bless( {
+                       "type" => "Network",
+                       "value" => "network-159"
+                     }, 'ManagedObjectReference' ),
+                     "type" => "Network",
+                     "value" => "network-159"
+                  }
+               }
+
+=cut
+
+sub get_host_network_info {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       return $self->{vm_network_info} if $self->{vm_network_info};
+       
+       my $vmhost_hostname = $self->data->get_vmhost_hostname();
+       
+       # Override the die handler
+       local $SIG{__DIE__} = sub{};
+       
+       # Get the datacenter view
+       my $datacenter_view = $self->_get_datacenter_view();
+       
+       # Get the NetworkFolder view
+       my $network_folder_view = Vim::get_view(mo_ref => 
$datacenter_view->networkFolder);
+       if (!$network_folder_view) {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve networkFolder 
view from $vmhost_hostname");
+               return;
+       }
+       
+       my $child_array = $network_folder_view->{childEntity};
+       if (!$child_array) {
+               notify($ERRORS{'WARNING'}, 0, "networkFolder does not contain a 
'childEntity' key:\n" . _mo_ref_to_string($network_folder_view));
+               return;
+       }
+       
+       my $host_network_info = {};
+       CHILD: for my $child (@$child_array) {
+               my $type = $child->{type};
+               my $value = $child->{value};
+               
+               # Get a view for the child entity
+               my $child_view = Vim::get_view(mo_ref => $child);
+               if (!$child_view) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to retrieve view 
for networkFolder child:\n" . format_data($child));
+                       next CHILD;
+               }
+               
+               my $name = $child_view->{name};
+               if (!$name) {
+                       notify($ERRORS{'WARNING'}, 0, "networkFolder child does 
not have a 'name' key:\n" . format_data($child_view));
+                       next CHILD;
+               }
+               
+               $host_network_info->{$name}{type} = $type;
+               $host_network_info->{$name}{value} = $value;
+               
+               if ($type eq 'Network') {
+                       $host_network_info->{$name}{network} = $child;
+               }
+               elsif ($type eq 'DistributedVirtualPortgroup') {
+                       # Save the portgroup key to the hash, example: 
dvportgroup-361
+                       $host_network_info->{$name}{portgroupKey} = 
$child_view->{key};
+                       
+                       # Each portgroup belongs to a distributed virtual switch
+                       # The UUID of the switch is required when adding the 
portgroup to a VM
+                       # Get the dvSwitch view
+                       my $dv_switch_view = Vim::get_view(mo_ref => 
$child_view->config->distributedVirtualSwitch);
+                       if (!$dv_switch_view) {
+                               notify($ERRORS{'WARNING'}, 0, "failed to 
retrieve DistributedVirtualSwitch view for portgroup $name");
+                               next CHILD;
+                       }
+                       
+                       my $dv_switch_uuid = $dv_switch_view->{uuid};
+                       $host_network_info->{$name}{switchUuid} = 
$dv_switch_uuid;
+               }
+               
+       }
+       
+       $self->{host_network_info} = $host_network_info;
+       notify($ERRORS{'DEBUG'}, 0, "retrieved network info from 
$vmhost_hostname:\n" . format_data($host_network_info));
+       return $host_network_info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_network_names
+
+ Parameters  : none
+ Returns     : array
+ Description : Retrieves the network names configured on the VM host.
+
+=cut
+
+sub get_network_names {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       my $host_network_info = $self->get_host_network_info();
+       if ($host_network_info) {
+               return sort keys %$host_network_info;
+       }
+       else {
+               return;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 add_ethernet_adapter
+
+ Parameters  : $vmx_path, $adapter_specification
+ Returns     : boolean
+ Description : Adds an ethernet adapter to the VM based on the adapter
+               specification argument.
+
+=cut
+
+sub add_ethernet_adapter {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the vmx path argument and convert it to a datastore path
+       my $vmx_path = $self->_get_datastore_path(shift) || return;
+       
+       # Get the adapter spec argument and make sure required values are 
included
+       my $adapter_specification = shift;
+       if (!$adapter_specification) {
+               notify($ERRORS{'WARNING'}, 0, "adapter specification argument 
was not supplied");
+               return;
+       }
+       my $adapter_type = $adapter_specification->{adapter_type};
+       my $network_name = $adapter_specification->{network_name};
+       my $address_type = $adapter_specification->{address_type};
+       my $address = $adapter_specification->{address} || '';
+       if (!$adapter_type) {
+               notify($ERRORS{'WARNING'}, 0, "'adapter_type' is missing from 
adapter specification:\n" . format_data($adapter_specification));
+               return;
+       }
+       if (!$network_name) {
+               notify($ERRORS{'WARNING'}, 0, "'network_name' is missing from 
adapter specification:\n" . format_data($adapter_specification));
+               return;
+       }
+       if (!$address_type) {
+               notify($ERRORS{'WARNING'}, 0, "'address_type' is missing from 
adapter specification:\n" . format_data($adapter_specification));
+               return;
+       }
+       
+       # Get the VM host's network info
+       my $host_network_info = $self->get_host_network_info();
+       if (!$host_network_info) {
+               notify($ERRORS{'WARNING'}, 0, "unable to add ethernet adapter, 
VM host network info could not be retrieved");
+               return;
+       }
+       
+       # Make sure the network name provided in the adapter spec argument was 
found on the VM host
+       my $adapter_network_info = $host_network_info->{$network_name};
+       if (!$adapter_network_info) {
+               notify($ERRORS{'WARNING'}, 0, "unable to add ethernet adapter, 
VM host network info does not contain a network named '$network_name'");
+               return;
+       }
+       my $adapter_network_type = $adapter_network_info->{type};
+       
+       # Assemble the backing info
+       my $backing;
+       if ($adapter_network_type eq 'DistributedVirtualPortgroup') {
+               my $portgroup_key = $adapter_network_info->{portgroupKey};
+               my $switch_uuid = $adapter_network_info->{switchUuid};
+               
+               $backing = 
VirtualEthernetCardDistributedVirtualPortBackingInfo->new(
+                       port => DistributedVirtualSwitchPortConnection->new(
+                               portgroupKey => $portgroup_key,
+                               switchUuid => $switch_uuid,
+                       ),
+               );
+       }
+       else {
+               my $network = $adapter_network_info->{network};
+               $backing = VirtualEthernetCardNetworkBackingInfo->new(
+                       deviceName => $network_name,
+                       network => $network,
+               );
+       }
+       
+       # Assemble the ethernet device
+       my $ethernet_device;
+       if ($adapter_type =~ /e1000/i) {
+               $ethernet_device = VirtualE1000->new(
+                       key => '',
+                       backing => $backing,
+                       addressType => $address_type,
+                       macAddress => $address,
+               );
+       }
+       elsif ($adapter_type =~ /vmxnet/i) {
+               $ethernet_device = VirtualVmxnet3->new(
+                       key => '',
+                       backing => $backing,
+                       addressType => $address_type,
+                       macAddress => $address,
+               );
+       }
+       else {
+               $ethernet_device = VirtualPCNet32->new(
+                       key => '',
+                       backing => $backing,
+                       addressType => $address_type,
+                       macAddress => $address,
+               );
+       }
+       
+       # Assemble the VM config spec
+       my $vm_config_spec = VirtualMachineConfigSpec->new(
+               deviceChange => [
+                       VirtualDeviceConfigSpec->new(
+                               operation =>    
VirtualDeviceConfigSpecOperation->new('add'),
+                               device => $ethernet_device,
+                       ),
+               ],
+       );
+       
+       # Override the die handler
+       local $SIG{__DIE__} = sub{};
+       
+       my $vm = $self->_get_vm_view($vmx_path) || return;
+       
+       notify($ERRORS{'DEBUG'}, 0, "attempting to add ethernet adapter to VM: 
$vmx_path:\n" . format_data($adapter_specification));
+       eval {
+               $vm->ReconfigVM(
+                       spec => $vm_config_spec,
+               );
+       };
+       if ($@) {
+               notify($ERRORS{'WARNING'}, 0, "failed to add ethernet adapter 
to VM: $vmx_path, adapter specification:\n" . 
format_data($adapter_specification) . "\nerror:\n$@");
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "added ethernet adapter to VM: 
$vmx_path:\n" . format_data($adapter_specification));
+               return 1;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 


Reply via email to