Author: arkurth Date: Thu Aug 4 17:02:25 2011 New Revision: 1153929 URL: http://svn.apache.org/viewvc?rev=1153929&view=rev Log: VCL-470 Added code contributed by Aaron Coburn included in the Jira issue to add a vSphere_SDK.pm::get_total_space subroutine.
VCL-471 Updated VMware.pm::_get_parent_directory_normal_path() to allow non-datastore paths to be specified. This solves a problem where a path residing on the management node is passed, but the subroutine fails. VCL-450 Fixed a problem where vSphere_SDK.pm::copy_virtual_disk failed because the vmdk adapter type is not listed in the typical info if a snapshot has been created. Updated vSphere.pm to cache most of the SDK object types it uses including host, vm, datastore. This prevents the code from having to fetch a new object every time, greatly increasing speed. This also reduced a lot of duplicated code. Fixed problem in VMware.pm::node_status. It was not accounting for VMs loaded before the snapshot functionality was added which were using nonpersistent mode. Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.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=1153929&r1=1153928&r2=1153929&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 Thu Aug 4 17:02:25 2011 @@ -1008,6 +1008,7 @@ sub node_status { my $reservation_id = $self->data->get_reservation_id(); my $computer_name = $self->data->get_computer_node_name(); my $image_name = $self->data->get_image_name(); + my $request_forimaging = $self->data->get_request_forimaging(); notify($ERRORS{'DEBUG'}, 0, "attempting to check the status of computer $computer_name, image: $image_name"); @@ -1068,7 +1069,8 @@ sub node_status { } # If the VM is dedicated, check if the vmdk of the VM already loaded is shared or dedicated - if ($self->is_vm_dedicated()) { + my $is_vm_dedicated = $self->is_vm_dedicated(); + if ($request_forimaging || $is_vm_dedicated) { # Determine the vmx file path actively being used by the VM my $vmx_file_path = $self->get_active_vmx_file_path(); if (!$vmx_file_path) { @@ -1102,7 +1104,6 @@ sub node_status { notify($ERRORS{'WARNING'}, 0, "vmdk file path was not found in the vmx file info, returning 'RELOAD':\n" . format_data($vmx_info)); return $status; } - notify($ERRORS{'DEBUG'}, 0, "vmdk file path used by the VM already loaded: $vmdk_file_path"); # Get the vmdk mode from the vmx information and make sure it is not nonpersistent my $vmdk_mode = $vmx_info->{vmdk}{$vmdk_identifiers[0]}{mode}; @@ -1111,17 +1112,22 @@ sub node_status { return $status; } + notify($ERRORS{'DEBUG'}, 0, "vmdk file path used by the VM already loaded: $vmdk_file_path, mode: $vmdk_mode"); + + # Can't use if nonpersistent if ($vmdk_mode =~ /nonpersistent/i) { notify($ERRORS{'OK'}, 0, "VM already loaded may NOT be used, vmdk mode: '$vmdk_mode', returning 'RELOAD'"); return $status; } - if ($self->is_vmdk_shared($vmdk_file_path)) { - notify($ERRORS{'OK'}, 0, "VM already loaded may NOT be used, the vmdk appears to be shared"); - return $status; - } - else { - notify($ERRORS{'DEBUG'}, 0, "VM already loaded may be used, the vmdk does NOT appear to be shared"); + if ($is_vm_dedicated) { + if ($self->is_vmdk_shared($vmdk_file_path)) { + notify($ERRORS{'OK'}, 0, "VM already loaded may NOT be used, the vmdk appears to be shared"); + return $status; + } + else { + notify($ERRORS{'DEBUG'}, 0, "VM already loaded may be used, the vmdk does NOT appear to be shared"); + } } } @@ -3082,9 +3088,9 @@ sub get_reference_vmx_file_path { 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"); + my $vmdk_directory_path_shared = $self->get_vmdk_directory_path_shared(); + if (!$vmdk_directory_path_shared) { + notify($ERRORS{'WARNING'}, 0, "unable to construct reference vmx file path, shared vmdk directory path could not be determined"); return; } @@ -3094,7 +3100,7 @@ sub get_reference_vmx_file_path { return; } - $ENV{reference_vmx_file_path} = "$vmdk_directory_path/$reference_vmx_file_name"; + $ENV{reference_vmx_file_path} = "$vmdk_directory_path_shared/$reference_vmx_file_name"; notify($ERRORS{'DEBUG'}, 0, "determined reference vmx file path: $ENV{reference_vmx_file_path}"); return $ENV{reference_vmx_file_path}; } @@ -6019,7 +6025,7 @@ sub get_datastore_info { return; } else { - notify($ERRORS{'DEBUG'}, 0, "retrieved datastore info from VM host:\n" . join("\n", sort keys(%$datastore_info))); + notify($ERRORS{'DEBUG'}, 0, "retrieved datastore info from VM host:\n" . join(", ", sort keys(%$datastore_info))); $self->{datastore_info} = $datastore_info; return $datastore_info; } @@ -6366,6 +6372,13 @@ sub _get_parent_directory_normal_path { return; } + # If this is a normal path - remove the part after the last '/' + if ($path_argument !~ /\[.+\]/) { + $path_argument =~ s/[^\/]*\/?$//g; + return $self->_get_normal_path($path_argument); + } + + # Datastore path was passed, call datastore sub and return normal path my $parent_directory_datastore_path = $self->_get_parent_directory_datastore_path($path_argument); if (!$parent_directory_datastore_path) { notify($ERRORS{'WARNING'}, 0, "unable to determine parent directory normal path, parent directory datastore path could not be determined on which the normal path is based: '$path_argument'"); Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm?rev=1153929&r1=1153928&r2=1153929&view=diff ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm (original) +++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm Thu Aug 4 17:02:25 2011 @@ -122,12 +122,12 @@ sub vm_register { # Get the vmx path argument and convert it to a datastore path my $vmx_path = $self->_get_datastore_path(shift) || return; - my $host_view = VIExt::get_host_view(1) || return; - my $datacenter = Vim::find_entity_view (view_type => 'Datacenter') || return; + my $host_view = $self->_get_host_view() || return; + my $datacenter = $self->_get_datacenter_view() || return; my $vm_folder = Vim::get_view(mo_ref => $datacenter->{vmFolder}) || return; my $resource_pool = Vim::find_entity_view(view_type => 'ResourcePool') || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; my $vm_mo_ref; @@ -181,12 +181,7 @@ sub vm_unregister { # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'DEBUG'}, 0, "VM is not registered: $vmx_path"); - return 1; - } + my $vm = $self->_get_vm_view($vmx_path) || return; # Make sure the VM is powered off or unregister will fail $self->vm_power_off($vmx_path) || return; @@ -197,6 +192,9 @@ sub vm_unregister { return; } + # Delete the cached VM object + delete $self->{vm_view_objects}{$vmx_path}; + notify($ERRORS{'DEBUG'}, 0, "unregistered VM: $vmx_path"); return 1; } @@ -226,12 +224,7 @@ sub vm_power_on { # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'WARNING'}, 0, "unable to power on VM because it is not registered: $vmx_path"); - return; - } + my $vm = $self->_get_vm_view($vmx_path) || return; eval { $vm->PowerOnVM(); }; if ($@) { @@ -273,15 +266,10 @@ sub vm_power_off { # Get the vmx path argument and convert it to a datastore path my $vmx_path = $self->_get_datastore_path(shift) || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'WARNING'}, 0, "unable to power off VM because it is not registered: $vmx_path"); - return; - } + my $vm = $self->_get_vm_view($vmx_path) || return; eval { $vm->PowerOffVM(); }; if ($@) { @@ -326,15 +314,10 @@ sub get_vm_power_state { # Get the vmx path argument and convert it to a datastore path my $vmx_path = $self->_get_datastore_path(shift) || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'WARNING'}, 0, "unable to retrieve power state of VM because it is not registered: $vmx_path"); - return; - } + my $vm = $self->_get_vm_view($vmx_path) || return; my $power_state = $vm->runtime->powerState->val; @@ -457,40 +440,28 @@ sub copy_virtual_disk { return; } - my $destination_adapter_type = shift; + my $adapter_type = shift; # If the adapter type was not specified, retrieve it from the source vmdk file - if (!$destination_adapter_type) { - $destination_adapter_type = $self->get_virtual_disk_controller_type($source_path); - if (!$destination_adapter_type) { - notify($ERRORS{'WARNING'}, 0, "destination adapter type argument was not specifed and unable to retrieve adapter type from source vmdk file: $source_path, using lsiLogic"); - $destination_adapter_type = 'lsiLogic'; + if (!$adapter_type) { + $adapter_type = $self->get_vm_disk_adapter_type($source_path); + if (!$adapter_type) { + notify($ERRORS{'WARNING'}, 0, "adapter type argument was not specifed and unable to retrieve adapter type from source vmdk file: $source_path, using lsiLogic"); + $adapter_type = 'lsiLogic'; } } - # Check the adapter type argument, the string must match exactly or the copy will fail - my @valid_adapter_types = qw( busLogic lsiLogic ide ); - if (!grep(/^$destination_adapter_type$/, @valid_adapter_types)) { - notify($ERRORS{'WARNING'}, 0, "adapter type argument is not valid: '$destination_adapter_type', it must exactly match (case sensitive) one of the following strings:\n" . join("\n", @valid_adapter_types)); - return; - } - my $vmhost_name = $self->data->get_vmhost_hostname(); # Get a virtual disk manager object - my $service_content = Vim::get_service_content() || return; - if (!$service_content->{virtualDiskManager}) { - notify($ERRORS{'WARNING'}, 0, "unable to copy virtual disk on VM host $vmhost_name, virtual disk manager is not available through the vSphere SDK"); - return; - } - my $virtual_disk_manager = Vim::get_view(mo_ref => $service_content->{virtualDiskManager}) || return; + my $virtual_disk_manager = $self->_get_virtual_disk_manager_view() || return; # Get the destination partent directory path and create the directory my $destination_directory_path = $self->_get_parent_directory_datastore_path($destination_path) || return; $self->create_directory($destination_directory_path) || return; # Create a virtual disk spec object - my $virtual_disk_spec = VirtualDiskSpec->new(adapterType => $destination_adapter_type, + my $virtual_disk_spec = VirtualDiskSpec->new(adapterType => $adapter_type, diskType => $destination_disk_type, ); @@ -500,10 +471,9 @@ sub copy_virtual_disk { my @file_names = keys(%{$source_info}); my $info_file_name = $file_names[0]; - my $source_adapter_type = $source_info->{$info_file_name}{controllerType}; - my $source_disk_type = $source_info->{$info_file_name}{diskType}; - my $source_file_size_bytes = $source_info->{$info_file_name}{fileSize}; - if ($source_adapter_type !~ /\w/ || $source_disk_type !~ /\w/ || $source_file_size_bytes !~ /\d/) { + my $source_disk_type = $source_info->{$info_file_name}{diskType} || 'unknown'; + my $source_file_size_bytes = $source_info->{$info_file_name}{fileSize} || 'unknown'; + if ($adapter_type !~ /\w/ || $source_disk_type !~ /\w/ || $source_file_size_bytes !~ /\d/) { notify($ERRORS{'WARNING'}, 0, "unable to retrieve adapter type, disk type, and file size of source file on VM host $vmhost_name: '$source_path', file info:\n" . format_data($source_info)); return; } @@ -513,7 +483,7 @@ sub copy_virtual_disk { # Attempt to copy the file notify($ERRORS{'DEBUG'}, 0, "attempting to copy file on VM host $vmhost_name: '$source_path' --> '$destination_path' - adapter type: $source_adapter_type --> $destination_adapter_type + adapter type: $adapter_type disk type: $source_disk_type --> $destination_disk_type source file size: " . format_number($source_file_size_bytes)); @@ -590,27 +560,10 @@ sub move_virtual_disk { $self->create_directory($destination_parent_directory_path) || return; # Check if a virtual disk manager object is available - my $service_content = Vim::get_service_content() || return; - - # Check if the virtual disk manager is available - if (!$service_content->{virtualDiskManager}) { - notify($ERRORS{'OK'}, 0, "unable to move virtual disk using vSphere SDK because virtual disk manager object is not available on VM host $vmhost_name"); - return 0; - } - - # Create a virtual disk manager object - my $virtual_disk_manager = Vim::get_view(mo_ref => $service_content->{virtualDiskManager}); - if (!$virtual_disk_manager) { - notify($ERRORS{'WARNING'}, 0, "failed to create vSphere SDK virtual disk manager object on VM host $vmhost_name"); - return; - } + my $virtual_disk_manager = $self->_get_virtual_disk_manager_view() || return; # Create a datacenter object - my $datacenter = Vim::find_entity_view(view_type => 'Datacenter'); - if (!$datacenter) { - notify($ERRORS{'WARNING'}, 0, "failed to create vSphere SDK datacenter object on VM host $vmhost_name"); - return; - } + my $datacenter = $self->_get_datacenter_view() || return; # Override the die handler local $SIG{__DIE__} = sub{}; @@ -835,7 +788,7 @@ sub get_virtual_disk_controller_type { # Check if the controllerType key exists in the vmdk file info if (!defined($vmdk_file_info->{controllerType}) || !$vmdk_file_info->{controllerType}) { - notify($ERRORS{'WARNING'}, 0, "unable to retrieve controllerType value from file info: $vmdk_file_path\n" . format_data($vmdk_file_info)); + notify($ERRORS{'DEBUG'}, 0, "unable to retrieve controllerType value from file info: $vmdk_file_path\n" . format_data($vmdk_file_info)); return; } @@ -980,7 +933,7 @@ sub get_vmware_product_name { my $vmhost_hostname = $self->data->get_vmhost_hostname(); # Get the host view - my $host_view = VIExt::get_host_view(1); + my $host_view = $self->_get_host_view(); my $product_name = $host_view->config->product->fullName; if ($product_name) { @@ -1017,7 +970,7 @@ sub get_vmware_product_version { my $vmhost_hostname = $self->data->get_vmhost_hostname(); # Get the host view - my $host_view = VIExt::get_host_view(1); + my $host_view = $self->_get_host_view(); my $product_version = $host_view->config->product->version; if ($product_version) { @@ -1049,7 +1002,7 @@ sub get_network_names { } # Get the host view - my $host_view = VIExt::get_host_view(1); + my $host_view = $self->_get_host_view(); # Retrieve the network info, check if each network is accessible my @network_names; @@ -1160,8 +1113,7 @@ sub create_directory { my $vmhost_hostname = $self->data->get_vmhost_hostname(); # Get a fileManager object - my $service_content = Vim::get_service_content() || return; - my $file_manager = Vim::get_view(mo_ref => $service_content->{fileManager}) || return; + my $file_manager = $self->_get_file_manager_view() || return; # Override the die handler because MakeDirectory may call it local $SIG{__DIE__} = sub{}; @@ -1226,10 +1178,9 @@ sub delete_file { } # Get a fileManager object - my $service_content = Vim::get_service_content() || return; - my $file_manager = Vim::get_view(mo_ref => $service_content->{fileManager}) || return; + my $file_manager = $self->_get_file_manager_view() || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; # Attempt to delete the file @@ -1282,11 +1233,10 @@ sub copy_file { $self->create_directory($destination_directory_path) || return; # Get a fileManager object - my $service_content = Vim::get_service_content() || return; - my $file_manager = Vim::get_view(mo_ref => $service_content->{fileManager}) || return; - my $datacenter = Vim::find_entity_view(view_type => 'Datacenter') || return; + my $file_manager = $self->_get_file_manager_view() || return; + my $datacenter = $self->_get_datacenter_view() || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; # Attempt to copy the file @@ -1540,11 +1490,10 @@ sub move_file { $self->create_directory($destination_directory_path) || return; # Get a fileManager and Datacenter object - my $service_content = Vim::get_service_content() || return; - my $file_manager = Vim::get_view(mo_ref => $service_content->{fileManager}) || return; - my $datacenter = Vim::find_entity_view(view_type => 'Datacenter') || return; + my $file_manager = $self->_get_file_manager_view() || return; + my $datacenter = $self->_get_datacenter_view() || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; # Attempt to copy the file @@ -1753,6 +1702,50 @@ sub find_files { } #///////////////////////////////////////////////////////////////////////////// + +=head2 get_total_space + + Parameters : $path + Returns : integer + Description : Returns the total size (in bytes) of the volume specified by the + argument. + +=cut + +sub get_total_space { + 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 path argument + my $path = shift; + if (!$path) { + notify($ERRORS{'WARNING'}, 0, "path argument was not specified"); + return; + } + + # Get the datastore name + my $datastore_name = $self->_get_datastore_name($path) || return; + + my $vmhost_hostname = $self->data->get_vmhost_hostname(); + + # Get the datastore info hash + my $datastore_info = $self->_get_datastore_info() || return; + + my $total_bytes = $datastore_info->{$datastore_name}{capacity}; + if (!defined($total_bytes)) { + notify($ERRORS{'WARNING'}, 0, "datastore $datastore_name capacity key does not exist in datastore info:\n" . format_data($datastore_info)); + return; + } + + notify($ERRORS{'DEBUG'}, 0, "capacity of $datastore_name datastore on $vmhost_hostname: " . get_file_size_info_string($total_bytes)); + return $total_bytes; +} + + +#///////////////////////////////////////////////////////////////////////////// =head2 get_available_space @@ -1783,7 +1776,7 @@ sub get_available_space { my $vmhost_hostname = $self->data->get_vmhost_hostname(); # Get the datastore info hash - my $datastore_info = $self->_get_datastore_info() || return; + my $datastore_info = $self->_get_datastore_info(1) || return; my $available_bytes = $datastore_info->{$datastore_name}{freeSpace}; if (!defined($available_bytes)) { @@ -1791,7 +1784,7 @@ sub get_available_space { return; } - notify($ERRORS{'DEBUG'}, 0, "space available in $datastore_name datastore on $vmhost_hostname: " . format_number($available_bytes) . " bytes"); + notify($ERRORS{'DEBUG'}, 0, "space available in $datastore_name datastore on $vmhost_hostname: " . get_file_size_info_string($available_bytes)); return $available_bytes; } @@ -1996,7 +1989,7 @@ sub _get_file_info { query => [@file_queries], ); - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; # Searches the folder specified by the datastore path and all subfolders based on the searchSpec @@ -2056,12 +2049,168 @@ sub _get_file_info { } } - #notify($ERRORS{'DEBUG'}, 0, "retrieved info for " . scalar(keys(%file_info)) . " matching files:\n" . format_data(\%file_info)); + notify($ERRORS{'DEBUG'}, 0, "retrieved info for " . scalar(keys(%file_info)) . " matching files:\n" . format_data(\%file_info)); return \%file_info; } #///////////////////////////////////////////////////////////////////////////// +=head2 _get_host_view + + Parameters : + Returns : vSphere SDK host object + Description : Retrieves a host object. + +=cut + +sub _get_host_view { + 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->{host_view_object} if $self->{host_view_object}; + + # Get the host view + $self->{host_view_object} = VIExt::get_host_view(1); + return $self->{host_view_object}; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_datacenter_view + + Parameters : + Returns : vSphere SDK datacenter view object + Description : Retrieves a vSphere SDK datacenter view object. + +=cut + +sub _get_datacenter_view { + 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->{datacenter_view_object} if $self->{datacenter_view_object}; + + # Get the host view + my $datacenter = Vim::find_entity_view(view_type => 'Datacenter'); + if (!$datacenter) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve datacenter view object"); + return; + } + else { + $self->{datacenter_view_object} = $datacenter; + return $self->{datacenter_view_object}; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_vm_view + + Parameters : $vmx_file_path (optional) + Returns : + Description : + +=cut + +sub _get_vm_view { + 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 = shift || $self->get_vmx_file_path(); + $vmx_path = $self->_get_datastore_path($vmx_path); + + # Override the die handler + local $SIG{__DIE__} = sub{}; + + my $vm_view; + eval { $vm_view = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; + if (!$vm_view) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve view object for VM: $vmx_path"); + return; + } + + $self->{vm_view_objects}{$vmx_path} = $vm_view; + return $self->{vm_view_objects}{$vmx_path}; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_virtual_disk_manager_view + + Parameters : + Returns : vSphere SDK virtual disk manager view object + Description : Retrieves a vSphere SDK virtual disk manager view object. + +=cut + +sub _get_virtual_disk_manager_view { + 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->{virtual_disk_manager_object} if $self->{virtual_disk_manager_object}; + + # Get a virtual disk manager object + my $service_content = Vim::get_service_content() || return; + if (!$service_content->{virtualDiskManager}) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve virtual disk manager object, it is not available via the vSphere SDK"); + return; + } + + my $virtual_disk_manager = Vim::get_view(mo_ref => $service_content->{virtualDiskManager}); + if (!$virtual_disk_manager) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve virtual disk manager object"); + return; + } + + $self->{virtual_disk_manager_object} = $virtual_disk_manager; + return $self->{virtual_disk_manager_object}; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 _get_file_manager_view + + Parameters : + Returns : vSphere SDK file manager view object + Description : Retrieves a vSphere SDK file manager view object. + +=cut + +sub _get_file_manager_view { + 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->{file_manager_object} if $self->{file_manager_object}; + + my $service_content = Vim::get_service_content() || return; + my $file_manager = Vim::get_view(mo_ref => $service_content->{fileManager}); + if (!$file_manager) { + notify($ERRORS{'WARNING'}, 0, "failed to retrieve file manager object"); + return; + } + + $self->{file_manager_object} = $file_manager; + return $self->{file_manager_object}; +} + +#///////////////////////////////////////////////////////////////////////////// + =head2 _get_datastore_object Parameters : $datastore_name @@ -2079,14 +2228,16 @@ sub _get_datastore_object { } # Get the datastore name argument - my $datastore_name = shift; - if (!$datastore_name) { + my $datastore_name_argument = shift; + if (!$datastore_name_argument) { notify($ERRORS{'WARNING'}, 0, "datastore name argument was not specified"); return; } + return $self->{datastore_objects}{$datastore_name_argument} if ($self->{datastore_objects}{$datastore_name_argument}); + # Get the host view - my $host_view = VIExt::get_host_view(1); + my $host_view = $self->_get_host_view(); # Get an array containing datastore managed object references my @datastore_mo_refs = @{$host_view->datastore}; @@ -2096,11 +2247,13 @@ sub _get_datastore_object { my @datastore_names_found; for my $datastore_mo_ref (@datastore_mo_refs) { my $datastore = Vim::get_view(mo_ref => $datastore_mo_ref); - return $datastore if ($datastore_name eq $datastore->summary->name); - push @datastore_names_found, $datastore->summary->name; + my $datastore_name = $datastore->summary->name; + $self->{datastore_objects}{$datastore_name} = $datastore; } - notify($ERRORS{'WARNING'}, 0, "failed to find datastore named $datastore_name, datastore names found:\n" . join("\n", @datastore_names_found)); + return $self->{datastore_objects}{$datastore_name_argument} if ($self->{datastore_objects}{$datastore_name_argument}); + + notify($ERRORS{'WARNING'}, 0, "failed to find datastore named $datastore_name_argument, datastore names found:\n" . join("\n", keys(%{$self->{datastore_objects}}))); return; } @@ -2134,10 +2287,14 @@ sub _get_datastore_info { return; } + # If the datastore info was previously retrieved, return the cached data unless an argument was specified + my $no_cache = shift; + return $self->{datastore_info} if (!$no_cache && $self->{datastore_info}); + my $vmhost_hostname = $self->data->get_vmhost_hostname(); # Get the host view - my $host_view = VIExt::get_host_view(1); + my $host_view = $self->_get_host_view(); # Get an array containing datastore managed object references my @datastore_mo_refs = @{$host_view->datastore}; @@ -2173,6 +2330,8 @@ sub _get_datastore_info { $datastore_info->{$datastore_name} = $datastore_view->summary; } + #notify($ERRORS{'DEBUG'}, 0, "retrieved datastore info:\n" . format_data($datastore_info)); + $self->{datastore_info} = $datastore_info; return $datastore_info; } @@ -2201,12 +2360,7 @@ sub create_snapshot { # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'WARNING'}, 0, "unable to create snapshop because VM is not registered: $vmx_path"); - return; - } + my $vm = $self->_get_vm_view($vmx_path) || return; eval { $vm->CreateSnapshot(name => $snapshot_name, memory => 0, @@ -2243,18 +2397,13 @@ sub snapshot_exists { # Get the vmx path argument and convert it to a datastore path my $vmx_path = $self->_get_datastore_path(shift) || return; - # Override the die handler because fileManager may call it + # Override the die handler local $SIG{__DIE__} = sub{}; - my $vm; - eval { $vm = Vim::find_entity_view(view_type => 'VirtualMachine', filter => {'config.files.vmPathName' => $vmx_path}); }; - if (!$vm) { - notify($ERRORS{'WARNING'}, 0, "unable to determine if snapshot exists because VM is not registered: $vmx_path"); - return; - } + my $vm = $self->_get_vm_view($vmx_path) || return; if (defined($vm->snapshot)) { - notify($ERRORS{'DEBUG'}, 0, "snapshot exists for VM: $vmx_path"); + notify($ERRORS{'DEBUG'}, 0, "snapshot exists for VM: $vmx_path\n" . format_data($vm->snapshot)); return 1; } else {