Author: arkurth
Date: Mon Apr 25 15:30:50 2011
New Revision: 1096498

URL: http://svn.apache.org/viewvc?rev=1096498&view=rev
Log:
VCL-450
Added default minimum memory sizes for each OS/architecture which requires more 
than 512 MB of RAM in the %VM_OS_CONFIGURATION hash.  Updated get_vm_ram to use 
this value.

Added code to capture subroutine to save the vmx file used on the VM being 
captured along with the vmdk files. This vmx file can later be used as a 
reference. Added get_reference_vmx_file_name, get_reference_vmx_file_path, and 
get_reference_vmx_info subroutines.

Updated copy_vmdk to also copy the reference vmx file when copying a vmdk.

Updated get_vmdk_parameter_value to allow it to retrieve a parameter from the 
vmdk file if it resides on the VM host. It previously only checked the files on 
the management node.

Updated get_vm_disk_adapter_type and get_vm_virtual_hardware_version to try to 
first retrieve the type from the reference vmx file. This should allow VMs 
using the LSI SAS adapter type to work correctly.

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

Modified: 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=1096498&r1=1096497&r2=1096498&view=diff
==============================================================================
--- 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm 
(original)
+++ 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm 
Mon Apr 25 15:30:50 2011
@@ -87,17 +87,17 @@ our %VM_OS_CONFIGURATION = (
                "scsi-virtualDev" => "lsiLogic",
        },
        # Windows configurations:
-       "xp-x86" => {
+       "winxp-x86" => {
                "guestOS" => "winXPPro",
                "ethernet-virtualDev" => "vlance",
                "scsi-virtualDev" => "busLogic",
        },
-       "xp-x86_64" => {
+       "winxp-x86_64" => {
                "guestOS" => "winXPPro-64",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
        },
-       "vista-x86" => {
+       "winvista-x86" => {
                "guestOS" => "winvista",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
@@ -109,34 +109,35 @@ our %VM_OS_CONFIGURATION = (
                "scsi-virtualDev" => "lsiLogic",
                "memsize" => 1024,
        }, 
-       "7-x86" => {
+       "win7-x86" => {
                "guestOS" => "windows7",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
                "memsize" => 1024,
        },
-       "7-x86_64" => {
+       "win7-x86_64" => {
                "guestOS" => "windows7-64",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
                "memsize" => 2048,
        }, 
-       "2003-x86" => {
+       "win2003-x86" => {
                "guestOS" => "winNetEnterprise",
                "ethernet-virtualDev" => "vlance",
                "scsi-virtualDev" => "lsiLogic",
        },
-       "2003-x86_64" => {
+       "win2003-x86_64" => {
                "guestOS" => "winNetEnterprise-64",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
+               "memsize" => 1024,
        },
-       "2008-x86" => {
+       "win2008-x86" => {
                "guestOS" => "winServer2008Enterprise-32",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
        },
-       "2008-x86_64" => {
+       "win2008-x86_64" => {
                "guestOS" => "winServer2008Enterprise-64",
                "ethernet-virtualDev" => "e1000",
                "scsi-virtualDev" => "lsiLogic",
@@ -469,7 +470,7 @@ sub capture {
                notify($ERRORS{'WARNING'}, 0, "failed to determine the vmx file 
path actively being used by VM $computer_name");
                return;
        }
-
+       
        # Set the vmx file path in this object so that it overrides the default 
value that would normally be constructed
        if (!$self->set_vmx_file_path($vmx_file_path_original)) {
                notify($ERRORS{'WARNING'}, 0, "failed to set the vmx file to 
the path that was determined to be in use by VM $computer_name being captured: 
$vmx_file_path_original");
@@ -535,6 +536,11 @@ sub capture {
        my $vmdk_directory_path_renamed = 
"$vmdk_base_directory_path/$image_name";
        my $vmdk_file_path_renamed = 
"$vmdk_directory_path_renamed/$image_name.vmdk";
        
+       # Construct the path of the reference vmx file to be saved with the vmdk
+       # The .vmx file is only saved so that it can be referenced later
+       my $reference_vmx_file_name = $self->get_reference_vmx_file_name();
+       my $vmx_file_path_renamed = 
"$vmdk_directory_path_renamed/$reference_vmx_file_name";
+       
        # Make sure the vmdk file path for the captured image doesn't already 
exist
        # Do this before calling pre_capture and shutting down the VM
        if ($vmdk_file_path_original ne $vmdk_file_path_renamed && 
$self->vmhost_os->file_exists($vmdk_file_path_renamed)) {
@@ -585,6 +591,18 @@ sub capture {
                }
        }
        
+       # Copy the vmx file to the new image directory for later reference
+       # First check if vmx file already exists (could happen if base image VM 
was manually created)
+       if ($vmx_file_path_original eq $vmx_file_path_renamed) {
+               notify($ERRORS{'DEBUG'}, 0, "vmx file will not be copied, vmx 
file path being captured is already named as the image being captured: 
'$vmx_file_path_original'");
+       }
+       else {
+               if (!$self->vmhost_os->copy_file($vmx_file_path_original, 
$vmx_file_path_renamed)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to copy the 
reference vmx file after the VM was powered off: '$vmx_file_path_original' --> 
'$vmx_file_path_renamed'");
+                       return;
+               }
+       }
+       
        # Copy the vmdk to the image repository if the repository path is 
defined in the VM profile
        my $repository_directory_path = 
$self->get_repository_vmdk_directory_path();
        if ($repository_directory_path) {
@@ -598,10 +616,18 @@ sub capture {
                        # Files can be copied directly to the image repository 
and converted while they are copied
                        my $repository_vmdk_file_path = 
$self->get_repository_vmdk_file_path();
                        if ($self->copy_vmdk($vmdk_file_path_renamed, 
$repository_vmdk_file_path, '2gbsparse')) {
-                               $repository_copy_successful = 1;
+                               
+                               # Copy the reference vmx file of the VM being 
captured to the vmdk directory
+                               my $repository_vmx_file_path = 
"$repository_directory_path/$image_name.vmx";
+                               if 
($self->vmhost_os->copy_file($vmx_file_path_renamed, 
$repository_vmx_file_path)) {
+                                       $repository_copy_successful = 1;
+                               }
+                               else {
+                                       notify($ERRORS{'WARNING'}, 0, "failed 
to copy the reference vmx file to the repository mounted on the VM host after 
the VM was powered off: '$vmx_file_path_renamed' --> 
'$repository_vmx_file_path'");
+                               }
                        }
                        else {
-                               notify($ERRORS{'WARNING'}, 0, "failed to copy 
the vmdk files after the VM was powered off: '$vmdk_file_path_renamed' --> 
'$repository_vmdk_file_path'");
+                               notify($ERRORS{'WARNING'}, 0, "failed to copy 
the vmdk files to the repository mounted on the VM host after the VM was 
powered off: '$vmdk_file_path_renamed' --> '$repository_vmdk_file_path'");
                        }
                }
                else {
@@ -619,7 +645,7 @@ sub capture {
                        elsif ($virtual_disk_type =~ /sparse/) {
                                # Virtual disk is sparse, get a list of the 
vmdk file paths
                                notify($ERRORS{'DEBUG'}, 0, "vmdk can be copied 
directly from VM host $vmhost_hostname to the image repository because the 
virtual disk type is sparse: $virtual_disk_type");
-                               @vmdk_copy_paths = 
$self->vmhost_os->find_files($vmdk_directory_path_original, '*.vmdk');
+                               @vmdk_copy_paths = 
$self->vmhost_os->find_files($vmdk_directory_path_renamed, '*.vmdk');
                        }
                        else {
                                # Virtual disk is NOT sparse - a sparse copy 
must first be created before being copied to the repository
@@ -628,7 +654,7 @@ sub capture {
                                # Construct the vmdk file path where the 
2gbsparse copy will be created
                                # The vmdk files are copied to a directory with 
the same name but with '_2gbsparse' appended to the directory name
                                # The vmdk files in the '_2gbsparse' are named 
the same as the original non-sparse directory
-                               $vmdk_directory_path_sparse = 
"$vmdk_directory_path_original\_2gbsparse";
+                               $vmdk_directory_path_sparse = 
"$vmdk_directory_path_renamed\_2gbsparse";
                                $vmdk_file_path_sparse = 
"$vmdk_directory_path_sparse/$image_name.vmdk";
                                
                                # Create a sparse copy of the virtual disk
@@ -643,6 +669,9 @@ sub capture {
                        
                        # Copy the vmdk directory from the VM host to the image 
repository
                        if (@vmdk_copy_paths) {
+                               # Add the reference vmx file path to the array 
so that the vmx is copied to the repository
+                               push @vmdk_copy_paths, $vmx_file_path_renamed;
+                               
                                # Loop through the files, copy each to the 
management node's repository directory
                                notify($ERRORS{'DEBUG'}, 0, "vmdk files will be 
copied from VM host $vmhost_hostname to the image repository on the management 
node:\n" . join("\n", sort @vmdk_copy_paths));
                                VMDK_COPY_PATH: for my $vmdk_copy_path 
(@vmdk_copy_paths) {
@@ -1849,7 +1878,7 @@ sub prepare_vmdk {
        
        # Find the vmdk file paths in the image repository directory
        my @vmdk_repository_file_paths;
-       my $command = "find \"$repository_vmdk_directory_path\" -type f -iname 
\"$image_name*.vmdk\"";
+       my $command = "find \"$repository_vmdk_directory_path\" -type f -iname 
\"$image_name*\"";
        my ($exit_status, $output) = run_command($command, 1);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to find 
files in image repository directory: '$repository_vmdk_directory_path', 
pattern: '*.vmdk', command:\n$command");
@@ -1888,7 +1917,7 @@ sub prepare_vmdk {
        
        # Check if the vmdk disk type is compatible with the VMware product 
installed on the host
        return 1 if $self->is_vmdk_compatible();
-
+       
        # Disk type is not compatible with the VMware product installed on the 
host
        # Attempt to make a copy - copy_vmdk should create a copy in a 
compatible format
        # The destination copy is stored in a directory with the same name as 
the normal vmdk directory followed by a ~
@@ -2941,6 +2970,69 @@ sub set_vmx_file_path {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_reference_vmx_file_name
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the name of the reference vmx file that was used when 
the
+               image was captured.
+
+=cut
+
+sub get_reference_vmx_file_name {
+       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;
+       }
+       
+       return $ENV{reference_vmx_file_name} if 
defined($ENV{reference_vmx_file_name});
+       
+       my $image_name = $self->data->get_image_name() || return;
+       
+       $ENV{reference_vmx_file_name} = "$image_name.vmx.reference";
+       return $ENV{reference_vmx_file_name};
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_reference_vmx_file_path
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the path to the reference vmx file that was used when 
the
+               image was captured.
+
+=cut
+
+sub get_reference_vmx_file_path {
+       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;
+       }
+       
+       return $ENV{reference_vmx_file_path} if 
defined($ENV{reference_vmx_file_path});
+       
+       my $vmdk_directory_path = $self->get_vmdk_directory_path();
+       if (!$vmdk_directory_path) {
+               notify($ERRORS{'WARNING'}, 0, "unable to construct reference 
vmx file path, vmdk directory path could not be determined");
+               return;
+       }
+       
+       my $reference_vmx_file_name = $self->get_reference_vmx_file_name();
+       if (!$reference_vmx_file_name) {
+               notify($ERRORS{'WARNING'}, 0, "unable to construct reference 
vmx file path, reference vmx file name could not be determined");
+               return;
+       }
+       
+       $ENV{reference_vmx_file_path} = 
"$vmdk_directory_path/$reference_vmx_file_name";
+       notify($ERRORS{'DEBUG'}, 0, "determined reference vmx file path: 
$ENV{reference_vmx_file_path}");
+       return $ENV{reference_vmx_file_path};
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 get_vmdk_file_path
 
  Parameters  : none
@@ -3989,54 +4081,41 @@ sub get_vmdk_parameter_value {
                return;
        }
        
-       my $vmdk_file_path = $self->get_vmdk_file_path() || return;
-       my $image_repository_vmdk_file_path = 
$self->get_repository_vmdk_file_path() || return;
+       my $vmhost_hostname = $self->data->get_vmhost_hostname();
        
-       # Open the vmdk file for reading
-       if (open FILE, "<", $vmdk_file_path) {
-               notify($ERRORS{'DEBUG'}, 0, "attempting to locate 
$vmdk_parameter value in vmdk file: $vmdk_file_path");
-       }
-       elsif (open FILE, "<", $image_repository_vmdk_file_path) {
-               notify($ERRORS{'DEBUG'}, 0, "attempting to locate 
$vmdk_parameter value in vmdk file: $image_repository_vmdk_file_path");
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "unable to open either vmdk file 
for reading: $vmdk_file_path, $image_repository_vmdk_file_path");
-               return;
-       }
+       # Try to get the file contents from the VM host
+       my $vmdk_file_path = $self->get_vmdk_file_path();
+       my @vmdk_file_lines = 
$self->vmhost_os->get_file_contents($vmdk_file_path);
        
-       # Read the file line by line - do not read the file all at once
-       # The vmdk file may be very large depending on the type - it may not be 
split up into a descriptor file and extents
-       # If the vmdk file isn't split, the descriptor section will be at the 
beginning
-       my $line_count = 0;
-       my $value;
-       while ($line_count < 100) {
-               $line_count++;
-               my $line = <FILE>;
-               chomp $line;
+       if (!@vmdk_file_lines) {
+               my $head_command = "head -n 100 $vmdk_file_path";
+               
+               my $image_repository_vmdk_file_path = 
$self->get_repository_vmdk_file_path();
+               $head_command .= " $image_repository_vmdk_file_path" if 
$image_repository_vmdk_file_path;
                
+               my ($head_exit_status, $head_output) = 
$self->mn_os->execute($head_command);
+               if (!defined($head_output)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to run command on 
management node while attempting to locate $vmdk_parameter value in vmdk file: 
'$head_command'");
+                       return;
+               }
+               @vmdk_file_lines = @$head_output;
+       }
+       
+       for my $vmdk_file_line (@vmdk_file_lines) {
                # Ignore comment lines
-               next if ($line =~ /^\s*#/);
+               next if ($vmdk_file_line =~ /^\s*#/);
                
                # Check if the line contains the parameter name
-               if ($line =~ /(^|\.)$vmdk_parameter[\s=]+/i) {
-                       notify($ERRORS{'DEBUG'}, 0, "found line containing 
$vmdk_parameter: '$line'");
-                       
-                       # Extract the value from the line
-                       ($value) = $line =~ /\"(.+)\"/;
-                       last;
+               if ($vmdk_file_line =~ 
/(?:^|\.)$vmdk_parameter[=\s\"]*([^\"]*)/ig) {
+                       my $value = $1;
+                       chomp $value;
+                       notify($ERRORS{'DEBUG'}, 0, "found '$vmdk_parameter' 
value in vmdk file:\nline: '$vmdk_file_line'\nvalue: '$value'");
+                       return $value;
                }
        }
        
-       close FILE;
-       
-       if (defined($value)) {
-               notify($ERRORS{'DEBUG'}, 0, "found $vmdk_parameter value in 
vmdk file: '$value'");
-               return $value;
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "did not find $vmdk_parameter 
value in vmdk file");
-               return;
-       }
+       notify($ERRORS{'WARNING'}, 0, "did not find '$vmdk_parameter' value in 
vmdk file");
+       return;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -4062,31 +4141,44 @@ sub get_vm_disk_adapter_type {
        
        my $vmdk_controller_type;
        
-       if ($self->api->can("get_virtual_disk_controller_type") && 
($vmdk_controller_type = 
$self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path()))) {
-               notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter type 
from api object: $vmdk_controller_type");
-       }
-       elsif ($vmdk_controller_type = 
$self->get_vmdk_parameter_value('adapterType')) {
-               notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter type 
from vmdk file: $vmdk_controller_type");
+       # Attempt to retrieve the type from the reference vmx file for the image
+       my $reference_vmx_file_info = $self->get_reference_vmx_info();
+       if ($reference_vmx_file_info) {
+               for my $vmx_key (keys %$reference_vmx_file_info) {
+                       if ($vmx_key =~ /scsi\d+\.virtualdev/i) {
+                               $vmdk_controller_type = 
$reference_vmx_file_info->{$vmx_key};
+                               notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk 
adapter type from reference vmx file: $vmdk_controller_type");
+                               return $vmdk_controller_type;
+                       }
+               }
+               notify($ERRORS{'DEBUG'}, 0, "unable to retrieve VM disk adapter 
type from reference vmx file, 'scsi*.virtualDev' key does not exist");
        }
        
-       if (!$vmdk_controller_type) {
-               my $vm_os_configuration = $self->get_vm_os_configuration();
-               if (!$vm_os_configuration) {
-                       notify($ERRORS{'WARNING'}, 0, "unable to determine VM 
disk adapter type because unable to retrieve default VM OS configuration");
-                       return;
+       # Try to get the type from the API module's 
get_virtual_disk_controller_type subroutine
+       if ($self->api->can("get_virtual_disk_controller_type")) {
+               if ($vmdk_controller_type = 
$self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path())) {
+                       notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter 
type from api object: $vmdk_controller_type");
+                       return $vmdk_controller_type;
                }
-               
-               $vmdk_controller_type = 
$vm_os_configuration->{"scsi-virtualDev"};
-               notify($ERRORS{'DEBUG'}, 0, "retrieved default VM disk adapter 
type for VM OS: $vmdk_controller_type");
        }
        
-       if ($vmdk_controller_type) {
+       # Try to retrieve the adapter type by reading the vmdk descriptor
+       if ($vmdk_controller_type = 
$self->get_vmdk_parameter_value('adapterType')) {
+               notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter type 
from vmdk file: $vmdk_controller_type");
+               return $vmdk_controller_type;
+       }
+       
+       # Try to retrieve the default adapter type for the image OS
+       my $vm_os_configuration = $self->get_vm_os_configuration();
+       if ($vm_os_configuration && ($vmdk_controller_type = 
$vm_os_configuration->{"scsi-virtualDev"})) {
+               notify($ERRORS{'DEBUG'}, 0, "retrieved default VM disk adapter 
type for VM OS: $vmdk_controller_type");
                return $vmdk_controller_type;
        }
        else {
-               notify($ERRORS{'WARNING'}, 0, "unable to determine VM disk 
adapter type");
+               notify($ERRORS{'WARNING'}, 0, "unable to determine VM disk 
adapter type from default VM OS configuration");
                return;
        }
+       
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -4107,6 +4199,21 @@ sub get_vm_virtual_hardware_version {
        }
        
        my $hardware_version;
+       
+       # Attempt to retrieve the type from the reference vmx file for the image
+       my $reference_vmx_file_info = $self->get_reference_vmx_info();
+       if ($reference_vmx_file_info) {
+               for my $vmx_key (keys %$reference_vmx_file_info) {
+                       if ($vmx_key =~ /virtualHW\.version/i) {
+                               $hardware_version = 
$reference_vmx_file_info->{$vmx_key};
+                               notify($ERRORS{'DEBUG'}, 0, "retrieved VM 
virtual hardware version from reference vmx file: $hardware_version");
+                               return $hardware_version;
+                       }
+               }
+               notify($ERRORS{'DEBUG'}, 0, "unable to retrieve VM virtual 
hardware version from reference vmx file, 'virtualHW.version' key does not 
exist");
+       }
+       
+       
        if ($self->api->can("get_virtual_disk_hardware_version")) {
                $hardware_version = 
$self->api->get_virtual_disk_hardware_version($self->get_vmdk_file_path());
                notify($ERRORS{'DEBUG'}, 0, "retrieved hardware version from 
api object: $hardware_version");
@@ -4165,8 +4272,8 @@ sub get_vm_virtual_hardware_version {
  Returns     : hash
  Description : Returns the information stored in %VM_OS_CONFIGURATION for
                the guest OS. The guest OS type, OS name, and archictecture are
-               used to determine the appropriate guestOS and 
ethernet-virtualDev
-               values to be used in the vmx file.
+               used to determine some of the appropriate values to be used in
+               the vmx file.
 
 =cut
 
@@ -4180,40 +4287,52 @@ sub get_vm_os_configuration {
        # Return previously retrieved data if it exists
        return $self->{vm_os_configuration} if $self->{vm_os_configuration};
        
-       my $image_os_type = $self->data->get_image_os_type() || return;
        my $image_os_name = $self->data->get_image_os_name() || return;
+       my $image_os_type = $self->data->get_image_os_type();
        my $image_architecture = $self->data->get_image_architecture() || 
return;
        
        # Figure out the key name in the %VM_OS_CONFIGURATION hash for the 
guest OS
-       my $vm_os_configuration_key;
-       if ($image_os_type =~ /linux/i) {
-               $vm_os_configuration_key = "linux-$image_architecture";
-       }
-       elsif ($image_os_type =~ /windows/i) {
-               my $regex = 'xp|2003|2008|vista|7';
-               $image_os_name =~ /($regex)/i;
-               my $windows_product = $1;
-               if (!$windows_product) {
-                       notify($ERRORS{'WARNING'}, 0, "unsupported Windows 
product: $image_os_name, it does not contain ($regex), using default values for 
Windows");
-                       $windows_product = 'windows';
+       for my $vm_os_configuration_key (keys(%VM_OS_CONFIGURATION)) {
+               my ($os_product_name, $os_architecture) = 
$vm_os_configuration_key =~ /(.+)-(.+)/;
+               if (!$os_product_name || !$os_architecture) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to parse VM OS 
configuration key: $vm_os_configuration_key, format should be <OS product 
name>-<architecture>");
+                       next;
+               }
+               elsif ($image_architecture ne $os_architecture) {
+                       next;
+               }
+               elsif ($image_os_name !~ /$os_product_name/) {
+                       next;
+               }
+               else {
+                       $self->{vm_os_configuration} = 
$VM_OS_CONFIGURATION{$vm_os_configuration_key};
+                       notify($ERRORS{'DEBUG'}, 0, "returning matching 
'$vm_os_configuration_key' OS configuration: $image_os_name, image 
architecture: $image_architecture\n" . 
format_data($self->{vm_os_configuration}));
                }
-               $vm_os_configuration_key = 
"$windows_product-$image_architecture";
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "unsupported OS type: 
$image_os_type, using default values");
-               $vm_os_configuration_key = "default-$image_architecture";
        }
        
-       # Retrieve the information from the hash, set an object variable
-       $self->{vm_os_configuration} = 
$VM_OS_CONFIGURATION{$vm_os_configuration_key};
-       if ($self->{vm_os_configuration}) {
-               notify($ERRORS{'DEBUG'}, 0, "retrieved default VM configuration 
for OS: $vm_os_configuration_key\n" . 
format_data($self->{vm_os_configuration}));
-               return $self->{vm_os_configuration};
-       }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "failed to find default VM 
configuration for OS: $vm_os_configuration_key");
-               return;
+       if (!$self->{vm_os_configuration}) {
+               # Check if the default key exists for the OS type - 'windows', 
'linux', etc.
+               if ($self->{vm_os_configuration} = 
$VM_OS_CONFIGURATION{"$image_os_type-$image_architecture"}) {
+                       notify($ERRORS{'DEBUG'}, 0, "returning default 
'$image_os_type' OS configuration, architecture: $image_architecture\n" . 
format_data($self->{vm_os_configuration}));
+               }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "default VM OS 
configuration key '$image_os_type-$image_architecture' does not exist for image 
OS type: $image_os_type, image architecture: $image_architecture");
+                       
+                       # Check if the default key exists for the image 
architecture
+                       if ($self->{vm_os_configuration} = 
$VM_OS_CONFIGURATION{"default-$image_architecture"}) {
+                               notify($ERRORS{'DEBUG'}, 0, "returning default 
OS configuration, architecture: $image_architecture\n" . 
format_data($self->{vm_os_configuration}));
+                       }
+                       else {
+                               notify($ERRORS{'WARNING'}, 0, "default VM OS 
configuration key 'default-$image_architecture' does not exist for image 
architecture: $image_architecture");
+                               
+                               # Unable to locate closest matching key, return 
default x86 configuration
+                               $self->{vm_os_configuration} = 
$VM_OS_CONFIGURATION{"default-x86"};
+                               notify($ERRORS{'DEBUG'}, 0, "returning default 
x86 OS configuration\n" . format_data($self->{vm_os_configuration}));
+                       }
+               }
        }
+       
+       return $self->{vm_os_configuration};
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -4285,8 +4404,6 @@ sub get_vm_ram {
                return;
        }
        
-       my $minimum_vm_ram_mb = 512;
-       
        # Get the image minram setting
        my $image_minram_mb = $self->data->get_image_minram();
        if (!defined($image_minram_mb)) {
@@ -4298,16 +4415,21 @@ sub get_vm_ram {
        if ($image_minram_mb % 4) {
                my $image_minram_mb_original = $image_minram_mb;
                $image_minram_mb -= ($image_minram_mb % 4);
-               notify($ERRORS{'DEBUG'}, 0, "image minram value is not a 
multiple of 4: $image_minram_mb_original, adjusting to $image_minram_mb");
+               notify($ERRORS{'DEBUG'}, 0, "image minimum RAM value 
($image_minram_mb_original MB) is not a multiple of 4, adjusting to 
$image_minram_mb MB");
        }
        
        # Check if the image setting is too low
-       if ($image_minram_mb < $minimum_vm_ram_mb) {
-               notify($ERRORS{'DEBUG'}, 0, "image ram setting is too low: 
$image_minram_mb MB, $minimum_vm_ram_mb MB will be used");
-               return $minimum_vm_ram_mb;
+       # Get the minimum memory size for the OS
+       my $vm_os_configuration = $self->get_vm_os_configuration();
+       my $vm_guest_os = $vm_os_configuration->{guestOS} || 'unknown';
+       my $vm_os_memsize = $vm_os_configuration->{memsize} || 512;
+       if ($image_minram_mb < $vm_os_memsize) {
+               notify($ERRORS{'DEBUG'}, 0, "image minimum RAM value 
($image_minram_mb MB) is too low for the $vm_guest_os guest OS, adjusting to 
$vm_os_memsize MB");
+               return $vm_os_memsize;
+       }
+       else {
+               return $image_minram_mb;
        }
-       
-       return $image_minram_mb;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -4507,6 +4629,58 @@ sub get_vmx_info {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_reference_vmx_info
+
+ Parameters  : none
+ Returns     : hash reference
+ Description : Checks if the reference vmx file exists for the image and 
returns
+               a hash reference containing the data contained in the file. This
+               data is the configuration used when the image was captured.
+
+=cut
+
+sub get_reference_vmx_info {
+       my $self = shift;
+       if (ref($self) !~ /module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Check if the reference vmx info has already been retrieved
+       if ($self->{reference_vmx_info}) {
+               return $self->{reference_vmx_info};
+       }
+       
+       # Check if it was already determined that the reference vmx file 
doesn't exist
+       # $self->{reference_vmx_info} is set to 0 if the file doesn't exist
+       if (defined($self->{reference_vmx_info}) && 
!$self->{reference_vmx_info}) {
+               return 0;
+       }
+       
+       # Get the reference vmx file path and check if the file exists
+       my $reference_vmx_file_path = $self->get_reference_vmx_file_path();
+       if (!$self->vmhost_os->file_exists($reference_vmx_file_path)) {
+               notify($ERRORS{'DEBUG'}, 0, "reference vmx file does not exist: 
$reference_vmx_file_path");
+               # Set $self->{reference_vmx_info} to 0 so this subroutine 
doesn't have to check if it exists again on subsequent calls
+               $self->{reference_vmx_info} = 0;
+               return 0;
+       }
+       
+       # Retrieve the info from the file
+       my $reference_vmx_info = $self->get_vmx_info($reference_vmx_file_path);
+       if ($reference_vmx_info) {
+               notify($ERRORS{'DEBUG'}, 0, "retrieved reference vmx info from 
file: $reference_vmx_file_path");
+               $self->{reference_vmx_info} = $reference_vmx_info;
+               return $reference_vmx_info;
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve reference vmx 
info from file: $reference_vmx_file_path");
+               return;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 delete_vm
 
  Parameters  : $vmx_file_path
@@ -4751,9 +4925,19 @@ sub copy_vmdk {
                return;
        }
        
+       # Normalize the file paths
        $source_vmdk_file_path = 
$self->_get_normal_path($source_vmdk_file_path) || return;
        $destination_vmdk_file_path = 
$self->_get_normal_path($destination_vmdk_file_path) || return;
        
+       my $source_directory_path = 
$self->_get_parent_directory_normal_path($source_vmdk_file_path) || return;
+       my $destination_directory_path = 
$self->_get_parent_directory_normal_path($destination_vmdk_file_path) || return;
+       
+       # Construct the source and destination reference vmx file paths
+       # The reference vmx file is copied to the vmdk directory if it exists
+       my $reference_vmx_file_name = $self->get_reference_vmx_file_name();
+       my $source_reference_vmx_file_path = 
"$source_directory_path/$reference_vmx_file_name";
+       my $destination_reference_vmx_file_path = 
"$destination_directory_path/$reference_vmx_file_name";
+       
        # Set the default virtual disk type if the argument was not specified
        if (!$virtual_disk_type) {
                if ($vmhost_product_name =~ /esx/i) {
@@ -4782,16 +4966,9 @@ sub copy_vmdk {
                return;
        }
        
-       # Get the destination parent directory path and create the directory
-       my ($destination_directory_path) = $destination_vmdk_file_path =~ 
/(.+)\/[^\/]+/;
-       if (!$self->vmhost_os->create_directory($destination_directory_path)) {
-               notify($ERRORS{'WARNING'}, 0, "unable to copy vmdk, destination 
directory could not be created on VM host $vmhost_name: 
$destination_directory_path");
-               return;
-       }
-       
        my $start_time = time;
        my $copy_result = 0;
-       
+
        # Attempt to use the API's copy_virtual_disk subroutine
        if ($self->api->can('copy_virtual_disk')) {
                if ($self->api->copy_virtual_disk($source_vmdk_file_path, 
$destination_vmdk_file_path, $virtual_disk_type)) {
@@ -4809,6 +4986,13 @@ sub copy_vmdk {
                notify($ERRORS{'WARNING'}, 0, "failed to copy vmdk on VM host 
$vmhost_name, unable to copy using API's copy_virtual_disk subroutine and an 
'execute' subroutine is not implemented by the VM host OS object");
                return;
        }
+       elsif (!$copy_result) {
+               # Create the destination directory
+               if 
(!$self->vmhost_os->create_directory($destination_directory_path)) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to copy vmdk, 
destination directory could not be created on VM host $vmhost_name: 
$destination_directory_path");
+                       return;
+               }
+       }
        
        if (!$copy_result) {
                # Try to use vmkfstools
@@ -4905,6 +5089,12 @@ sub copy_vmdk {
        # Check if any of the methods was successful
        if (!$copy_result) {
                notify($ERRORS{'WARNING'}, 0, "failed to copy virtual disk on 
VM host $vmhost_name using any available methods:\n'$source_vmdk_file_path' --> 
'$destination_vmdk_file_path'");
+               
+               # Delete the destination directory
+               if 
(!$self->vmhost_os->delete_file($destination_directory_path)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to delete 
destination directory after failing to copy virtual disk on VM host 
$vmhost_name: $destination_directory_path");
+               }
+               
                return;
        }
        
@@ -4920,11 +5110,21 @@ sub copy_vmdk {
                $seconds = "0$seconds";
        }
        
+       # Check if the reference vmx file exists in the source directory
+       # Copy it to the destination directory if it does exist
+       if ($self->vmhost_os->file_exists($source_reference_vmx_file_path)) {
+               notify($ERRORS{'DEBUG'}, 0, "copying reference vmx file to vmdk 
directory: '$source_reference_vmx_file_path' --> 
'$destination_reference_vmx_file_path'");
+               if 
(!$self->vmhost_os->copy_file($source_reference_vmx_file_path, 
$destination_reference_vmx_file_path)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to copy reference 
vmx file to vmdk directory: '$source_reference_vmx_file_path' --> 
'$destination_reference_vmx_file_path'");
+               }
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "reference vmx file not copied to 
vmdk directory because it does not exist: '$source_reference_vmx_file_path'");
+       }
+       
        # Get the size of the copied vmdk files
        my $search_path = $destination_vmdk_file_path;
-       $search_path =~ s/\.vmdk$//g;
-       $search_path .= '*.vmdk';
-       
+       $search_path =~ s/(\.vmdk)$/\*$1/i;
        my $image_size_bytes = $self->vmhost_os->get_file_size($search_path);
        if (!defined($image_size_bytes) || $image_size_bytes !~ /^\d+$/) {
                notify($ERRORS{'WARNING'}, 0, "copied vmdk on VM host 
$vmhost_name but failed to retrieve destination file 
size:\n'$source_vmdk_file_path' --> '$destination_vmdk_file_path'");


Reply via email to