You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2010/08/20 22:06:13 UTC

svn commit: r987623 [1/2] - in /incubator/vcl/trunk/managementnode/lib/VCL: Module/OS/Windows.pm Module/Provisioning/VMware/VMware.pm Module/Provisioning/VMware/vSphere_SDK.pm image.pm utils.pm

Author: arkurth
Date: Fri Aug 20 20:06:13 2010
New Revision: 987623

URL: http://svn.apache.org/viewvc?rev=987623&view=rev
Log:
VCL-164
Added setup and setup_capture_base_image subroutines to image.pm which allows the base image creation steps to be automated via a command-line interface when vcld is run with the -setup argument.  Added get_computer_ids, get_os_info, and get_user_info subroutines to utils.pm which are called by image.pm::setup.

Removed call to enable DHCP in Windows.pm::pre_capture and added a switch to Windows.pm::shutdown allowing the caller to specify whether or not DHCP should be disabled immediately before shutting down the computer. This allows a base image to be captured which has been configured with a static address.

VCL-298
Updated VMware.pm. Split up prepare_vmx subroutine to create another subroutine which only removes existing VMs which were created for the VM assigned to the reservation.

Reworked VMware.pm::capture to display more meaningful error and warning messages.

Reworked most of the get_vmx...path and get_vmdk...path subroutines to display more meaningful error and warning messages.

Updated vSphere.pm::copy_virtual_disk to retrieve the adapter type from the source vmdk rather than using lsiLogic as the default value if the argument was not specified.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm
    incubator/vcl/trunk/managementnode/lib/VCL/image.pm
    incubator/vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=987623&r1=987622&r2=987623&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Fri Aug 20 20:06:13 2010
@@ -226,16 +226,6 @@ sub pre_capture {
 		return 0;
 	}
 
-#=item *
-#
-# Disable IPv6
-#
-#=cut
-#
-#	if (!$self->disable_ipv6()) {
-#		notify($ERRORS{'WARNING'}, 0, "unable to disable IPv6");
-#	}
-
 =item *
 
  Disable dynamic DNS
@@ -335,17 +325,6 @@ sub pre_capture {
 	if (!$self->clean_hard_drive()) {
 		notify($ERRORS{'WARNING'}, 0, "unable to clean unnecessary files the hard drive");
 	}
-	
-=item *
-
- Configure the network adapters to use DHCP
-
-=cut
-
-	if (!$self->enable_dhcp()) {
-		notify($ERRORS{'WARNING'}, 0, "unable to enable DHCP on the public and private interfaces");
-		return 0;
-	}
 
 =item *
 
@@ -3078,14 +3057,40 @@ sub shutdown {
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return;
 	}
+	
+	# Get the argument that determines whether or not to disable DHCP before shutting down computer
+	my $disable_dhcp = shift;
 
 	my $management_node_keys = $self->data->get_management_node_keys();
 	my $computer_node_name   = $self->data->get_computer_node_name();
-
-	notify($ERRORS{'DEBUG'}, 0, "$computer_node_name will be shut down");
-
+	
+	my $system32_path = $self->get_system32_path();
+	my $shutdown_command = "/bin/cygstart.exe cmd.exe /c \"";
+	
+	if ($disable_dhcp) {
+		notify($ERRORS{'DEBUG'}, 0, "enabling DHCP and shutting down $computer_node_name");
+		
+		my $private_interface_name = $self->get_private_interface_name();
+		my $public_interface_name = $self->get_public_interface_name();
+		if (!$private_interface_name || !$public_interface_name) {
+			notify($ERRORS{'WARNING'}, 0, "unable to determine private and public interface names, failed to enable DHCP and shut down $computer_node_name");
+			return;
+		}
+		
+		$shutdown_command .= "$system32_path/netsh.exe interface ip set address name=\\\"$private_interface_name\\\" source=dhcp & ";
+		$shutdown_command .= "$system32_path/netsh.exe interface ip set dnsservers name=\\\"$private_interface_name\\\" source=dhcp & ";
+		
+		$shutdown_command .= "$system32_path/netsh.exe interface ip set address name=\\\"$public_interface_name\\\" source=dhcp & ";
+		$shutdown_command .= "$system32_path/netsh.exe interface ip set dnsservers name=\\\"$public_interface_name\\\" source=dhcp & ";
+		
+		$shutdown_command .= "$system32_path/route.exe DELETE 0.0.0.0 MASK 0.0.0.0 & ";
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "shutting down $computer_node_name");
+	}
+	
 	# Initiate the shutdown.exe command to reboot the computer
-	my $shutdown_command = 'cmd.exe /c "' . $self->get_system32_path() . '/shutdown.exe -s -t 0 -f"';
+	$shutdown_command .= "$system32_path/shutdown.exe -s -t 0 -f\"";
 	
 	my $attempt_count = 0;
 	my $attempt_limit = 12;
@@ -3097,30 +3102,28 @@ sub shutdown {
 		}
 		
 		my ($shutdown_exit_status, $shutdown_output) = run_ssh_command($computer_node_name, $management_node_keys, $shutdown_command);
-		if (defined($shutdown_exit_status) && $shutdown_exit_status == 0) {
-			notify($ERRORS{'DEBUG'}, 0, "attempt $attempt_count/$attempt_limit: executed shutdown command on $computer_node_name");
-			
-			# Wait maximum of 3 minutes for the computer to become unresponsive
-			if ($self->wait_for_no_ping(180)) {
-				notify($ERRORS{'OK'}, 0, "attempt $attempt_count/$attempt_limit: computer has become unresponsive after shutdown command was issued");
-				return 1;
-			}
-			else {
-				# Computer never stopped responding to ping
-				notify($ERRORS{'WARNING'}, 0, "attempt $attempt_count/$attempt_limit: $computer_node_name never became unresponsive after shutdown command was issued, attempting power off");
-			}
+		if (!defined($shutdown_output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to shutdown $computer_node_name");
+			last;
 		}
-		elsif (defined($shutdown_output) && grep(/processing another action/i, @$shutdown_output)) {
+		elsif (grep(/(processing another action)/i, @$shutdown_output)) {
 			notify($ERRORS{'WARNING'}, 0, "attempt $attempt_count/$attempt_limit: failed to execute shutdown command on $computer_node_name, exit status: $shutdown_exit_status, output:\n@{$shutdown_output}");
 			next;
 		}
-		elsif (defined($shutdown_output)) {
-			notify($ERRORS{'WARNING'}, 0, "attempt $attempt_count/$attempt_limit: failed to execute shutdown command on $computer_node_name, exit status: $shutdown_exit_status, output:\n@{$shutdown_output}");
-		}
 		else {
-			notify($ERRORS{'WARNING'}, 0, "failed to execute ssh command to shutdown $computer_node_name");
+			notify($ERRORS{'DEBUG'}, 0, "attempt $attempt_count/$attempt_limit: executed shutdown command on $computer_node_name");
+			last;
 		}
-		last;
+	}
+	
+	# Wait maximum of 3 minutes for the computer to become unresponsive
+	if ($self->wait_for_no_ping(180)) {
+		notify($ERRORS{'OK'}, 0, "attempt $attempt_count/$attempt_limit: computer has become unresponsive after shutdown command was issued");
+		return 1;
+	}
+	else {
+		# Computer never stopped responding to ping
+		notify($ERRORS{'WARNING'}, 0, "$computer_node_name did not become unresponsive after shutdown command was issued, attempting power off");
 	}
 	
 	# Call provisioning module's power_off() subroutine
@@ -3291,7 +3294,7 @@ sub prepare_post_load {
 	
 	# Shut down computer unless end_state argument was passed with a value other than 'off'
 	if ($end_state eq 'off') {
-		if (!$self->shutdown()) {
+		if (!$self->shutdown(1)) {
 			notify($ERRORS{'WARNING'}, 0, "failed to shut down computer");
 			return;
 		}
@@ -4671,6 +4674,9 @@ sub get_network_configuration {
 			}
 		}
 		
+		
+		
+		
 		notify($ERRORS{'DEBUG'}, 0, 'saving network configuration in $self->{network_configuration}');
 		$self->{network_configuration} = \%network_configuration;
 	}

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=987623&r1=987622&r2=987623&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 Fri Aug 20 20:06:13 2010
@@ -324,6 +324,12 @@ sub load {
 	
 	insertloadlog($reservation_id, $computer_id, "startload", "$computer_name $image_name");
 	
+	# Remove existing VMs which were created for the reservation computer
+	if (!$self->remove_existing_vms()) {
+		notify($ERRORS{'WARNING'}, 0, "failed to remove existing VMs created for computer $computer_name on VM host: $vmhost_hostname");
+		return;
+	}
+	
 	# Check if the .vmdk files exist, copy them if necessary
 	if (!$self->prepare_vmdk()) {
 		notify($ERRORS{'WARNING'}, 0, "failed to prepare vmdk file for $computer_name on VM host: $vmhost_hostname");
@@ -391,17 +397,27 @@ sub capture {
 	}
 	
 	# 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) {
-		notify($ERRORS{'WARNING'}, 0, "unable to capture image, failed to determine the vmx file path being used by $computer_name");
+	my $vmx_file_path_capture = $self->get_active_vmx_file_path();
+	if (!$vmx_file_path_capture) {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine the vmx file path actively being used by $computer_name");
 		return;
 	}
 
 	# Set the vmx file path in this object so that it overrides the default value that would normally be constructed
-	$self->set_vmx_file_path($vmx_file_path) || return;
+	if (!$self->set_vmx_file_path($vmx_file_path_capture)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the vmx file to the path that was determined to be in use by the VM being captured: $vmx_file_path_capture");
+		return;
+	}
+	
+	# Get the vmx directory path of the VM being captured
+	my $vmx_directory_path_capture = $self->get_vmx_directory_path();
+	if (!$vmx_directory_path_capture) {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine the vmx directory path of the VM being captured");
+		return;
+	}
 	
 	# Get the information contained within the vmx file
-	my $vmx_info = $self->get_vmx_info($vmx_file_path);
+	my $vmx_info = $self->get_vmx_info($vmx_file_path_capture);
 	notify($ERRORS{'DEBUG'}, 0, "vmx info for VM to be captured:\n" . format_data($vmx_info));
 	
 	# Get the vmdk info from the vmx info
@@ -415,13 +431,13 @@ sub capture {
 		return;
 	}
 	
-	# Get the vmdk file path from the vmx information
-	my $vmdk_file_path = $vmx_info->{vmdk}{$vmdk_identifiers[0]}{vmdk_file_path};
-	if (!$vmdk_file_path) {
-		notify($ERRORS{'WARNING'}, 0, "vmdk file path was not found in the vmx info:\n" . format_data($vmx_info));
+	# Get the vmdk file path to be captured from the vmx information
+	my $vmdk_file_path_capture = $vmx_info->{vmdk}{$vmdk_identifiers[0]}{vmdk_file_path};
+	if (!$vmdk_file_path_capture) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file path to be captured was not found in the vmx file info:\n" . format_data($vmx_info));
 		return;	
 	}
-	notify($ERRORS{'DEBUG'}, 0, "vmdk file path used by the VM: $vmdk_file_path");
+	notify($ERRORS{'DEBUG'}, 0, "vmdk file path used by the VM to be captured: $vmdk_file_path_capture");
 	
 	# Get the vmdk mode from the vmx information and make sure it's persistent
 	my $vmdk_mode = $vmx_info->{vmdk}{$vmdk_identifiers[0]}{mode};
@@ -429,70 +445,96 @@ sub capture {
 		notify($ERRORS{'WARNING'}, 0, "vmdk mode was not found in the vmx info:\n" . format_data($vmx_info));
 		return;	
 	}
-	elsif ($vmdk_mode !~ /(independent-)?persistent/i) {
-		notify($ERRORS{'WARNING'}, 0, "vmdk mode is not persistent: $vmdk_mode");
+	elsif ($vmdk_mode !~ /^(independent-)?persistent/i) {
+		notify($ERRORS{'WARNING'}, 0, "mode of vmdk '$vmdk_file_path_capture': $vmdk_mode, the mode must be persistent in order to be captured");
 		return;	
 	}
-	notify($ERRORS{'DEBUG'}, 0, "vmdk mode is valid: $vmdk_mode");
+	notify($ERRORS{'DEBUG'}, 0, "mode of vmdk to be captured is valid: $vmdk_mode");
 	
 	# Set the vmdk file path in this object so that it overrides the default value that would normally be constructed
-	$self->set_vmdk_file_path($vmdk_file_path) || return;
+	if (!$self->set_vmdk_file_path($vmdk_file_path_capture)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to set the vmdk file to the path that was determined to be in use by the VM being captured: $vmdk_file_path_capture");
+		return;
+	}
 	
 	# Construct the vmdk file path where the captured image will be saved to
-	my $vmdk_renamed_file_path = "$vmhost_profile_datastore_path/$image_name/$image_name.vmdk";
+	my $vmdk_file_path_renamed = "$vmhost_profile_datastore_path/$image_name/$image_name.vmdk";
 	
 	# Make sure the vmdk file path for the captured image doesn't already exist
-	if ($vmdk_file_path ne $vmdk_renamed_file_path && $self->vmhost_os->file_exists($vmdk_renamed_file_path)) {
-		notify($ERRORS{'WARNING'}, 0, "vmdk file for captured image already exists: $vmdk_renamed_file_path");
+	# Do this before calling pre_capture and shutting down the VM
+	if ($vmdk_file_path_capture ne $vmdk_file_path_renamed && $self->vmhost_os->file_exists($vmdk_file_path_renamed)) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file that captured image will be renamed to already exists: $vmdk_file_path_renamed");
 		return;
 	}
 	
 	# Write the details about the new image to ~/currentimage.txt
-	write_currentimage_txt($self->data) || return;
+	if (!write_currentimage_txt($self->data)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to create the currentimage.txt file on the VM being captured");
+		return;
+	}
 	
 	# Call the OS module's pre_capture() subroutine if implemented
-	if ($self->os->can("pre_capture")) {
-		$self->os->pre_capture({end_state => 'off'}) || return;
+	if ($self->os->can("pre_capture") && !$self->os->pre_capture({end_state => 'off'})) {
+		notify($ERRORS{'WARNING'}, 0, "failed to complete OS module's pre_capture tasks");
+		return;
 	}
 	
 	# Power off the VM if it's not already off
-	my $vm_power_state = $self->api->get_vm_power_state($vmx_file_path) || return;
-	if ($vm_power_state !~ /off/i) {
-		$self->api->vm_power_off($vmx_file_path) || return;
-		
-		# Sleep for 5 seconds to make sure the power off is complete
-		sleep 5;
+	my $vm_power_state = $self->api->get_vm_power_state($vmx_file_path_capture);
+	if (!defined($vm_power_state)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to retrieve the power state of the VM being captured after the OS module's pre_capture tasks were completed");
+		return;
+	}
+	elsif ($vm_power_state !~ /off/i) {
+		if ($self->api->vm_power_off($vmx_file_path_capture)) {
+			# Sleep for 5 seconds to make sure the power off is complete
+			sleep 5;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to power off the VM being captured after the OS module's pre_capture tasks were completed, VM power state: $vm_power_state");
+			return;
+		}
 	}
 	
 	# Rename the vmdk files on the VM host and change the vmdk directory name to the image name
-	# This ensures that the vmdk and vmx files now reside in different directories
-	#   so that the vmdk files can't be deleted when the vmx directory is deleted later on
-	if ($vmdk_file_path ne $vmdk_renamed_file_path) {
-		$self->rename_vmdk($vmdk_file_path, $vmdk_renamed_file_path) || return;
-		$self->set_vmdk_file_path($vmdk_renamed_file_path) || return;
+	if ($vmx_file_path_capture ne $vmdk_file_path_renamed) {
+		if (!$self->rename_vmdk($vmdk_file_path_capture, $vmdk_file_path_renamed)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to rename the vmdk files after the VM was powered off: '$vmdk_file_path_capture' --> '$vmdk_file_path_renamed'");
+			return;
+		}
+		
+		if (!$self->set_vmdk_file_path($vmdk_file_path_renamed)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to set the vmdk file to the path after renaming the vmdk files: $vmdk_file_path_renamed");
+			return;
+		}
 	}
 	else {
-		notify($ERRORS{'DEBUG'}, 0, "vmdk file does not need to be renamed: $vmdk_file_path");
+		notify($ERRORS{'DEBUG'}, 0, "vmdk file does not need to be renamed: $vmx_file_path_capture");
 	}
 	
+	# Get the renamed vmdk directory path
+	my $vmdk_directory_path_renamed = $self->get_vmdk_directory_path();
+	
 	# Check if the VM host is using local or network-based disk to store vmdk files
 	# Don't have to do anything else for network disk because the vmdk directory has already been renamed
 	if ($vmprofile_vmdisk eq "localdisk") {
-		# Get the vmdk directory path
-		my $vmdk_directory_path = $self->get_vmdk_directory_path() || return;
-		
 		# Copy the vmdk directory from the VM host to the image repository
-		my @vmdk_copy_paths = $self->vmhost_os->find_files($vmdk_directory_path, '*.vmdk');
+		my @vmdk_copy_paths = $self->vmhost_os->find_files($vmdk_directory_path_renamed, '*.vmdk');
 		if (!@vmdk_copy_paths) {
-			notify($ERRORS{'WARNING'}, 0, "unable to find vmdk file paths on VM host to copy back to the managment node, vmdk directory path: $vmdk_directory_path, pattern: *.vmdk");
+			notify($ERRORS{'WARNING'}, 0, "failed to find the renamed vmdk files on VM host to copy back to the managment node's image repository");
 			return;
 		}
 		
-		my $repository_directory_path = $self->get_repository_vmdk_directory_path() || return;
+		# Get the image repository directory path on this management node
+		my $repository_directory_path = $self->get_repository_vmdk_directory_path();
+		if (!$repository_directory_path) {
+			notify($ERRORS{'WARNING'}, 0, "failed to retrieve management node's image repository path");
+			return;
+		}
 		
 		# Loop through the files, copy each to the management node's repository directory
 		for my $vmdk_copy_path (@vmdk_copy_paths) {
-			my ($vmdk_copy_name) = $vmdk_copy_path =~ /([^\/]+)$/g;
+			my ($vmdk_copy_name) = $vmdk_copy_path =~ /([^\/]+)$/;
 			if (!$self->vmhost_os->copy_file_from($vmdk_copy_path, "$repository_directory_path/$vmdk_copy_name")) {
 				notify($ERRORS{'WARNING'}, 0, "failed to copy vmdk file from the VM host to the management node:\n '$vmdk_copy_path' --> '$repository_directory_path/$vmdk_copy_name'");
 				return;
@@ -500,19 +542,40 @@ sub capture {
 		}
 		
 		# Delete the vmdk directory on the VM host
-		$self->vmhost_os->delete_file($vmdk_directory_path) || return;
+		if ($vmdk_directory_path_renamed eq $vmx_directory_path_capture) {
+			notify($ERRORS{'DEBUG'}, 0, "renamed vmdk directory will not be deleted yet because it matches the vmx directory path and the VM has not been unregistered yet: $vmdk_directory_path_renamed");
+		}
+		else {
+			if ($self->vmhost_os->delete_file($vmdk_directory_path_renamed)) {
+				notify($ERRORS{'OK'}, 0, "deleted the vmdk directory after files were copied to the image repository: $vmdk_directory_path_renamed");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "failed to delete the vmdk directory after files were copied to the image repository: $vmdk_directory_path_renamed");
+			}
+		}
 	}
 	
+	
 	# Unregister the VM
-	$self->api->vm_unregister($vmx_file_path) || return;
+	if ($self->api->vm_unregister($vmx_file_path_capture)) {
+		notify($ERRORS{'OK'}, 0, "unregistered the VM being captured: $vmx_file_path_capture");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to unregister the VM being captured: $vmx_file_path_capture");
+	}
+	
 	
 	# Delete the vmx directory
-	if ($self->get_vmx_directory_path() ne $self->get_vmdk_directory_path()) {
-		$self->vmhost_os->delete_file($self->get_vmx_directory_path()) || return;
+	if ($vmprofile_vmdisk eq "networkdisk" && $vmx_directory_path_capture eq $vmdk_directory_path_renamed) {
+		notify($ERRORS{'DEBUG'}, 0, "vmx directory will not be deleted because the VM disk mode is '$vmprofile_vmdisk' and the vmx directory path is the same as the vmdk directory path for the captured image: '$vmdk_directory_path_renamed'");
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "vmx directory not deleted because it matches the vmdk directory, this should never happen: " . $self->get_vmdk_directory_path());
-		return;
+		if ($self->vmhost_os->delete_file($vmx_directory_path_capture)) {
+			notify($ERRORS{'OK'}, 0, "deleted the vmx directory after the image was captured: $vmx_directory_path_capture");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to delete the vmx directory that was captured: $vmx_directory_path_capture");
+		}
 	}
 	
 	return 1;
@@ -935,70 +998,24 @@ sub get_vmhost_api_object {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 prepare_vmx
+=head2 remove_existing_vms
 
  Parameters  : none
  Returns     : boolean
- Description : Creates a .vmx file on the VM host configured for the
-               reservation. Checks if a VM for the same VCL computer entry is
-               already registered. If the VM is already registered, it is
-               unregistered and the files for the existing VM are deleted.
+ Description : 
 
 =cut
 
-sub prepare_vmx {
+sub remove_existing_vms {
 	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;
 	}
 	
-	# Get the required data to configure the .vmx file
-	my $image_id                 = $self->data->get_image_id() || return;
-	my $imagerevision_id         = $self->data->get_imagerevision_id() || return;
-	my $image_project            = $self->data->get_image_project() || return;
-	my $computer_id              = $self->data->get_computer_id() || return;
-	my $vmx_file_name            = $self->get_vmx_file_name() || return;
-	my $vmx_file_path            = $self->get_vmx_file_path() || return;
-	my $vmx_directory_name       = $self->get_vmx_directory_name() || return;
-	my $vmx_directory_path       = $self->get_vmx_directory_path() || return;
-	my $vmdk_file_path           = $self->get_vmdk_file_path() || return;
-	my $computer_name            = $self->data->get_computer_short_name() || return;
-	my $image_name               = $self->data->get_image_name() || return;
-	my $vm_ram                   = $self->get_vm_ram() || return;
-	my $vm_cpu_count             = $self->data->get_image_minprocnumber() || 1;
-	my $vm_ethernet_adapter_type = $self->get_vm_ethernet_adapter_type() || return;
-	my $vm_eth0_mac              = $self->data->get_computer_eth0_mac_address() || return;
-	my $vm_eth1_mac              = $self->data->get_computer_eth1_mac_address() || return;	
-	my $virtual_switch_0         = $self->data->get_vmhost_profile_virtualswitch0() || return;
-	my $virtual_switch_1         = $self->data->get_vmhost_profile_virtualswitch1() || return;
-	my $vm_disk_adapter_type     = $self->get_vm_disk_adapter_type() || return;
-	my $vm_hardware_version      = $self->get_vm_virtual_hardware_version() || return;
-	my $vm_persistent            = $self->is_vm_persistent();
-	my $guest_os                 = $self->get_vm_guest_os() || return;
-	
-	## Figure out how much additional space is required for the vmx directory for the VM for this reservation
-	## This is the number of additional bytes which have not already been allocated the VM will likely use
-	#my $vm_additional_vmx_bytes_required = $self->get_vm_additional_vmx_bytes_required();
-	#return if !defined($vm_additional_vmx_bytes_required);
-	#
-	## Get the number of bytes available on the device where the base vmx directory resides
-	#my $host_vmx_bytes_available = $self->vmhost_os->get_available_space($self->get_vmx_base_directory_path());
-	#return if !defined($host_vmx_bytes_available);
-	#
-	## Check if there is enough space available for the VM's vmx files
-	#if ($vm_additional_vmx_bytes_required > $host_vmx_bytes_available) {
-	#	my $vmx_deficit_bytes = ($vm_additional_vmx_bytes_required - $host_vmx_bytes_available);
-	#	my $vmx_deficit_mb = format_number($vmx_deficit_bytes / 1024 / 1024);
-	#	notify($ERRORS{'WARNING'}, 0, "not enough space is available for the vmx files on the VM host, deficit: $vmx_deficit_bytes bytes ($vmx_deficit_mb MB)");
-	#}
-	#else {
-	#	notify($ERRORS{'DEBUG'}, 0, "enough space is available for the vmx files on the VM host");
-	#}
+	my $computer_name = $self->data->get_computer_short_name() || return;
 	
-	# Get a hash containing info about all the .vmx files that exist on the VM host
 	# Check the VMs on the host to see if any match the computer assigned to this reservation
-	
 	# Get an array containing the existing vmx file paths on the VM host
 	my @vmx_file_paths = $self->get_vmx_file_paths();
 	
@@ -1020,6 +1037,7 @@ sub prepare_vmx {
 	}
 	
 	# Loop through the existing vmx file paths found, check if it matches the VM for this reservation
+	my $vmx_base_directory_path = $self->get_vmx_base_directory_path();
 	for my $vmx_file_path (@vmx_file_paths) {
 		# Parse the vmx file name from the path
 		my ($vmx_directory_name, $vmx_file_name) = $vmx_file_path =~ /([^\/]+)\/([^\/]+\.vmx)$/i;
@@ -1028,6 +1046,14 @@ sub prepare_vmx {
 			next;
 		}
 		
+		# Ignore file if it does not begin with the base directory path
+		# get_vmx_file_paths() will return all vmx files it finds under the base directory path and all registered vmx files
+		# It's possible for a vmx file to be registered that resided on some other datastore
+		if ($vmx_file_path !~ /^$vmx_base_directory_path/) {
+			notify($ERRORS{'DEBUG'}, 0, "ignoring existing vmx file '$vmx_file_path' because it does not begin with the base directory path: '$vmx_base_directory_path'");
+			next;
+		}
+		
 		# Check if the vmx directory name matches the pattern:
 		# <computer_short_name>_<image id>-v<imagerevision revision>
 		# <computer_short_name>_<image id>-v<imagerevision revision>_<request id>
@@ -1047,10 +1073,75 @@ sub prepare_vmx {
 			}
 		}
 		else {
-			notify($ERRORS{'DEBUG'}, 0, "ignoring existing vmx file: $vmx_file_path");
+			notify($ERRORS{'DEBUG'}, 0, "ignoring existing vmx directory: $vmx_directory_name");
 			next;
 		}
 	}
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 prepare_vmx
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Creates a .vmx file on the VM host configured for the
+               reservation. Checks if a VM for the same VCL computer entry is
+               already registered. If the VM is already registered, it is
+               unregistered and the files for the existing VM are deleted.
+
+=cut
+
+sub prepare_vmx {
+	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;
+	}
+	
+	# Get the required data to configure the .vmx file
+	my $image_id                 = $self->data->get_image_id() || return;
+	my $imagerevision_id         = $self->data->get_imagerevision_id() || return;
+	my $image_project            = $self->data->get_image_project() || return;
+	my $computer_id              = $self->data->get_computer_id() || return;
+	my $vmx_file_name            = $self->get_vmx_file_name() || return;
+	my $vmx_file_path            = $self->get_vmx_file_path() || return;
+	my $vmx_directory_name       = $self->get_vmx_directory_name() || return;
+	my $vmx_directory_path       = $self->get_vmx_directory_path() || return;
+	my $vmdk_file_path           = $self->get_vmdk_file_path() || return;
+	my $computer_name            = $self->data->get_computer_short_name() || return;
+	my $image_name               = $self->data->get_image_name() || return;
+	my $vm_ram                   = $self->get_vm_ram() || return;
+	my $vm_cpu_count             = $self->data->get_image_minprocnumber() || 1;
+	my $vm_ethernet_adapter_type = $self->get_vm_ethernet_adapter_type() || return;
+	my $vm_eth0_mac              = $self->data->get_computer_eth0_mac_address() || return;
+	my $vm_eth1_mac              = $self->data->get_computer_eth1_mac_address() || return;	
+	my $virtual_switch_0         = $self->data->get_vmhost_profile_virtualswitch0() || return;
+	my $virtual_switch_1         = $self->data->get_vmhost_profile_virtualswitch1() || return;
+	my $vm_disk_adapter_type     = $self->get_vm_disk_adapter_type() || return;
+	my $vm_hardware_version      = $self->get_vm_virtual_hardware_version() || return;
+	my $vm_persistent            = $self->is_vm_persistent();
+	my $guest_os                 = $self->get_vm_guest_os() || return;
+	
+	## Figure out how much additional space is required for the vmx directory for the VM for this reservation
+	## This is the number of additional bytes which have not already been allocated the VM will likely use
+	#my $vm_additional_vmx_bytes_required = $self->get_vm_additional_vmx_bytes_required();
+	#return if !defined($vm_additional_vmx_bytes_required);
+	#
+	## Get the number of bytes available on the device where the base vmx directory resides
+	#my $host_vmx_bytes_available = $self->vmhost_os->get_available_space($self->get_vmx_base_directory_path());
+	#return if !defined($host_vmx_bytes_available);
+	#
+	## Check if there is enough space available for the VM's vmx files
+	#if ($vm_additional_vmx_bytes_required > $host_vmx_bytes_available) {
+	#	my $vmx_deficit_bytes = ($vm_additional_vmx_bytes_required - $host_vmx_bytes_available);
+	#	my $vmx_deficit_mb = format_number($vmx_deficit_bytes / 1024 / 1024);
+	#	notify($ERRORS{'WARNING'}, 0, "not enough space is available for the vmx files on the VM host, deficit: $vmx_deficit_bytes bytes ($vmx_deficit_mb MB)");
+	#}
+	#else {
+	#	notify($ERRORS{'DEBUG'}, 0, "enough space is available for the vmx files on the VM host");
+	#}
 	
 	# Create the .vmx directory on the host
 	if (!$self->vmhost_os->create_directory($vmx_directory_path)) {
@@ -1117,6 +1208,8 @@ sub prepare_vmx {
 		
 		"config.version" => "8",
 		
+		"disk.locking" => "false",
+		
 		"displayName" => "$display_name",
 		
 		"ethernet0.address" => "$vm_eth0_mac",
@@ -1183,6 +1276,25 @@ sub prepare_vmx {
 		));
 	}
 	
+	if ($vm_hardware_version >= 7) {
+		%vmx_parameters = (%vmx_parameters, (
+			"pciBridge0.present" => "TRUE",
+			"pciBridge4.present" => "TRUE",
+			"pciBridge4.virtualDev" => "pcieRootPort",
+			"pciBridge4.functions" => "8",
+			"pciBridge5.present" => "TRUE",
+			"pciBridge5.virtualDev" => "pcieRootPort",
+			"pciBridge5.functions" => "8",
+			"pciBridge6.present" => "TRUE",
+			"pciBridge6.virtualDev" => "pcieRootPort",
+			"pciBridge6.functions" => "8",
+			"pciBridge7.present" => "TRUE",
+			"pciBridge7.virtualDev" => "pcieRootPort",
+			"pciBridge7.functions" => "8",
+			"vmci0.present" => "TRUE",
+		));
+	}
+	
 	# Add additional Ethernet interfaces if the image project name is not vcl
 	if ($image_project !~ /^vcl$/i) {
 		notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, checking if additional network adapters should be configured");
@@ -1280,10 +1392,24 @@ sub prepare_vmdk {
 	my $image_name = $self->data->get_image_name() || return;
 	my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
 	
+	my $is_vm_persistent = $self->is_vm_persistent();
+	
 	# Check if the first .vmdk file exists on the host
 	if ($self->vmhost_os->file_exists($host_vmdk_file_path)) {
-		notify($ERRORS{'DEBUG'}, 0, "vmdk file exists on VM host: $host_vmdk_file_path");
-		return $self->check_vmdk_disk_type();
+		
+		if ($is_vm_persistent) {
+			notify($ERRORS{'DEBUG'}, 0, "VM is persistent and vmdk file already exists on VM host: $host_vmdk_file_path, vmdk file will be deleted and a new copy will be used");
+			exit;
+			if (!$self->vmhost_os->delete_file($host_vmdk_file_path)) {
+				notify($ERRORS{'WARNING'}, 0, "failed to deleted existing vmdk file: ");
+				return;
+			}
+		}
+		else {
+			# vmdk file exists and not persistent
+			# No copying necessary, proceed to check the disk type
+			return $self->check_vmdk_disk_type();
+		}
 	}
 	else {
 		notify($ERRORS{'DEBUG'}, 0, "vmdk file does NOT exist on VM host: $host_vmdk_file_path");
@@ -1311,7 +1437,7 @@ sub prepare_vmdk {
 	#}
 	
 	# Check if the VM is persistent, if so, attempt to copy files locally from the nonpersistent directory if they exist
-	if ($self->is_vm_persistent()) {
+	if ($is_vm_persistent) {
 		
 		if ($self->api->can('copy_virtual_disk') && $self->api->copy_virtual_disk($host_vmdk_file_path_nonpersistent, $host_vmdk_file_path)) {
 			notify($ERRORS{'OK'}, 0, "copied vmdk files from nonpersistent to persistent directory on VM host");
@@ -1419,8 +1545,7 @@ sub check_vmdk_disk_type {
 	my $vmdk_file_path = $self->get_vmdk_file_path() || return;
 	
 	# Check if the API object implements the required subroutines
-	unless ($self->api->can("get_virtual_disk_type")
-			  && $self->api->can("copy_virtual_disk")) {
+	unless ($self->api->can("get_virtual_disk_type") && $self->api->can("copy_virtual_disk")) {
 		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because required subroutines are not implemented by the API object");
 		return 1;
 	}
@@ -1448,8 +1573,6 @@ sub check_vmdk_disk_type {
 			my $vmdk_file_prefix = $self->get_vmdk_file_prefix() || return;
 			my $thin_vmdk_file_path = "$vmdk_directory_path/thin_$vmdk_file_prefix.vmdk";
 			
-			my $vm_disk_adapter_type = $self->get_vm_disk_adapter_type() || return;
-			
 			if ($self->vmhost_os->file_exists($thin_vmdk_file_path)) {
 				notify($ERRORS{'DEBUG'}, 0, "thin virtual disk already exists: $thin_vmdk_file_path");
 			}
@@ -1457,7 +1580,7 @@ sub check_vmdk_disk_type {
 				notify($ERRORS{'DEBUG'}, 0, "attempting to create a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
 				
 				# Attempt to create a thin copy of the virtual disk
-				if ($self->api->copy_virtual_disk($vmdk_file_path, $thin_vmdk_file_path, 'thin', $vm_disk_adapter_type)) {
+				if ($self->api->copy_virtual_disk($vmdk_file_path, $thin_vmdk_file_path, 'thin')) {
 					notify($ERRORS{'DEBUG'}, 0, "created a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
 				}
 				else {
@@ -1490,14 +1613,50 @@ sub check_vmdk_disk_type {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_vmx_file_path
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the path to the vmx file being used for the reservation.
+               Example:
+               /vmfs/volumes/local-datastore/vclv1-29_vmwarewin7-Test75321-v0/vclv1-29_vmwarewin7-Test75321-v0.vmx
+
+=cut
+
+sub get_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{vmx_file_path} if $ENV{vmx_file_path};
+	
+	my $vmx_base_directory_path = $self->get_vmx_base_directory_path();
+	if (!$vmx_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to construct vmx file path, vmx base directory path could not be determined");
+		return;
+	}
+	
+	my $vmx_directory_name = $self->get_vmx_directory_name();
+	if (!$vmx_directory_name) {
+		notify($ERRORS{'WARNING'}, 0, "unable to construct vmx file path, vmx directory name could not be determined");
+		return;
+	}
+	
+	return "$vmx_base_directory_path/$vmx_directory_name/$vmx_directory_name.vmx";
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 get_vmx_base_directory_path
 
  Parameters  : none
  Returns     : string
  Description : Returns the path on the VM host under which the vmx directory is
-               located.  Example:
-               vmx file path: /vmfs/volumes/nfs-vmpath/vm1-6-987-v0/vm1-6-987-v0.vmx
-               vmx base directory path: /vmfs/volumes/nfs-vmpath
+               located.
+               Example:
+               /vmfs/volumes/local-datastore
 
 =cut
 
@@ -1510,25 +1669,29 @@ sub get_vmx_base_directory_path {
 	
 	my $vmx_base_directory_path;
 	
-	my $vmhost_profile_vmpath = normalize_file_path($self->data->get_vmhost_profile_vmpath());
-	if ($vmhost_profile_vmpath) {
-		$vmhost_profile_vmpath =~ s/\\//g;
-		$vmx_base_directory_path = $vmhost_profile_vmpath;
-	}
-	else {
-		my $vmhost_profile_datastore_path = normalize_file_path($self->data->get_vmhost_profile_datastore_path());
-		if ($vmhost_profile_datastore_path) {
-			$vmx_base_directory_path = $vmhost_profile_datastore_path;
+	# Check if vmx_file_path environment variable has been set
+	# If set, parse the path to return the directory name preceding the vmx file name and directory name
+	# /<vmx base directory path>/<vmx directory name>/<vmx file name>
+	if ($ENV{vmx_file_path}) {
+		($vmx_base_directory_path) = $ENV{vmx_file_path} =~ /(.+)\/[^\/]+\/[^\/]+.vmx$/i;
+		if ($vmx_base_directory_path) {
+			return $vmx_base_directory_path;
 		}
 		else {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine the vmdk base directory, could not determine VM path or datastore path from the database");
+			notify($ERRORS{'WARNING'}, 0, "vmx base directory path could not be determined from vmx file path: '$ENV{vmx_file_path}'");
 			return;
 		}
 	}
 	
-	# Remove any trailing slashes
-	$vmx_base_directory_path =~ s/\/$//g;
-	return $vmx_base_directory_path;
+	# Get the vmprofile.vmpath
+	# If this is not set, use vmprofile.datastorepath
+	$vmx_base_directory_path = $self->data->get_vmhost_profile_vmpath() || $self->data->get_vmhost_profile_datastore_path();
+	if (!$vmx_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the vmdk base directory path, failed to retrieve either the VM path or datastore path for the VM profile");
+		return;
+	}
+	
+	return normalize_file_path($vmx_base_directory_path);
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1540,8 +1703,8 @@ sub get_vmx_base_directory_path {
  Description : Returns the name of the directory in which the .vmx file is
                located.  The name differs depending on whether or not the VM
                is persistent.
-               If not persistent: <computer name>_<image ID>-<revision>
-               If persistent: <computer name>_<image ID>-<revision>_<request ID>
+               If not persistent: <computer name>_<image name>
+               If persistent: <computer name>_<image name>_<request ID>
 
 =cut
 
@@ -1553,44 +1716,106 @@ sub get_vmx_directory_name {
 	}
 	
 	my $vmx_directory_name;
-
+	
+	# Check if vmx_file_path environment variable has been set
+	# If set, parse the path to return the directory name preceding the vmx file name
+	# /<vmx base directory path>/<vmx directory name>/<vmx file name>
 	if ($ENV{vmx_file_path}) {
-		my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return;
-		($vmx_directory_name) = $ENV{vmx_file_path} =~ /^$vmx_base_directory_path\/(.+)\/[^\/]+.vmx$/;
-		return $vmx_directory_name;
+		($vmx_directory_name) = $ENV{vmx_file_path} =~ /([^\/]+)\/[^\/]+.vmx$/i;
+		if ($vmx_directory_name) {
+			return $vmx_directory_name;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "vmx directory name could not be determined from vmx file path: '$ENV{vmx_file_path}'");
+			return;
+		}
+	}
+	
+	if ($self->is_vm_persistent()) {
+		return $self->get_vmx_directory_name_persistent();
+	}
+	else {
+		return $self->get_vmx_directory_name_nonpersistent();
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmx_directory_name_persistent
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the name of the directory in which the .vmx file is
+               located if the VM is persistent. Example:
+					<computer name>_<image name>
+
+=cut
+
+sub get_vmx_directory_name_persistent {
+	my $self = shift;
+	if (ref($self) !~ /vmware/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $vmx_directory_name_nonpersistent = $self->get_vmx_directory_name_nonpersistent();
+	if (!$vmx_directory_name_nonpersistent) {
+		notify($ERRORS{'WARNING'}, 0, "unable to assemble the persistent vmx directory name, failed to retrieve the nonpersistent vmx directory name on which the persistent vmx directory name is based");
+		return;
+	}
+	
+	my $request_id = $self->data->get_request_id();
+	if (!defined($request_id)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to assemble the persistent vmx directory name, failed to retrieve request ID");
+		return;
 	}
 	
-	# Get the computer name, image ID, and revision number
+	return "$vmx_directory_name_nonpersistent\_$request_id";
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmx_directory_name_nonpersistent
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the name of the directory in which the .vmx file is
+               located if the VM is not persistent.
+               Example:
+               <computer name>_<image name>_<request ID>
+
+=cut
+
+sub get_vmx_directory_name_nonpersistent {
+	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;
+	}
+	
+	# Get the computer name
 	my $computer_short_name = $self->data->get_computer_short_name();
 	if (!$computer_short_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve computer short name");
+		notify($ERRORS{'WARNING'}, 0, "unable to assemble the nonpersistent vmx directory name, failed to retrieve computer short name");
 		return;
 	}
+	
+	# Get the image ID
 	my $image_id = $self->data->get_image_id();
 	if (!defined($image_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve image ID");
+		notify($ERRORS{'WARNING'}, 0, "unable to assemble the nonpersistent vmx directory name, failed to retrieve image ID");
 		return;
 	}
-	my $imagerevision_revision = $self->data->get_imagerevision_revision();
-	if (!defined($imagerevision_revision)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve imagerevision revision");
+	
+	# Get the image revision number
+	my $image_revision = $self->data->get_imagerevision_revision();
+	if (!defined($image_revision)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to assemble the nonpersistent vmx directory name, failed to retrieve image revision");
 		return;
 	}
 	
 	# Assemble the directory name
-	$vmx_directory_name = "$computer_short_name\_$image_id-v$imagerevision_revision";
-	
-	# If persistent, append the request ID
-	if ($self->is_vm_persistent()) {
-		my $request_id = $self->data->get_request_id();
-		if (!defined($request_id)) {
-			notify($ERRORS{'WARNING'}, 0, "unable to retrieve request ID");
-			return;
-		}
-		$vmx_directory_name .= "\_$request_id";
-	}
-	
-	return $vmx_directory_name;
+	return "$computer_short_name\_$image_id-v$image_revision";
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1613,10 +1838,22 @@ sub get_vmx_directory_path {
 		return;
 	}
 	
-	my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return;
-	my $vmx_directory_name = $self->get_vmx_directory_name() || return;
+	# Get the vmx file path
+	my $vmx_file_path = $self->get_vmx_file_path();
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx directory path could not be determined because vmx file path could not be retrieved");
+		return;
+	}
 	
-	return "$vmx_base_directory_path/$vmx_directory_name";
+	# Parse the vmx file path, return the path preceding the vmx file name
+	my ($vmx_directory_path) = $vmx_file_path =~ /(.+)\/[^\/]+.vmx$/i;
+	if ($vmx_directory_path) {
+		return $vmx_directory_path;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "vmx directory path could not be determined from vmx file path: '$vmx_file_path'");
+		return;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1638,37 +1875,181 @@ sub get_vmx_file_name {
 		return;
 	}
 	
-	if ($ENV{vmx_file_path}) {
-		my ($vmx_file_name) = $ENV{vmx_file_path} =~ /([^\/]+.vmx)$/g;
+	# Get the vmx file path
+	my $vmx_file_path = $self->get_vmx_file_path();
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx directory path could not be determined because vmx file path could not be retrieved");
+		return;
 	}
 	
-	my $vmx_directory_name = $self->get_vmx_directory_name() || return;
-	return "$vmx_directory_name.vmx";
+	# Parse the vmx file path, return the path preceding the vmx file name
+	my ($vmx_file_name) = $vmx_file_path =~ /\/([^\/]+.vmx)$/i;
+	if ($vmx_file_name) {
+		return $vmx_file_name;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "vmx file name could not be determined from vmx file path: '$vmx_file_path'");
+		return;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_vmx_file_path
+=head2 set_vmx_file_path
+
+ Parameters  : $vmx_file_path
+ Returns     : boolean
+ Description : Sets the vmx path into %ENV so that the default values are
+               overridden when the various get_vmx_ subroutines are called. This
+               is useful when a base image is being captured. The vmx file does
+               not need to be in the expected directory nor does it need to be
+               named anything particular. The code locates the vmx file and then
+               saves the non-default path in this object so that capture works
+               regardless of the vmx path/name.
+
+=cut
+
+sub set_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;
+	}
+	
+	# Get the vmx file path argument
+	my $vmx_file_path_argument = shift;
+	if (!$vmx_file_path_argument) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	
+	$vmx_file_path_argument = normalize_file_path($vmx_file_path_argument);
+	
+	# Make sure the vmx file path format is valid
+	if ($vmx_file_path_argument !~ /^\/.+\/.+\/[^\/]+\.vmx$/i) {
+		notify($ERRORS{'WARNING'}, 0, "unable to override vmx file path because the path format is invalid: '$vmx_file_path_argument'");
+		return;
+	}
+	
+	$ENV{vmx_file_path} = $vmx_file_path_argument;
+	
+	# Check all of the vmx file path components
+	if ($self->check_file_paths('vmx')) {
+		# Set the vmx_file_path environment variable
+		notify($ERRORS{'OK'}, 0, "set overridden vmx file path: '$vmx_file_path_argument'");
+		return 1;
+	}
+	else {
+		delete $ENV{vmx_file_path};
+		notify($ERRORS{'WARNING'}, 0, "failed to set overridden vmx file path: '$vmx_file_path_argument'");
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmdk_file_path
 
  Parameters  : none
  Returns     : string
- Description : Returns the path to the .vmx file.  Example:
-               vmx file path: /vmfs/volumes/nfs-vmpath/vm1-6-987-v0/vm1-6-987-v0.vmx
+ Description : Returns the path of the vmdk file. Example:
+               vmdk file path: /vmfs/volumes/nfs-datastore/vmwarewinxp-base234-v12/vmwarewinxp-base234-v12.vmdk
 
 =cut
 
-sub get_vmx_file_path {
+sub get_vmdk_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{vmdk_file_path} if $ENV{vmdk_file_path};
+	
+	if ($self->is_vm_persistent()) {
+		return $self->get_vmdk_file_path_persistent();
+	}
+	else {
+		return $self->get_vmdk_file_path_nonpersistent();
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmdk_file_path_persistent
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the vmdk file path for a persistent VM. This is
+               useful when checking the image size on a VM host using
+               network-based disks. It returns the vmdk file path that would be
+               used for nonperistent VMs.
+
+=cut
+
+sub get_vmdk_file_path_persistent {
+	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;
+	}
+	
+	# Get the vmprofile.datastorepath
+	my $vmdk_base_directory_path = $self->data->get_vmhost_profile_datastore_path();
+	if (!$vmdk_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the persistent vmdk file path, failed to retrieve datastore path for the VM profile");
+		return;
+	}
+	
+	my $vmdk_directory_name_persistent = $self->get_vmdk_directory_name_persistent();
+	if (!$vmdk_directory_name_persistent) {
+		notify($ERRORS{'WARNING'}, 0, "unable to construct vmdk file path, vmdk directory name could not be determined");
+		return;
+	}
+	
+	my $image_name = $self->data->get_image_name();
+	if (!$image_name) {
+		notify($ERRORS{'WARNING'}, 0, "unable to construct vmdk file path, image name could not be determined");
+		return;
+	}
+	
+	return "$vmdk_base_directory_path/$vmdk_directory_name_persistent/$image_name.vmdk";
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmdk_file_path_nonpersistent
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the vmdk file path for a nonpersistent VM. This is
+               useful when checking the image size on a VM host using
+               network-based disks. It returns the vmdk file path that would be
+               used for nonperistent VMs.
+
+=cut
+
+sub get_vmdk_file_path_nonpersistent {
 	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{vmx_file_path} if $ENV{vmx_file_path};
+	# Get the vmprofile.datastorepath
+	my $vmdk_base_directory_path = $self->data->get_vmhost_profile_datastore_path();
+	if (!$vmdk_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the nonpersistent vmdk file path, failed to retrieve datastore path for the VM profile");
+		return;
+	}
 	
-	my $vmx_directory_path = $self->get_vmx_directory_path() || return;
-	my $vmx_file_name = $self->get_vmx_file_name() || return;
-	return "$vmx_directory_path/$vmx_file_name";
+	my $vmdk_directory_name_nonpersistent = $self->get_vmdk_directory_name_nonpersistent();
+	if (!$vmdk_directory_name_nonpersistent) {
+		notify($ERRORS{'WARNING'}, 0, "unable to construct vmdk file path, vmdk directory name could not be determined");
+		return;
+	}
+	
+	return "$vmdk_base_directory_path/$vmdk_directory_name_nonpersistent/$vmdk_directory_name_nonpersistent.vmdk";
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1691,24 +2072,30 @@ sub get_vmdk_base_directory_path {
 		return;
 	}
 	
-	# Check if $ENV{vmdk_file_path} is set, parse this path if it is set
-	if (my $vmdk_file_path = $ENV{vmdk_file_path}) {
-		my ($vmdk_base_directory_path) = $vmdk_file_path =~ /^(.+)\/[^\/]+\/[^\/]+\.vmdk$/g;
-		if (!$vmdk_base_directory_path) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk base directory path from vmdk file path: $vmdk_file_path");
-			return;
+	my $vmdk_base_directory_path;
+	
+	# Check if vmdk_file_path environment variable has been set
+	# If set, parse the path to return the directory name preceding the vmdk file name and directory name
+	# /<vmdk base directory path>/<vmdk directory name>/<vmdk file name>
+	if ($ENV{vmdk_file_path}) {
+		($vmdk_base_directory_path) = $ENV{vmdk_file_path} =~ /(.+)\/[^\/]+\/[^\/]+.vmdk$/i;
+		if ($vmdk_base_directory_path) {
+			return $vmdk_base_directory_path;
 		}
-		return $vmdk_base_directory_path;
-	}
-	else {
-		# Get the VM host profile datastore path
-		my $vmhost_profile_datastore_path = normalize_file_path($self->data->get_vmhost_profile_datastore_path());
-		if (!$vmhost_profile_datastore_path) {
-			notify($ERRORS{'WARNING'}, 0, "unable to retrieve VM host profile datastore path");
+		else {
+			notify($ERRORS{'WARNING'}, 0, "vmdk base directory path could not be determined from vmdk file path: '$ENV{vmdk_file_path}'");
 			return;
 		}
-		return $vmhost_profile_datastore_path;
 	}
+	
+	# Get the vmprofile.datastorepath
+	$vmdk_base_directory_path = $self->data->get_vmhost_profile_datastore_path();
+	if (!$vmdk_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the vmdk base directory path, failed to retrieve either the datastore path for the VM profile");
+		return;
+	}
+	
+	return normalize_file_path($vmdk_base_directory_path);
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1735,6 +2122,20 @@ sub get_vmdk_directory_name {
 		return;
 	}
 	
+	# Check if vmdk_file_path environment variable has been set
+	# If set, parse the path to return the directory name preceding the vmdk file name
+	# /<vmdk base directory path>/<vmdk directory name>/<vmdk file name>
+	if ($ENV{vmdk_file_path}) {
+		my ($vmdk_directory_name) = $ENV{vmdk_file_path} =~ /([^\/]+)\/[^\/]+.vmdk$/i;
+		if ($vmdk_directory_name) {
+			return $vmdk_directory_name;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "vmdk directory name could not be determined from vmdk file path: '$ENV{vmdk_file_path}'");
+			return;
+		}
+	}
+	
 	if ($self->is_vm_persistent()) {
 		return $self->get_vmdk_directory_name_persistent();
 	}
@@ -1762,19 +2163,15 @@ sub get_vmdk_directory_name_persistent {
 		return;
 	}
 	
-	if ($ENV{vmdk_file_path}) {
-		my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
-		my ($vmdk_directory_name) = $ENV{vmdk_file_path} =~ /^$vmdk_base_directory_path\/(.+)\/[^\/]+.vmdk$/;
-		if ($vmdk_directory_name) {
-			return $vmdk_directory_name;
-		}
-		else {
-			notify($ERRORS{'WARNING'}, 0, "unable to parse vmdk directory name from vmdk file path: $ENV{vmdk_file_path}");
-			return;
-		}
+	# Use the same name that's used for the persistent vmx directory name
+	my $vmdk_directory_name_persistent = $self->get_vmx_directory_name_persistent();
+	if ($vmdk_directory_name_persistent) {
+		return $vmdk_directory_name_persistent;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine persistent vmdk directory name because persistent vmx directory name could not be retrieved");
+		return;
 	}
-	
-	return $self->get_vmx_directory_name();
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1796,25 +2193,15 @@ sub get_vmdk_directory_name_nonpersisten
 		return;
 	}
 	
-	if ($ENV{vmdk_file_path}) {
-		my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
-		my ($vmdk_directory_name) = $ENV{vmdk_file_path} =~ /^$vmdk_base_directory_path\/(.+)\/[^\/]+.vmdk$/;
-		
-		if ($vmdk_directory_name) {
-			return $vmdk_directory_name;
-		}
-		else {
-			notify($ERRORS{'WARNING'}, 0, "unable to parse vmdk directory name from vmdk file path: $ENV{vmdk_file_path}");
-			return;
-		}
-	}
-	
+	# Use the image name for the vmdk directory name
 	my $image_name = $self->data->get_image_name();
-	if (!$image_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable determine vmdk directory name because unable to retrieve image name");
+	if ($image_name) {
+		return $image_name;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable determine vmdk nonpersistent vmdk directory name because image name could not be retrieved");
 		return;
 	}
-	return $image_name;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1837,19 +2224,60 @@ sub get_vmdk_directory_path {
 		return;
 	}
 	
-	my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path();
+	# Check if vmdk_file_path environment variable has been set
+	# If set, parse the path to return the directory name preceding the vmdk file name
+	# /<vmdk base directory path>/<vmdk directory name>/<vmdk file name>
+	if ($ENV{vmdk_file_path}) {
+		my ($vmdk_directory_path) = $ENV{vmdk_file_path} =~ /(.+)\/[^\/]+.vmdk$/i;
+		if ($vmdk_directory_path) {
+			return $vmdk_directory_path;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "vmdk directory name could not be determined from vmdk file path: '$ENV{vmdk_file_path}'");
+			return;
+		}
+	}
+	
+	if ($self->is_vm_persistent()) {
+		return $self->get_vmdk_directory_path_persistent();
+	}
+	else {
+		return $self->get_vmdk_directory_path_nonpersistent();
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vmdk_directory_path_persistent
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the directory path under which the .vmdk files are
+               located for persistent VMs.
+
+=cut
+
+sub get_vmdk_directory_path_persistent {
+	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;
+	}
+	
+	# Get the vmprofile.datastorepath
+	my $vmdk_base_directory_path = $self->data->get_vmhost_profile_datastore_path();
 	if (!$vmdk_base_directory_path) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk directory path because vmdk base directory path could not be determined");
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the persistent vmdk base directory path, failed to retrieve datastore path for the VM profile");
 		return;
 	}
 	
-	my $vmdk_directory_name = $self->get_vmdk_directory_name() || return;
-	if (!$vmdk_directory_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk directory path because vmdk directory name could not be determined");
+	my $vmdk_directory_name_persistent = $self->get_vmdk_directory_name_persistent();
+	if (!$vmdk_directory_name_persistent) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine persistent vmdk directory path because persistent vmdk directory name could not be determined");
 		return;
 	}
 	
-	return "$vmdk_base_directory_path/$vmdk_directory_name";
+	return "$vmdk_base_directory_path/$vmdk_directory_name_persistent";
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1870,19 +2298,20 @@ sub get_vmdk_directory_path_nonpersisten
 		return;
 	}
 	
-	my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
+	# Get the vmprofile.datastorepath
+	my $vmdk_base_directory_path = $self->data->get_vmhost_profile_datastore_path();
 	if (!$vmdk_base_directory_path) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine nonpersistent vmdk directory path because vmdk base directory path could not be determined");
+		notify($ERRORS{'WARNING'}, 0, "unable to determine the nonpersistent vmdk base directory path, failed to retrieve datastore path for the VM profile");
 		return;
 	}
 	
-	my $vmdk_directory_name = $self->get_vmdk_directory_name_nonpersistent() || return;
-	if (!$vmdk_directory_name) {
+	my $vmdk_directory_name_nonpersistent = $self->get_vmdk_directory_name_nonpersistent();
+	if (!$vmdk_directory_name_nonpersistent) {
 		notify($ERRORS{'WARNING'}, 0, "unable to determine nonpersistent vmdk directory path because nonpersistent vmdk directory name could not be determined");
 		return;
 	}
 	
-	return "$vmdk_base_directory_path/$vmdk_directory_name";
+	return "$vmdk_base_directory_path/$vmdk_directory_name_nonpersistent";
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1905,13 +2334,22 @@ sub get_vmdk_file_prefix {
 		return;
 	}
 	
-	if ($ENV{vmdk_file_path}) {
-		my ($vmdk_file_prefix) = $ENV{vmdk_file_path} =~ /([^\/]+).vmdk$/g;
-		return $vmdk_file_prefix;
+	# Get the vmdk file path
+	my $vmdk_file_path = $self->get_vmdk_file_path();
+	if (!$vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk directory path could not be determined because vmdk file path could not be retrieved");
+		return;
 	}
 	
-	my $image_name = $self->data->get_image_name() || return;
-	return $image_name;
+	# Parse the vmdk file path, return the path preceding the vmdk file name
+	my ($vmdk_file_name) = $vmdk_file_path =~ /\/([^\/]+)\.vmdk$/i;
+	if ($vmdk_file_name) {
+		return $vmdk_file_name;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file name could not be determined from vmdk file path: '$vmdk_file_path'");
+		return;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1933,61 +2371,133 @@ sub get_vmdk_file_name {
 		return;
 	}
 	
-	my $vmdk_file_prefix = $self->get_vmdk_file_prefix() || return;
-	if (!$vmdk_file_prefix) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk file name because vmdk file prefix could not be determined");
+	# Get the vmdk file path
+	my $vmdk_file_path = $self->get_vmdk_file_path();
+	if (!$vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk directory path could not be determined because vmdk file path could not be retrieved");
 		return;
 	}
 	
-	return "$vmdk_file_prefix.vmdk";
+	# Parse the vmdk file path, return the path preceding the vmdk file name
+	my ($vmdk_file_name) = $vmdk_file_path =~ /\/([^\/]+\.vmdk)$/i;
+	if ($vmdk_file_name) {
+		return $vmdk_file_name;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file name could not be determined from vmdk file path: '$vmdk_file_path'");
+		return;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_vmdk_file_path_nonpersistent
+=head2 set_vmdk_file_path
 
- Parameters  : none
- Returns     : string
- Description : Returns the vmdk file path for a nonpersistent VM. This is
-               useful when checking the image size on a VM host using
-               network-based disks. It returns the vmdk file path that would be
-               used for nonperistent VMs.
+ Parameters  : $vmx_file_path
+ Returns     : 
+ Description : Sets the vmdk path into %ENV so that the default values are
+               overridden when the various get_vmdk_... subroutines are called.
+               This is useful for base image imaging reservations if the
+               code detects the vmdk path is not in the expected place.
 
 =cut
 
-sub get_vmdk_file_path_nonpersistent {
+sub set_vmdk_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;
 	}
 	
-	my $vmdk_directory_path_nonpersistent = $self->get_vmdk_directory_path_nonpersistent() || return;
-	my $vmdk_file_name = $self->get_vmdk_file_name() || return;
-	return "$vmdk_directory_path_nonpersistent/$vmdk_file_name";
+	# Get the vmdk file path argument
+	my $vmdk_file_path_argument = shift;
+	if (!$vmdk_file_path_argument) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
+		return;
+	}
+	
+	$vmdk_file_path_argument = normalize_file_path($vmdk_file_path_argument);
+	
+	# Make sure the vmdk file path format is valid
+	if ($vmdk_file_path_argument !~ /^\/.+\/.+\/[^\/]+\.vmdk$/i) {
+		notify($ERRORS{'WARNING'}, 0, "unable to override vmdk file path because the path format is invalid: '$vmdk_file_path_argument'");
+		return;
+	}
+	
+	$ENV{vmdk_file_path} = $vmdk_file_path_argument;
+	
+	# Check all of the vmdk file path components
+	if ($self->check_file_paths('vmdk')) {
+		# Set the vmdk_file_path environment variable
+		notify($ERRORS{'OK'}, 0, "set overridden vmdk file path: '$vmdk_file_path_argument'");
+		return 1;
+	}
+	else {
+		delete $ENV{vmdk_file_path};
+		notify($ERRORS{'WARNING'}, 0, "failed to set overridden vmdk file path: '$vmdk_file_path_argument'");
+		return;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_vmdk_file_path
+=head2 check_file_paths
 
  Parameters  : none
- Returns     : string
- Description : Returns the path of the vmdk file. Example:
-               vmdk file path: /vmfs/volumes/nfs-datastore/vmwarewinxp-base234-v12/vmwarewinxp-base234-v12.vmdk
+ Returns     : 
+ Description : 
 
 =cut
 
-sub get_vmdk_file_path {
+sub check_file_paths {
 	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");
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
 		return;
 	}
 	
-	my $vmdk_directory_path = $self->get_vmdk_directory_path() || return;
-	my $vmdk_file_name = $self->get_vmdk_file_name() || return;
-	return "$vmdk_directory_path/$vmdk_file_name";
+	my $file_type = shift || 'all';
+	
+	# Check to make sure all of the vmdk file path components can be retrieved
+	my $undefined_string = "<undefined>";
+	
+	# Assemble a string of all of the components
+	my $check_paths_string;
+	
+	if ($file_type !~ /vmdk/i) {
+		$check_paths_string .= "vmx file path:                     '" . ($self->get_vmx_file_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmx directory path:                '" . ($self->get_vmx_directory_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmx base directory path:           '" . ($self->get_vmx_base_directory_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmx directory name:                '" . ($self->get_vmx_directory_name() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmx file name:                     '" . ($self->get_vmx_file_name() || $undefined_string) . "'\n";
+		$check_paths_string .= "persistent vmx directory name:     '" . ($self->get_vmx_directory_name_persistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "nonpersistent vmx directory name:  '" . ($self->get_vmx_directory_name_nonpersistent() || $undefined_string) . "'\n";
+	}
+	
+	if ($file_type !~ /vmx/i) {
+		$check_paths_string .= "vmdk file path:                    '" . ($self->get_vmdk_file_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmdk directory path:               '" . ($self->get_vmdk_directory_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmdk base directory path:          '" . ($self->get_vmdk_base_directory_path() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmdk directory name:               '" . ($self->get_vmdk_directory_name() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmdk file name:                    '" . ($self->get_vmdk_file_name() || $undefined_string) . "'\n";
+		$check_paths_string .= "vmdk file prefix:                  '" . ($self->get_vmdk_file_prefix() || $undefined_string) . "'\n";
+		$check_paths_string .= "persistent vmdk file path:         '" . ($self->get_vmdk_file_path_persistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "persistent vmdk directory path:    '" . ($self->get_vmdk_directory_path_persistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "persistent vmdk directory name:    '" . ($self->get_vmdk_directory_name_persistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "nonpersistent vmdk file path:      '" . ($self->get_vmdk_file_path_nonpersistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "nonpersistent vmdk directory path: '" . ($self->get_vmdk_directory_path_nonpersistent() || $undefined_string) . "'\n";
+		$check_paths_string .= "nonpersistent vmdk directory name: '" . ($self->get_vmdk_directory_name_nonpersistent() || $undefined_string) . "'\n";
+	}
+	
+	if ($check_paths_string =~ /$undefined_string/) {
+		notify($ERRORS{'WARNING'}, 0, "failed to retrieve $file_type file path components:\n$check_paths_string");
+		return;
+	}
+	else {
+		# Set the vmdk_file_path environment variable
+		notify($ERRORS{'OK'}, 0, "successfully retrieved $file_type file path components:\n$check_paths_string");
+		return 1;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2699,9 +3209,16 @@ sub get_vmx_file_paths {
 	
 	my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return;
 	
-	my @vmx_paths = $self->vmhost_os->find_files($vmx_base_directory_path, "*.vmx");
-	notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@vmx_paths) . " vmx files on VM host");
-	return @vmx_paths;
+	# Get a list of all the vmx files under the normal vmx base directory
+	my @found_vmx_paths = $self->vmhost_os->find_files($vmx_base_directory_path, "*.vmx");
+	
+	# Get a list of the registered VMs in case a VM is registered and the vmx file does not reside under the normal vmx base directory
+	my @registered_vmx_paths = $self->api->get_registered_vms();
+	
+	my %vmx_file_paths = map { $_ => 1 } (@found_vmx_paths, @registered_vmx_paths);
+	notify($ERRORS{'DEBUG'}, 0, "found " . scalar(keys %vmx_file_paths) . " unique vmx files on VM host:\n" . join("\n", sort keys %vmx_file_paths));
+	
+	return sort keys %vmx_file_paths;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -3019,167 +3536,6 @@ sub get_vm_additional_vmx_bytes_required
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 set_vmx_file_path
-
- Parameters  : $vmx_file_path
- Returns     : boolean
- Description : Sets the vmx path into %ENV so that the default values are
-               overridden when the various get_vmx_ subroutines are called. This
-               is useful when a base image is being captured. The vmx file does
-               not need to be in the expected directory nor does it need to be
-               named anything particular. The code locates the vmx file and then
-               saves the non-default path in this object so that capture works
-               regardless of the vmx path/name.
-
-=cut
-
-sub set_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;
-	}
-	
-	# Get the vmx file path argument
-	my $vmx_file_path = shift;
-	if (!$vmx_file_path) {
-		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
-		return;
-	}
-	
-	delete $ENV{vmx_file_path};
-	
-	if ($vmx_file_path ne $self->get_vmx_file_path()) {
-		notify($ERRORS{'DEBUG'}, 0, "vmx file path will be overridden, it does not match the expected path:
-				 argument: $vmx_file_path
-				 expected: " . $self->get_vmx_file_path());
-	}
-	else {
-		return 1;
-	}
-	
-	# Make sure the vmx file path begins with the vmx base directory
-	my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || return;
-	if ($vmx_file_path !~ /^$vmx_base_directory_path/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmx file path $vmx_file_path, it does not begin with the vmx base directory path: $vmx_base_directory_path");
-		return;
-	}
-	
-	# Make sure the vmx file path ends with .vmx
-	if ($vmx_file_path !~ /\.vmx$/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmx file path $vmx_file_path, it does not end with .vmx");
-		return;
-	}
-	
-	# Make sure the vmx file path contains a file name
-	if ($vmx_file_path !~ /\/[^\/]+\.vmx$/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmx file path $vmx_file_path, it does not contain a file name");
-		return;
-	}
-	
-	# Make sure the vmx file path contains an intermediate path
-	if ($vmx_file_path !~ /^$vmx_base_directory_path\/.+\/[^\/]+\.vmx$/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmx file path $vmx_file_path, it does not contain an intermediate path");
-		return;
-	}
-	
-	$ENV{vmx_file_path} = $vmx_file_path;
-	notify($ERRORS{'OK'}, 0, "set overridden vmx location:\n" .
-			 "vmx file path: $vmx_file_path\n" .
-			 "vmx base directory path: " . $self->get_vmx_base_directory_path() . "\n" .
-			 "vmx directory name: " . $self->get_vmx_directory_name() . "\n" .
-			 "vmx directory path: " . $self->get_vmx_directory_path() . "\n" .
-			 "vmx file name: " . $self->get_vmx_file_name() . "\n" .
-			 "vmx file path: " . $self->get_vmx_file_path());
-	
-	return 1;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 set_vmdk_file_path
-
- Parameters  : $vmx_file_path
- Returns     : 
- Description : Sets the vmdk path into %ENV so that the default values are
-               overridden when the various get_vmdk_... subroutines are called.
-               This is useful for base image imaging reservations if the
-               code detects the vmdk path is not in the expected place.
-
-=cut
-
-sub set_vmdk_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;
-	}
-	
-	# Get the vmdk file path argument
-	my $vmdk_file_path_argument = shift;
-	if (!$vmdk_file_path_argument) {
-		notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
-		return;
-	}
-	
-	delete $ENV{vmdk_file_path};
-	
-	if ($vmdk_file_path_argument ne $self->get_vmdk_file_path()) {
-		notify($ERRORS{'DEBUG'}, 0, "vmdk file path will be overridden, it does not match the expected path:
-				 argument: $vmdk_file_path_argument
-				 expected: " . $self->get_vmdk_file_path());
-	}
-	else {
-		notify($ERRORS{'DEBUG'}, 0, "vmdk file path does not need to overridden, it matches the expected path: $vmdk_file_path_argument");
-		return 1;
-	}
-	
-	# Make sure the vmdk file path ends with .vmdk
-	if ($vmdk_file_path_argument !~ /\.vmdk$/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmdk file path $vmdk_file_path_argument, it does not end with .vmdk");
-		return;
-	}
-	
-	# Make sure the vmdk file path contains a file name
-	if ($vmdk_file_path_argument !~ /\/[^\/]+\.vmdk$/) {
-		notify($ERRORS{'WARNING'}, 0, "unable to override vmdk file path $vmdk_file_path_argument, it does not contain a file name");
-		return;
-	}
-	
-	$ENV{vmdk_file_path} = $vmdk_file_path_argument;
-	
-	my $vmdk_file_path = $self->get_vmdk_file_path() || 'UNAVAILABLE';
-	my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || 'UNAVAILABLE';
-	my $vmdk_directory_name = $self->get_vmdk_directory_name() || 'UNAVAILABLE';
-	my $vmdk_directory_path = $self->get_vmdk_directory_path() || 'UNAVAILABLE';
-	my $vmdk_file_name = $self->get_vmdk_file_name() || 'UNAVAILABLE';
-	
-	if (grep(/UNAVAILABLE/, ($vmdk_file_path, $vmdk_base_directory_path, $vmdk_directory_name, $vmdk_directory_path, $vmdk_file_name))) {
-		notify($ERRORS{'WARNING'}, 0, "failed to override vmdk location, some path components are unavailable:\n" .
-			 "vmdk file path argument: $vmdk_file_path_argument\n" .
-			 "vmdk file path: $vmdk_file_path\n" .
-			 "vmdk base directory path: $vmdk_base_directory_path\n" .
-			 "vmdk directory name: $vmdk_directory_name\n" .
-			 "vmdk directory path: $vmdk_directory_path\n" .
-			 "vmdk file name: $vmdk_file_name\n" .
-			 "vmdk file path: $vmdk_file_path");
-		return;
-	}
-	
-	notify($ERRORS{'OK'}, 0, "set overridden vmdk location:\n" .
-			 "vmdk file path argument: $vmdk_file_path_argument\n" .
-			 "vmdk file path: $vmdk_file_path\n" .
-			 "vmdk base directory path: $vmdk_base_directory_path\n" .
-			 "vmdk directory name: $vmdk_directory_name\n" .
-			 "vmdk directory path: $vmdk_directory_path\n" .
-			 "vmdk file name: $vmdk_file_name\n" .
-			 "vmdk file path: $vmdk_file_path");
-	
-	return 1;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 rename_vmdk
 
  Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path

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=987623&r1=987622&r2=987623&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 Fri Aug 20 20:06:13 2010
@@ -368,11 +368,7 @@ sub get_vm_power_state {
  Description : Copies a virtual disk (set of vmdk files). This subroutine allows
                a virtual disk to be converted to a different disk type or
                adapter type. The source and destination vmdk file path arguments
-               are required. The adapter type argument is optional and may be
-               one of the following values:
-               -busLogic (default)
-               -ide
-               -lsiLogic
+               are required.
                
                The disk type argument is optional and may be one of the
                following values:
@@ -423,6 +419,16 @@ sub get_vm_power_state {
                   -not usable for disk creation
                -thin (default)
                   -space required for thin-provisioned virtual disk is allocated and zeroed on demand as the space is used
+                  
+               The adapter type argument is optional and may be one of the
+               following values:
+               -busLogic
+               -ide
+               -lsiLogic
+               
+               If the adapter type argument is not specified an attempt will be
+               made to retrieve it from the source vmdk file. If this fails,
+               lsiLogic will be used.
 
 =cut
 
@@ -440,7 +446,17 @@ sub copy_virtual_disk {
 	# Get the adapter type and disk type arguments if they were specified
 	# If not specified, set the default values
 	my $destination_disk_type = shift || 'thin';
-	my $destination_adapter_type = shift || 'busLogic';
+	my $destination_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';
+		}
+	}
 	
 	# Check the adapter type argument, the string must match exactly or the copy will fail
 	my @valid_adapter_types = qw( busLogic lsiLogic ide );
@@ -518,7 +534,7 @@ sub copy_virtual_disk {
 	my $bits_per_second = ($source_file_size_bytes * 8 / $duration_seconds);
 	my $mb_per_second = ($source_file_size_bytes / $duration_seconds / 1024 / 1024);
 	my $mbit_per_second = ($source_file_size_bytes * 8 / $duration_seconds / 1024 / 1024);
-	my $gbit_per_minute = ($source_file_size_bytes * 8 / $duration_seconds / 1024 / 1024 * 60);
+	my $gbyte_per_minute = ($source_file_size_bytes / $duration_seconds / 1024 / 1024 / 1024 * 60);
 	
 	notify($ERRORS{'OK'}, 0, "copied vmdk: '$source_path' --> '$destination_path'" .
 			 "source file bytes: " . format_number($source_file_size_bytes) . "\n" .
@@ -527,7 +543,7 @@ sub copy_virtual_disk {
 			 "b/s: " . format_number($bits_per_second) . "\n" .
 			 "MB/s: " . format_number($mb_per_second, 2) . "\n" .
 			 "Mb/s: " . format_number($mbit_per_second, 2) . "\n" .
-			 "Gb/m: " . format_number($gbit_per_minute, 2));
+			 "GB/m: " . format_number($gbyte_per_minute, 2));
 	return 1;
 }
 
@@ -1514,7 +1530,6 @@ sub file_exists {
 	
 	# Get and check the file path argument
 	my $file_path = $self->get_datastore_path(shift) || return;
-	notify($ERRORS{'DEBUG'}, 0, "checking if file exists: $file_path");
 	
 	# Check if the path argument is the root of a datastore
 	if ($file_path =~ /^\[(.+)\]$/) {