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__