Author: arkurth
Date: Wed Apr 22 19:59:24 2015
New Revision: 1675483

URL: http://svn.apache.org/r1675483
Log:
VCL-844
Added subroutines to VMware.pm:
* get_vmx_url_base_directory_path
* get_vmx_intermediate_directory_path
* _get_datastore_url
* _get_url_path
* configure_vmhost_ssh_keys
* copy_vmhost_ssh_public_key_to_another_host
* copy_file_to_another_host
* setup_migrate_vm
* migrate_vm
* migrate_revert_source

Added subroutines to utils.pm:
* update_computer_vmhost_id.
* setup_get_hash_multiple_choice.

Updated Module.pm::new to call initialize on ManagementNode.pm objects even if 
$SETUP_MODE is true.

Updated Module.pm::create_object to accept an additional argument which allows 
arguments to be passed to the constructor of the object being created as well 
as the DataStructure.pm object.

Updated Module.pm::create_vmhost_os_object to accept an argument specifying 
which VM host to create an object for.

Updated DataStructure.pm to accept a vmhost_identifier argument rather than use 
a vmhost_id argument.

Changed where cached data is stored from %ENV to $self in order to allow it to 
work with multiple VMware.pm objects.


VCL-851
Added check to skip the attempt to use vSphere_SDK.pm if vmprofile.password is 
not configured.

Modified:
    vcl/trunk/managementnode/lib/VCL/DataStructure.pm
    vcl/trunk/managementnode/lib/VCL/Module.pm
    vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm
    vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
    vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1675483&r1=1675482&r2=1675483&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Wed Apr 22 19:59:24 2015
@@ -579,14 +579,14 @@ my @blockrequest_data : Field : Arg('Nam
 
 my @computer_identifier : Field : Arg('Name' => 'computer_identifier') : 
Type(scalar) : Get('Name' => 'computer_identifier', 'Private' => 1);
 
-=head3 @vmhost_id
+=head3 @vmhost_identifier
 
  Data type   : array of scalars
  Description :
 
 =cut
 
-my @vmhost_id : Field : Arg('Name' => 'vmhost_id') : Type(scalar) : Get('Name' 
=> 'vmhost_id', 'Private' => 1);
+my @vmhost_identifier : Field : Arg('Name' => 'vmhost_identifier') : 
Type(scalar) : Get('Name' => 'vmhost_identifier', 'Private' => 1);
 
 =head3 @image_identifier
 
@@ -658,7 +658,7 @@ sub _initialize : Init {
        }
 
        my $computer_identifier = $self->computer_identifier;
-       my $vmhost_id = $self->vmhost_id;
+       my $vmhost_identifier = $self->vmhost_identifier;
        my $image_identifier = $self->image_identifier;
        my $imagerevision_identifier = $self->imagerevision_identifier;
        
@@ -677,15 +677,15 @@ sub _initialize : Init {
                
$self->request_data->{reservation}{$self->reservation_id}{computer} = 
$computer_info;
        }
        
-       # Get the VM host info if the vmhost_id argument was specified and add 
it to this object
-       if ($vmhost_id) {
-               notify($ERRORS{'DEBUG'}, 0, "VM host identifier argument was 
specified, retrieving data for VM host: $vmhost_id");
-               my $vmhost_info = get_vmhost_info($vmhost_id, 1);
+       # Get the VM host info if the $vmhost_identifier argument was specified 
and add it to this object
+       if ($vmhost_identifier) {
+               notify($ERRORS{'DEBUG'}, 0, "VM host identifier argument was 
specified, retrieving data for VM host: $vmhost_identifier");
+               my $vmhost_info = get_vmhost_info($vmhost_identifier, 1);
                if (!$vmhost_info) {
-                       notify($ERRORS{'WARNING'}, 0, "DataStructure object 
could not be initialized, failed to retrieve data for VM host: $vmhost_id");
+                       notify($ERRORS{'WARNING'}, 0, "DataStructure object 
could not be initialized, failed to retrieve data for VM host: 
$vmhost_identifier");
                        
                        # Throw an exception because simply returning undefined 
(return;) does not result in this DataStructure object being undefined
-                       Exception::Class::Base->throw( error => "DataStructure 
object could not be initialized, failed to retrieve data for VM host: 
$vmhost_id");
+                       Exception::Class::Base->throw( error => "DataStructure 
object could not be initialized, failed to retrieve data for VM host: 
$vmhost_identifier");
                        return;
                }
                
$self->request_data->{reservation}{$self->reservation_id}{computer}{vmhost} = 
$vmhost_info;

Modified: vcl/trunk/managementnode/lib/VCL/Module.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module.pm?rev=1675483&r1=1675482&r2=1675483&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module.pm Wed Apr 22 19:59:24 2015
@@ -178,26 +178,28 @@ sub new {
        # Get the memory address of this newly created object - useful for 
debugging object creation problems
        my $address = sprintf('%x', $self);
        
+       my $type = ref($self);
+       
        # Display a message based on the type of object created
        if ($self->isa('VCL::Module::State')) {
                my $request_state_name = $self->data->get_request_state_name(0) 
|| '<not set>';
-               notify($ERRORS{'DEBUG'}, 0, ref($self) . " object created for 
state $request_state_name, address: $address");
+               notify($ERRORS{'DEBUG'}, 0, "$type object created for state 
$request_state_name, address: $address");
        }
        elsif ($self->isa('VCL::Module::OS') && 
!$self->isa('VCL::Module::OS::Linux::ManagementNode')) {
                my $image_name = $self->data->get_image_name(0) || '<not set>';
-               notify($ERRORS{'DEBUG'}, 0, ref($self) . " object created for 
image $image_name, address: $address");
+               notify($ERRORS{'DEBUG'}, 0, "$type object created for image 
$image_name, address: $address");
        }
        elsif ($self->isa('VCL::Module::Provisioning')) {
                my $computer_name = $self->data->get_computer_short_name(0) || 
'<not set>';
-               notify($ERRORS{'DEBUG'}, 0, ref($self) . " object created for 
computer $computer_name, address: $address");
+               notify($ERRORS{'DEBUG'}, 0, "$type object created for computer 
$computer_name, address: $address");
        }
        else {
-               notify($ERRORS{'DEBUG'}, 0, ref($self) . " object created, 
address: $address");
+               notify($ERRORS{'DEBUG'}, 0, "$type object created, address: 
$address");
        }
        
        # Create a management node OS object
        # Check to make sure the object currently being created is not a MN OS 
object to avoid endless loop
-       if (!$self->isa('VCL::Module::OS::Linux::ManagementNode')) {
+       if (!$self->isa('VCL::Module::OS::Linux::ManagementNode') && 
!$self->isa('VCL::Module::State')) {
                my $mn_os;
                # Check if the mn_os argument was provided
                if ($args->{mn_os}) {
@@ -221,10 +223,15 @@ sub new {
        }
        
        # Check if not running in setup mode and if initialize() subroutine is 
defined for this module
-       if (!$SETUP_MODE && $self->can("initialize")) {
-               # Call the initialize() subroutine, if it returns 0, return 0
-               # If it doesn't return 0, return the object reference
-               return if (!$self->initialize($args));
+       if (!$SETUP_MODE || 
$self->isa('VCL::Module::OS::Linux::ManagementNode')) {
+               if ($self->can("initialize")) {
+                       # Call the initialize() subroutine, if it returns 0, 
return 0
+                       # If it doesn't return 0, return the object reference
+                       return if (!$self->initialize($args));
+               }
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "initialize not called for $type 
object ($address) because \$SETUP_MODE is true");
        }
 
        return $self;
@@ -289,7 +296,7 @@ sub create_datastructure_object {
 
 =head2 create_object
 
- Parameters  : $perl_package, $data_structure_arguments (optional)
+ Parameters  : $perl_package, $data_structure_arguments (optional), 
$object_argument_hashref (optional)
  Returns     : VCL::Module object reference
  Description : This is a general constructor to create VCL::Module objects. It
                contains the code to call 'use $perl_package', instantiate an
@@ -321,8 +328,14 @@ sub create_object {
        my $data;
        my $data_structure_arguments = shift;
        if ($data_structure_arguments) {
-               notify($ERRORS{'DEBUG'}, 0, "new DataStructure object will be 
created for the $perl_package object, data structure arguments passed:\n" . 
format_data($data_structure_arguments));
-               $data = create_datastructure_object($data_structure_arguments);
+               if (ref($data_structure_arguments) && 
ref($data_structure_arguments) =~ /DataStructure/) {
+                       notify($ERRORS{'DEBUG'}, 0, "DataStructure object 
argument will be passed to the new $perl_package object");
+                       $data = $data_structure_arguments;
+               }
+               else {
+                       notify($ERRORS{'DEBUG'}, 0, "new DataStructure object 
will be created for the $perl_package object, data structure arguments 
passed:\n" . format_data($data_structure_arguments));
+                       $data = 
create_datastructure_object($data_structure_arguments);
+               }
        }
        elsif (!$self) {
                notify($ERRORS{'DEBUG'}, 0, "new DataStructure object will be 
created for the $perl_package object, data structure arguments not passed and 
not called as an object reference");
@@ -332,6 +345,20 @@ sub create_object {
                notify($ERRORS{'DEBUG'}, 0, "existing DataStructure object will 
be passed to the new $perl_package object");
                $data = $self->data;
        }
+       
+       my $object_argument_hashref = shift;
+       if ($object_argument_hashref) {
+               my $type = ref($object_argument_hashref);
+               if (!$type) {
+                       notify($ERRORS{'WARNING'}, 0, "3rd argument is not a 
reference, it must be a hash reference: $object_argument_hashref");
+                       return;
+               }
+               elsif ($type ne 'HASH') {
+                       notify($ERRORS{'WARNING'}, 0, "3rd argument is a $type 
reference, it must be a hash reference");
+                       return;
+               }
+       }
+       $object_argument_hashref->{data_structure} = $data;
 
        # Attempt to load the module
        eval "use $perl_package";
@@ -344,7 +371,7 @@ sub create_object {
        # Attempt to create the object
        my $object;
        eval {
-               $object = ($perl_package)->new({data_structure => $data})
+               $object = ($perl_package)->new($object_argument_hashref)
        };
        
        if ($EVAL_ERROR) {
@@ -500,7 +527,7 @@ sub create_mn_os_object {
 
 =head2 create_vmhost_os_object
 
- Parameters  : none
+ Parameters  : $vmhost_identifier (optional)
  Returns     : boolean
  Description : Creates an OS object for the VM host.
 
@@ -513,9 +540,15 @@ sub create_vmhost_os_object {
                return;
        }
        
-       # Check if an OS object has already been stored in the calling object
-       if (my $vmhost_os = $self->vmhost_os(0)) {
-               return $vmhost_os;
+       my $vmhost_identifier = shift;
+       
+       if (!$vmhost_identifier) {
+               # Check if an OS object has already been stored in the calling 
object
+               if (my $vmhost_os = $self->vmhost_os(0)) {
+                       my $address = sprintf('%x', $vmhost_os);
+                       notify($ERRORS{'DEBUG'}, 0, "returning existing VM host 
OS object ($address)");
+                       return $vmhost_os;
+               }
        }
        
        # Make sure calling object isn't an OS module to avoid an infinite loop
@@ -526,20 +559,56 @@ sub create_vmhost_os_object {
        
        my $request_data = $self->data->get_request_data();
        my $reservation_id = $self->data->get_reservation_id();
-       my $vmhost_computer_id = $self->data->get_vmhost_computer_id();
-       my $vmhost_hostname = $self->data->get_vmhost_hostname();
-       my $vmhost_profile_image_id = 
$self->data->get_vmhost_profile_image_id();
+       
+       my $vmhost_computer_id;
+       my $vmhost_hostname;
+       my $vmhost_profile_image_id;
+       if ($vmhost_identifier) {
+               my $vmhost_info = get_vmhost_info($vmhost_identifier);
+               if (!$vmhost_info) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to create VM host 
OS object for host specified by argument: $vmhost_identifier, VM host info 
could not be retrieved");
+                       return;
+               }
+               
+               $vmhost_computer_id = $vmhost_info->{computerid};
+               if (!$vmhost_computer_id) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to create VM host 
OS object for host specified by argument: $vmhost_identifier, VM host computer 
ID could not be determined from VM host info:\n" . format_data($vmhost_info));
+                       return;
+               }
+               
+               $vmhost_hostname = $vmhost_info->{computer}{hostname};
+               if (!$vmhost_hostname) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to create VM host 
OS object for host specified by argument: $vmhost_identifier, VM host computer 
hostname could not be determined from VM host info:\n" . 
format_data($vmhost_info));
+                       return;
+               }
+               
+               $vmhost_profile_image_id = $vmhost_info->{vmprofile}{imageid};
+               if (!$vmhost_profile_image_id) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to create VM host 
OS object for host specified by argument: $vmhost_identifier, VM host profile 
image ID could not be determined from VM host info:\n" . 
format_data($vmhost_info));
+                       return;
+               }
+       }
+       else {
+               # Argument was not supplied, use reservation data
+               $vmhost_computer_id = $self->data->get_vmhost_computer_id();
+               $vmhost_hostname = $self->data->get_vmhost_hostname();
+               $vmhost_profile_image_id = 
$self->data->get_vmhost_profile_image_id();
+               if (!$vmhost_computer_id || !$vmhost_hostname || 
!defined($vmhost_profile_image_id)) {
+                       notify($ERRORS{'WARNING'}, 0, "unable to create VM host 
OS object, VM host computer ID, hostname, and profile image ID could not be 
determined from reservation data");
+                       return;
+               }
+       }
        
        # Create a DataStructure object containing computer data for the VM host
        my $vmhost_data;
        eval {
                $vmhost_data = new VCL::DataStructure({
-                                                                               
                                        request_data => $request_data,
-                                                                               
                                        reservation_id => $reservation_id,
-                                                                               
                                        computer_identifier => 
$vmhost_computer_id,
-                                                                               
                                        image_identifier => 
$vmhost_profile_image_id
-                                                                               
                                        }
-                                                                               
                                );
+                       request_data => $request_data,
+                       reservation_id => $reservation_id,
+                       computer_identifier => $vmhost_computer_id,
+                       image_identifier => $vmhost_profile_image_id
+                       }
+               );
        };
        
        if ($EVAL_ERROR) {

Modified: vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm?rev=1675483&r1=1675482&r2=1675483&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm 
(original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm Wed 
Apr 22 19:59:24 2015
@@ -1068,7 +1068,7 @@ sub get_registered_vms {
        }
        
        # Get the vmx path values for each VM
-       my @vmx_paths = values(%$vm_list);
+       my @vmx_paths = sort { lc($a) cmp lc($b) } values(%$vm_list);
        
        notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@vmx_paths) . " 
registered VMs");
        return @vmx_paths;
@@ -1302,7 +1302,7 @@ sub vm_power_off {
 
  Parameters  : $vmx_file_path
  Returns     : boolean
- Description : Powers off the VM indicated by the vmx file path argument.
+ Description : Suspends the VM indicated by the vmx file path argument.
 
 =cut
 
@@ -1340,6 +1340,8 @@ sub vm_suspend {
                return;
        }
        
+       notify($ERRORS{'DEBUG'}, 0, "suspending VM: $vmx_file_path ($vm_id)");
+       my $start_time = time;
        my $vim_cmd_arguments = "vmsvc/power.suspend $vm_id";
        my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 
400);
        return if !$output;
@@ -1365,7 +1367,8 @@ sub vm_suspend {
        
        # Wait for the task to complete
        if ($self->_wait_for_task($task_ids[0])) {
-               notify($ERRORS{'OK'}, 0, "suspended VM: $vmx_file_path");
+               my $duration = (time - $start_time);
+               notify($ERRORS{'OK'}, 0, "suspended VM: $vmx_file_path, took 
$duration seconds");
                return 1;
        }
        else {
@@ -2702,9 +2705,17 @@ sub _parse_vim_cmd_output {
                # Remove trailing newlines
                $line =~ s/\n+$//g;
                
-               # Remove class names at beginning of line surrounded by 
parenthesis
+               # Remove class names in parenthesis from beginning class name 
of indented lines
+               # '   (vim.vm.device.xxx) {' --> '   {'
+               $line =~ s/^(\s+)\([^\)]*\)\s*/$1/g;
+               
+               # Remove class names at beginning of a line surrounded by 
parenthesis
                # '(vim.vm.device.VirtualPointingDevice) {' --> '{'
-               $line =~ s/^(\s*)\([^\)]*\)\s*/$1/g;
+               $line =~ s/^\(([^\)]+)\)\s*{/'$1' => {/gx;
+               
+               # Add comma to lines containing a closing curly bracket
+               # '   }' --> '   },'
+               $line =~ s/^(\s*)}\s*$/$1},/g;
                
                # Remove class names after an equals sign
                # 'backing = (vim.vm.device.VirtualDevice.BackingInfo) null,' 
--> 'backing = null'
@@ -2729,6 +2740,9 @@ sub _parse_vim_cmd_output {
                $numbered_statement .= "$line_number:$line\n";
        }
        
+       # Enclose the entire statement in curly brackets
+       $statement = "{\n$statement\n}";
+
        # The statement variable should contain a valid definition
        my $result = eval($statement);
        if ($EVAL_ERROR) {
@@ -2743,6 +2757,169 @@ sub _parse_vim_cmd_output {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 _get_vm_virtual_disk_file_layout
+
+ Parameters  : $vmx_file_path
+ Returns     : hash reference
+ Description : Retrieves a VM's virtual disk file layout as reported by:
+               vim-cmd vmsvc/get.filelayout <VM ID>
+               A hash reference is returned:
+               {
+                 "vim.vm.FileInfo" => {
+                   "dynamicType" => "<unset>",
+                   "ftMetadataDirectory" => "<unset>",
+                   "logDirectory" => "[blade1e1-10-vmpath] arkvmm160_3868-v0",
+                   "snapshotDirectory" => "[blade1e1-10-vmpath] 
arkvmm160_3868-v0",
+                   "suspendDirectory" => "[blade1e1-10-vmpath] 
arkvmm160_3868-v0",
+                   "vmPathName" => "[blade1e1-10-vmpath] 
arkvmm160_3868-v0/arkvmm160_3868-v0.vmx"
+                 },
+                 "vim.vm.FileLayout" => {
+                   "configFile" => [
+                     "arkvmm160_3868-v0.vmxf",
+                     "nvram",
+                     "arkvmm160_3868-v0.vmsd"
+                   ],
+                   "disk" => [
+                     {
+                       "diskFile" => [
+                         "[datastore-compressed] 
vmwarewinxp-xpsp33868-v0/vmwarewinxp-xpsp33868-v0.vmdk",
+                         "[blade1e1-10-vmpath] 
arkvmm160_3868-v0/vmwarewinxp-xpsp33868-v0-000001.vmdk"
+                       ],
+                       "dynamicType" => "<unset>",
+                       "key" => 3000
+                     },
+                     {
+                       "diskFile" => [
+                         "[blade1e1-10-vmpath] 
arkvmm160_3868-v0/arkvmm160_3868-v0.vmdk"
+                       ],
+                       "dynamicType" => "<unset>",
+                       "key" => 2000
+                     }
+                   ],
+                   "dynamicType" => "<unset>",
+                   "logFile" => [
+                     "vmware-1.log",
+                     "vmware-2.log",
+                     "vmware-3.log",
+                     "vmware.log"
+                   ],
+                   "snapshot" => [
+                     {
+                       "dynamicType" => "<unset>",
+                       "key" => "'vim.vm.Snapshot:576-snapshot-1'",
+                       "snapshotFile" => [
+                         "[blade1e1-10-vmpath] 
arkvmm160_3868-v0/arkvmm160_3868-v0-Snapshot1.vmsn",
+                         "[datastore-compressed] 
vmwarewinxp-xpsp33868-v0/vmwarewinxp-xpsp33868-v0.vmdk"
+                       ]
+                     }
+                   ],
+                   "swapFile" => "<unset>"
+                 }
+               }
+
+=cut
+
+sub _get_vm_virtual_disk_file_layout {
+       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 $vmx_file_path = shift;
+       if (!$vmx_file_path) {
+               notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not 
specified");
+               return;
+       }
+       
+       # Get the VM ID
+       my $vm_id = $self->_get_vm_id($vmx_file_path);
+       if (!defined($vm_id)) {
+               notify($ERRORS{'WARNING'}, 0, "unable to power off VM because 
VM ID could not be determined");
+               return;
+       }
+       
+       my $vim_cmd_arguments = "vmsvc/get.filelayout $vm_id";
+       my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
+       return if !$output;
+       
+       my $virtual_disk_file_layout = $self->_parse_vim_cmd_output($output);
+       if ($virtual_disk_file_layout) {
+               notify($ERRORS{'DEBUG'}, 0, "retrieved virtual disk file layout 
for VM $vm_id ($vmx_file_path)\n" . format_data($virtual_disk_file_layout));
+               return $virtual_disk_file_layout;
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve virtual disk 
file layout for VM $vm_id ($vmx_file_path)");
+               return;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vm_virtual_disk_file_paths
+
+ Parameters  : $vmx_file_path
+ Returns     : array reference
+ Description : Retrieves a VM's virtual disk file layout and returns an array
+               reference. Each top-level array element represent entire virtual
+               disk and contains an array reference containing the virtual
+               disk's files:
+               [
+                 [
+                   
"/vmfs/volumes/datastore/vmwarewin7-bare3844-v1/vmwarewin7-bare3844-v1.vmdk",
+                   
"/vmfs/volumes/blade-vmpath/vm170_3844-v1/vmwarewin7-bare3844-v1-000001.vmdk",
+                   
"/vmfs/volumes/blade-vmpath/vm170_3844-v1/vmwarewin7-bare3844-v1-000002.vmdk",
+                   
"/vmfs/volumes/blade-vmpath/vm170_3844-v1/vmwarewin7-bare3844-v1-000003.vmdk"
+                 ],
+                 [
+                   
"/vmfs/volumes/blade-vmpath/vm170_3844-v1/vm170_3844-v1.vmdk"
+                 ]
+               ]
+
+=cut
+
+sub get_vm_virtual_disk_file_paths {
+       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 $vmx_file_path = shift;
+       if (!$vmx_file_path) {
+               notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not 
specified");
+               return;
+       }
+       
+       my $virtual_disk_file_layout = 
$self->_get_vm_virtual_disk_file_layout($vmx_file_path) || return;
+       
+       my $virtual_disk_array_ref = 
$virtual_disk_file_layout->{'vim.vm.FileLayout'}{'disk'};
+       if (!$virtual_disk_array_ref) {
+               notify($ERRORS{'WARNING'}, 0, "unable to determine virtual disk 
file paths, failed to retrieve {'vim.vm.FileLayout'}{'disk'} array reference 
from virtual disk file layout:\n" . format_data($virtual_disk_file_layout));
+               return;
+       }
+       elsif (!ref($virtual_disk_array_ref) || ref($virtual_disk_array_ref) ne 
'ARRAY') {
+               notify($ERRORS{'WARNING'}, 0, "unable to determine virtual disk 
file paths, virtual disk file layout {'vim.vm.FileLayout'}{'disk'} key does not 
contain an array reference:\n" . format_data($virtual_disk_array_ref));
+               return;
+       }
+       
+       my @virtual_disks;
+       for my $virtual_disk_ref (@$virtual_disk_array_ref) {
+               my $disk_file_array_ref = $virtual_disk_ref->{'diskFile'};
+               my @virtual_disk_file_paths;
+               for my $virtual_disk_file_path (@$disk_file_array_ref) {
+                       push @virtual_disk_file_paths, 
$self->_get_normal_path($virtual_disk_file_path);
+               }
+               push @virtual_disks, \@virtual_disk_file_paths;
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved virtual disk file paths for 
$vmx_file_path:\n" . format_data(\@virtual_disks));
+       return @virtual_disks;
+}
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 DESTROY
 
  Parameters  : none


Reply via email to