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/10/08 17:01:19 UTC

svn commit: r1005854 [1/2] - in /incubator/vcl/trunk/managementnode/lib/VCL: ./ Module/ Module/Provisioning/VMware/

Author: arkurth
Date: Fri Oct  8 15:01:19 2010
New Revision: 1005854

URL: http://svn.apache.org/viewvc?rev=1005854&view=rev
Log:
VCL-394
Updated Module.pm::get_semaphore to accept a semaphore ID string rather than just a specific file path.  Added code to Semaphore.pm to display the name of the process holding a lock on a file if unable to obtain a lock.

Updated VMware.pm:
-Added code to normalize the datastore and VM paths when initialized in case they arrive escaped.  Subroutines which use these paths expect them to not be escaped.
-Commented out code which deletes the vmdk directory on the VM host during image capture if it has been copied to the image repository for safety.
-Added check in prepare_vmx to determine if the network name should be specified using 'networkName' or 'vnet'.
-Added 'svga.autodetect = TRUE' to vmx files.  This should allow the screen to be displayed properly in the vSphere console.
-Added code to obtain a semaphore lock in prepare_vmdk to prevent multiple concurrent copies of the same files.
-Added code to check if the image repository path is mounted on the VM host. If so, files are copied using VMware's disk copy methods.  If not available (meaning repository path resides on the management node), SCP is used.
-Added vmware_cmd.pm which can control a VMware Server 1.x host using vmware-cmd.

Other
Made minor change to output in Module.pm::new and State.pm::Destroy.  Commented out unnecessary log messages in utils.pm::nmap_port.

Added:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm   (with props)
Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.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/Module/Semaphore.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/State.pm
    incubator/vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module.pm?rev=1005854&r1=1005853&r2=1005854&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module.pm Fri Oct  8 15:01:19 2010
@@ -131,7 +131,7 @@ sub new {
 	my $class = shift;
 	my $args  = shift;
 
-	notify($ERRORS{'DEBUG'}, 0, "constructor called, class=$class");
+	notify($ERRORS{'DEBUG'}, 0, "$class constructor called");
 	
 	# Create a variable to store the newly created class object
 	my $class_object;
@@ -426,7 +426,7 @@ sub code_loop_timeout {
 
 =head2 get_semaphore
 
- Parameters  : $file_path, $total_wait_seconds (optional), $attempt_delay_seconds (optional)
+ Parameters  : $semaphore_id, $total_wait_seconds (optional), $attempt_delay_seconds (optional)
  Returns     : VCL::Module::Semaphore object
  Description : This subroutine is used to ensure that only 1 process performs a
                particular task at a time. An example would be the retrieval of
@@ -474,12 +474,16 @@ sub get_semaphore {
 	}
 	
 	# Get the file path argument
-	my ($file_path, $total_wait_seconds, $attempt_delay_seconds) = @_;
-	if (!$file_path) {
-		notify($ERRORS{'WARNING'}, 0, "file path argument was not supplied");
+	my ($semaphore_id, $total_wait_seconds, $attempt_delay_seconds) = @_;
+	if (!$semaphore_id) {
+		notify($ERRORS{'WARNING'}, 0, "semaphore ID argument was not supplied");
 		return;
 	}
 	
+	$semaphore_id =~ s/\W+/-/g;
+	$semaphore_id =~ s/(^-|-$)//g;
+	my $file_path = "/tmp/$semaphore_id.lock";
+	
 	# Attempt to create a new semaphore object
 	my $semaphore = VCL::Module::Semaphore->new({'data_structure' => $self->data});
 	if (!$semaphore) {
@@ -490,6 +494,8 @@ sub get_semaphore {
 	# Attempt to open and exclusively lock the file
 	if ($semaphore->get_lockfile($file_path, $total_wait_seconds, $attempt_delay_seconds)) {
 		# Return the semaphore object
+		my $address = sprintf('%x', $semaphore);
+		notify($ERRORS{'DEBUG'}, 0, "created Semaphore object, memory address: $address");
 		return $semaphore;
 	}
 	else {

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm?rev=1005854&r1=1005853&r2=1005854&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm Fri Oct  8 15:01:19 2010
@@ -118,12 +118,12 @@ sub initialize {
 	my $command = 'vim-cmd ; vmware-vim-cmd';
 	my ($exit_status, $output) = $self->vmhost_os->execute($command);
 	if (!defined($output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to determine which VIM executable is available on the VM host");
+		notify($ERRORS{'OK'}, 0, "VIM executable is not available on the VM host");
 		return;
 	}
 	elsif (!grep(/vmsvc/, @$output)) {
 		# String 'vmsvc' does not exist in the output, neither of the commands worked
-		notify($ERRORS{'DEBUG'}, 0, "failed to determine which VIM executable is available on the VM host, output:\n" . join("\n", @$output));
+		notify($ERRORS{'DEBUG'}, 0, "VIM executable is not available on the VM host, output:\n" . join("\n", @$output));
 		return;
 	}
 	elsif (grep(/: vim-cmd:.*not found/i, @$output)) {
@@ -950,6 +950,8 @@ sub get_vm_power_state {
 	# Retrieved runtime info
 	# Suspended
 	
+	notify($ERRORS{'DEBUG'}, 0, "$vim_cmd_arguments:\n" . join("\n", @$output));
+	
 	if (grep(/powered on/i, @$output)) {
 		notify($ERRORS{'DEBUG'}, 0, "VM is powered on: $vmx_file_path");
 		return 'on';
@@ -1677,180 +1679,6 @@ sub get_virtual_disk_hardware_version {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 copy_virtual_disk
-
- Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path, $destination_disk_type (optional)
- Returns     : boolean
- Description : Copies a virtual disk on the VMware host using vmkfstools. The
-               disk type argument may be one of the following values:
-					zeroedthick
-					thin (default)
-					eagerzeroedthick
-					2gbsparse
-
-=cut
-
-sub copy_virtual_disk {
-	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 source and destination path arguments
-	my $source_path = shift;
-	my $destination_path = shift;
-	if (!$source_path || !$destination_path) {
-		notify($ERRORS{'WARNING'}, 0, "source and destination vmdk file path arguments were not specified");
-		return;
-	}
-	
-	# Get the disk type argument if specified
-	# If not specified, set default value
-	my $destination_disk_type = shift || 'thin';
-	
-	# Get the destination parent directory path and create the directory
-	my ($destination_directory_path) = $destination_path =~ /(.+)\/[^\/]+/;
-	if (!$self->vmhost_os->create_directory($destination_directory_path)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to copy virtual disk, destination directory could not be created on the VM host: $destination_directory_path");
-		return;
-	}
-	
-	# vmware-vdiskmanager disk types:
-	# 0 - single growable virtual disk, no separate descriptor file (copy time: 1:04)
-	#     createType="monolithicSparse"
-	#     4.2G disk_0.vmdk
-	#     4.2G total
-	# 1 - growable virtual disk split in 2GB files (copy time: 1:08)
-	#     createType="twoGbMaxExtentSparse"
-	#     691  disk_1.vmdk
-	#     2.0G disk_1-s001.vmdk
-	#     904M disk_1-s002.vmdk
-	#     16M  disk_1-s003.vmdk
-	#     203M disk_1-s004.vmdk
-	#     398M disk_1-s005.vmdk
-	#     623M disk_1-s006.vmdk
-	#     21M  disk_1-s007.vmdk
-	#     128K disk_1-s008.vmdk
-	#     4.2G total
-	# 2 - preallocated virtual disk (copy time: 12:33)
-	#     createType="monolithicFlat"
-	#     429 disk_2.vmdk
-	#     14G disk_2-flat.vmdk
-	#     15G total
-	# 3 - preallocated virtual disk split in 2GB files (copy time: 4:06)
-	#     createType="twoGbMaxExtentFlat"
-	#     688 disk_3.vmdk
-	#     2.0G disk_3-f001.vmdk
-	#     2.0G disk_3-f002.vmdk
-	#     2.0G disk_3-f003.vmdk
-	#     2.0G disk_3-f004.vmdk
-	#     2.0G disk_3-f005.vmdk
-	#     2.0G disk_3-f006.vmdk
-	#     2.0G disk_3-f007.vmdk
-	#     1.8M disk_3-f008.vmdk
-	#     15G total
-	# 4 : preallocated ESX-type virtual disk (copy time: 10:00)
-	#     createType="vmfs"
-	#     419 disk_4.vmdk
-	#     14G disk_4-flat.vmdk
-	#     15G total
-	# 5 : compressed disk optimized for streaming (copy time: 3:21)
-	#     createType="streamOptimized"
-	#     2.5G disk_5.vmdk
-	#     2.5G total
-	my $vdisk_type;
-	if ($destination_disk_type =~ /thin/i) {
-		$vdisk_type = 0;
-	}
-	elsif ($destination_disk_type =~ /2gbsparse/i) {
-		$vdisk_type = 1;
-	}
-	else {
-		$vdisk_type = 4;
-	}
-	
-	my $success = 0;
-	my $start_time;
-	my $end_time;
-	
-	# Try vmware-vdiskmanager
-	notify($ERRORS{'DEBUG'}, 0, "attempting to copy virtual disk using 'vmware-vdiskmanager', disk type: $destination_disk_type ($vdisk_type)");
-	my $vdisk_command = "vmware-vdiskmanager -r \"$source_path\" -t $vdisk_type \"$destination_path\"";
-	$start_time = time;
-	my ($vdisk_exit_status, $vdisk_output) = $self->vmhost_os->execute($vdisk_command);
-	if (!defined($vdisk_output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware-vdiskmanager' command on VM host to copy vmdk file:\n$vdisk_command");
-	}
-	elsif (grep(/success/i, @$vdisk_output)) {
-		$end_time = time;
-		$success = 1;
-		notify($ERRORS{'OK'}, 0, "copied vmdk file by executing 'vmware-vdiskmanager' on VM host: '$source_path' --> '$destination_path'");
-	}
-	elsif (grep(/not found/i, @$vdisk_output)) {
-		notify($ERRORS{'DEBUG'}, 0, "unable to copy vmdk using 'vmware-vdiskmanager' because the command is not available on VM host");
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware-vdiskmanager' on VM host to copy vmdk file:\n$vdisk_command\noutput:\n" . join("\n", @$vdisk_output));
-	}
-	
-	if (!$success){
-		# Run vmkfstools to copy the virtual disk
-		my $vmkfstools_command = "vmkfstools -i \"$source_path\" \"$destination_path\" -d $destination_disk_type";
-		notify($ERRORS{'DEBUG'}, 0, "attempting to copy virtual disk using 'vmkfstools', disk type: $destination_disk_type");
-		$start_time = time;
-		my ($vmkfstools_exit_status, $vmkfstools_output) = $self->vmhost_os->execute($vmkfstools_command);
-		
-		# Expected output:
-		# Destination disk format: VMFS thin-provisioned
-		# Cloning disk '/vmfs/volumes/nfs-datastore/vmwarewinxp-base234-v12/vmwarewinxp-base234-v12.vmdk'...
-		# Clone: 0% done.Clone: 1% done. ... Clone: 98% done.Clone: 99% done.Clone: 100% done.
-	
-		if (!defined($vmkfstools_output)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host: $vmkfstools_command");
-			return;
-		}
-		elsif (!grep(/100\% done/, @$vmkfstools_output)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to copy virtual disk, output does not contain '100% done', command: $vmkfstools_command, output:\n" . join("\n", @$vmkfstools_output));
-			return;
-		}
-		else {
-			$end_time = time;
-			$success = 1;
-			notify($ERRORS{'OK'}, 0, "copied virtual disk by executing 'vmkfstools' on VM host: '$source_path' --> '$destination_path'");
-		}
-	}
-	
-	my $duration_seconds = ($end_time - $start_time);
-	my $minutes = ($duration_seconds / 60);
-	$minutes =~ s/\..*//g;
-	my $seconds = ($duration_seconds - ($minutes * 60));
-	$seconds = "0$seconds" if length($seconds) == 1;
-	
-	my $search_path = $destination_path;
-	$search_path =~ s/\.vmdk$//g;
-	$search_path .= '*.vmdk';
-	my $image_size_bytes = $self->vmhost_os->get_file_size($search_path);
-	
-	my $bytes_per_second = ($image_size_bytes / $duration_seconds);
-	my $bits_per_second = ($image_size_bytes * 8 / $duration_seconds);
-	my $mb_per_second = ($image_size_bytes / $duration_seconds / 1024 / 1024);
-	my $mbit_per_second = ($image_size_bytes * 8 / $duration_seconds / 1024 / 1024);
-	my $gbyte_per_minute = ($image_size_bytes / $duration_seconds / 1024 / 1024 / 1024 * 60);
-	
-	notify($ERRORS{'OK'}, 0, "copied vmdk: '$source_path' --> '$destination_path'\n" .
-			 "total bytes: " . format_number($image_size_bytes) . "\n" .
-			 "time to copy: $minutes:$seconds (" . format_number($duration_seconds) . " seconds)\n" .
-			 "B/s: " . format_number($bytes_per_second) . "\n" .
-			 "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($gbyte_per_minute, 2));
-	return 1;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 get_network_names
 
  Parameters  : none

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=1005854&r1=1005853&r2=1005854&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 Oct  8 15:01:19 2010
@@ -187,6 +187,15 @@ our $VIX_API_PACKAGE = 'VCL::Module::Pro
 
 our $VIM_SSH_PACKAGE = 'VCL::Module::Provisioning::VMware::VIM_SSH';
 
+=head2 $VMWARE_CMD_PACKAGE
+
+ Data type   : string
+ Description : Perl package name for the vmware-cmd module.
+
+=cut
+
+our $VMWARE_CMD_PACKAGE = 'VCL::Module::Provisioning::VMware::vmware_cmd';
+
 ##############################################################################
 
 =head1 OBJECT METHODS
@@ -217,6 +226,18 @@ sub initialize {
 	my $vmhost_computer_name = $vmhost_data->get_computer_node_name() || return;
 	my $vm_computer_name = $self->data->get_computer_node_name() || return;
 	
+	# Make sure the VM and datastore paths are normalized - spaces not escaped
+	# The subroutines that use these paths expect this
+	my $vmprofile_vmpath = $self->data->get_vmhost_profile_vmpath();
+	if ($vmprofile_vmpath) {
+		$self->data->set_vmhost_profile_vmpath(normalize_file_path($vmprofile_vmpath));
+	}
+	
+	my $vmprofile_datastore_path = $self->data->get_vmhost_profile_datastore_path() || return;
+	if ($vmprofile_datastore_path) {
+		$self->data->set_vmhost_profile_datastore_path(normalize_file_path($vmprofile_datastore_path));
+	}
+	
 	my $vmware_api;
 	my $vmhost_os;
 	
@@ -264,9 +285,9 @@ sub initialize {
 		if ($vmware_api = $self->get_vmhost_api_object($VIM_SSH_PACKAGE)) {
 			notify($ERRORS{'DEBUG'}, 0, "VIM SSH command object will be used to control the VM: $vm_computer_name");
 		}
-		#elsif (($vmware_api = $self->get_vmhost_api_object($VIX_API_PACKAGE)) && !$vmware_api->is_restricted()) {
-		#	notify($ERRORS{'DEBUG'}, 0, "VIX API object will be used to control the VM: $vm_computer_name");
-		#}
+		elsif (($vmware_api = $self->get_vmhost_api_object($VMWARE_CMD_PACKAGE))) {
+			notify($ERRORS{'DEBUG'}, 0, "vmware_cmd object will be used to control the VM: $vm_computer_name");
+		}
 		else {
 			notify($ERRORS{'WARNING'}, 0, "failed to create an API object to control the VM: $vm_computer_name");
 			return;
@@ -547,21 +568,20 @@ sub capture {
 			}
 		}
 		
-		# Delete the vmdk directory on the VM host
-		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");
-			}
-		}
+		## Delete the vmdk directory on the VM host
+		#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
 	if ($self->api->vm_unregister($vmx_file_path_capture)) {
 		notify($ERRORS{'OK'}, 0, "unregistered the VM being captured: $vmx_file_path_capture");
@@ -1036,9 +1056,14 @@ sub get_vmhost_api_object {
 	my $api;
 	eval { $api = ($api_perl_package)->new({data_structure => $vmhost_datastructure, vmhost_os => $self->{vmhost_os}}) };
 	if (!$api) {
-		my $error = $EVAL_ERROR || 'no eval error';
-		notify($ERRORS{'WARNING'}, 0, "API object could not be created: $api_perl_package, $error");
-		return;
+		if ($EVAL_ERROR) {
+			notify($ERRORS{'WARNING'}, 0, "API object could not be created: $api_perl_package, error:\n$EVAL_ERROR");
+			return;
+		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "API object could not be created: $api_perl_package");
+			return;
+		}
 	}
 	
 	$api->{api} = $api;
@@ -1067,6 +1092,8 @@ sub remove_existing_vms {
 	}
 	
 	my $computer_name = $self->data->get_computer_short_name() || return;
+	my $vmx_base_directory_path = $self->get_vmx_base_directory_path();
+	my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path();
 	
 	# 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
@@ -1090,7 +1117,6 @@ sub remove_existing_vms {
 	}
 	
 	# 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;
@@ -1130,6 +1156,29 @@ sub remove_existing_vms {
 			next;
 		}
 	}
+	
+	# Delete orphaned vmx or vmdk directories previously created by VCL for the computer
+	# Find any files under the vmx or vmdk base directories matching the computer name
+	my @orphaned_paths = $self->vmhost_os->find_files($vmx_base_directory_path, "$computer_name*");
+	if ($vmx_base_directory_path ne $vmdk_base_directory_path) {
+		push @orphaned_paths, $self->vmhost_os->find_files($vmdk_base_directory_path, "$computer_name*");
+	}
+	my %unique_paths = map { $_ => 1 } (@orphaned_paths);
+	@orphaned_paths = sort keys(%unique_paths);
+	
+	# Check if any of the paths match the format of a directory VCL would have created for the computer
+	for my $orphaned_path (@orphaned_paths) {
+		if ($orphaned_path !~ /($vmx_base_directory_path|$vmdk_base_directory_path)\/$computer_name\_\d+-v\d+(_\d+)?$/i) {
+			notify($ERRORS{'DEBUG'}, 0, "ignoring path, it contains the computer name '$computer_name' but the directory name is not in the format VCL uses: '$orphaned_path'");
+			next;
+		}
+		
+		notify($ERRORS{'DEBUG'}, 0, "attempting to delete orphaned directory: '$orphaned_path'");
+		if (!$self->vmhost_os->delete_file($orphaned_path)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to delete orphaned directory: '$orphaned_path'");
+		}
+	}
+	
 	return 1;
 }
 
@@ -1176,6 +1225,7 @@ sub prepare_vmx {
 	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;
+	my $vmware_product_name      = $self->get_vmhost_product_name();
 	
 	## 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
@@ -1207,16 +1257,28 @@ sub prepare_vmx {
 	my $display_name;
 	my $vm_disk_mode;
 	my $vm_disk_write_through;
+	my $vm_disk_shared_bus;
 	if ($vm_persistent) {
 		$display_name = "$computer_name:$image_name (persistent)";
 		$vm_disk_mode = 'independent-persistent';
 		$vm_disk_write_through = "TRUE";
+		$vm_disk_shared_bus = "none";
 	}
 	else {
 		$display_name = "$computer_name:$image_name (nonpersistent)";
 		$vm_disk_mode = "independent-nonpersistent";
-		#$vm_disk_mode = "undoable";
 		$vm_disk_write_through = "FALSE";
+		$vm_disk_shared_bus = "none";
+	}
+	
+	# Determine which parameter to use in the vmx file for the network name
+	# VMware Server 1.x uses 'vnet', newer VMware products use 'networkName'
+	my $network_parameter;
+	if ($vmware_product_name =~ /VMware Server 1/i) {
+		$network_parameter = 'vnet';
+	}
+	else {
+		$network_parameter = 'networkName';
 	}
 	
 	notify($ERRORS{'DEBUG'}, 0, "vm info:
@@ -1265,17 +1327,19 @@ sub prepare_vmx {
 		
 		"displayName" => "$display_name",
 		
+		"ethernet0.connectionType" => "custom",
 		"ethernet0.address" => "$vm_eth0_mac",
 		"ethernet0.addressType" => "static",
 		"ethernet0.present" => "TRUE",
 		"ethernet0.virtualDev" => "$vm_ethernet_adapter_type",
-		"ethernet0.networkName" => "$virtual_switch_0",
+		"ethernet0.$network_parameter" => "$virtual_switch_0",
 		
+		"ethernet1.connectionType" => "custom",
 		"ethernet1.address" => "$vm_eth1_mac",
 		"ethernet1.addressType" => "static",
 		"ethernet1.present" => "TRUE",
 		"ethernet1.virtualDev" => "$vm_ethernet_adapter_type",
-		"ethernet1.networkName" => "$virtual_switch_1",
+		"ethernet1.$network_parameter" => "$virtual_switch_1",
 		
 		"floppy0.present" => "FALSE",
 		
@@ -1296,6 +1360,8 @@ sub prepare_vmx {
 		
 		"snapshot.disabled" => "TRUE",
 		
+		"svga.autodetect" => "TRUE",
+		
 		"tools.remindInstall" => "TRUE",
 		"tools.syncTime" => "FALSE",
 		
@@ -1316,6 +1382,7 @@ sub prepare_vmx {
 			"ide0:0.mode" => "$vm_disk_mode",
 			"ide0:0.present" => "TRUE",
 			"ide0:0.writeThrough" => "$vm_disk_write_through",
+			"ide0:0.sharedBus" => "$vm_disk_shared_bus",
 		));
 	}
 	else {
@@ -1326,6 +1393,7 @@ sub prepare_vmx {
 			"scsi0:0.mode" => "$vm_disk_mode",
 			"scsi0:0.present" => "TRUE",
 			"scsi0:0.writeThrough" => "$vm_disk_write_through",
+			"scsi0:0.sharedBus" => "$vm_disk_shared_bus",
 		));
 	}
 	
@@ -1349,7 +1417,7 @@ sub prepare_vmx {
 	}
 	
 	# Add additional Ethernet interfaces if the image project name is not vcl
-	if ($image_project !~ /^vcl$/i) {
+	if ($image_project !~ /^vcl$/i && self->api->can('get_network_names')) {
 		notify($ERRORS{'DEBUG'}, 0, "image project is: $image_project, checking if additional network adapters should be configured");
 		
 		# Get a list of all the network names configured on the VMware host
@@ -1371,7 +1439,7 @@ sub prepare_vmx {
 				$vmx_parameters{"ethernet$interface_index.addressType"} = "generated";
 				$vmx_parameters{"ethernet$interface_index.present"} = "TRUE";
 				$vmx_parameters{"ethernet$interface_index.virtualDev"} = "$vm_ethernet_adapter_type";
-				$vmx_parameters{"ethernet$interface_index.networkName"} = "$network_name";
+				$vmx_parameters{"ethernet$interface_index.$network_parameter"} = "$network_name";
 				
 				$interface_index++;
 			}
@@ -1403,6 +1471,9 @@ sub prepare_vmx {
 		return;
 	}
 	
+	# The vmx file should be set to executable
+	chmod("0755", "/tmp/$vmx_file_name");
+	
 	# Copy the temporary vmx file the the VM host
 	$self->vmhost_os->copy_file_to($temp_vmx_file_path, $vmx_file_path) || return;
 	notify($ERRORS{'OK'}, 0, "created vmx file on VM host: $vmx_file_path");
@@ -1437,104 +1508,112 @@ sub prepare_vmdk {
 		return;
 	}
 	
+	my $host_vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
 	my $host_vmdk_directory_path = $self->get_vmdk_directory_path() || return;
 	my $host_vmdk_file_path = $self->get_vmdk_file_path() || return;
 	my $host_vmdk_file_path_nonpersistent = $self->get_vmdk_file_path_nonpersistent() || return;
+	my $host_vmdk_directory_path_nonpersistent = $self->get_vmdk_directory_path_nonpersistent() || return;
 	
-	my $repository_vmdk_directory_path = $self->get_repository_vmdk_directory_path() || return;
 	my $image_name = $self->data->get_image_name() || return;
+	my $vm_computer_name = $self->data->get_computer_short_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)) {
-		
-		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;
-			}
+	# Semaphores are created when exclusive access to a file/directory is needed to avoid conflicts
+	# A semaphore ID is a string identifying a semaphore object when created
+	# Only 1 process at a time may create a semaphore with a given ID - other processes must wait if they attempt to do so
+	# If the VM profile disk type is NOT network, include the VM host name in the semaphore ID
+	# This means exclusive access to a directory is only restricted to the same VM host
+	# If the disk type is network, multiple VM hosts may use the same directory so access should be restricted across hosts
+	my $vmdk_semaphore_id;
+	my $nonpersistent_vmdk_semaphore_id;
+	my $vmprofile_disk_type = $self->data->get_vmhost_profile_vmdisk();
+	if ($vmprofile_disk_type =~ /network/i) {
+		$vmdk_semaphore_id = $host_vmdk_directory_path;
+		$nonpersistent_vmdk_semaphore_id = $host_vmdk_directory_path_nonpersistent;
+	}
+	else {
+		$vmdk_semaphore_id = "$vmhost_hostname-$host_vmdk_directory_path";
+		$nonpersistent_vmdk_semaphore_id = "$vmhost_hostname-$host_vmdk_directory_path_nonpersistent";
+	}
+	
+	# Establish a semaphore for the nonpersistent vmdk directory before checking if it exists
+	# This causes this process to wait if another process is copying to the nonpersistent directory
+	# Wait a long time to create the semaphore in case another process is copying a large vmdk to the directory
+	my $vmdk_semaphore = $self->get_semaphore($nonpersistent_vmdk_semaphore_id, (60 * 20), 15) || return;
+	my $nonpersistent_vmdk_exists = $self->vmhost_os->file_exists($host_vmdk_file_path_nonpersistent);
+	
+	# Return 1 if the VM is not persistent and the nonpersistent vmdk already exists on the host
+	if ($nonpersistent_vmdk_exists && !$is_vm_persistent) {
+		notify($ERRORS{'DEBUG'}, 0, "VM is not persistent and nonpersistent vmdk file already exists on VM host $vmhost_hostname: $host_vmdk_file_path");
+		return 1;
+	}
+	
+	# VM is either:
+	#    -persistent
+	#        -persistent directory should be deleted if it already exists
+	#        -persistent directory should be created and vmdk files copied to it
+	#    -nonpersistent and the directory doesn't exist
+	#        -nonpersistent vmdk directory should be retrieved from the image repository
+	# Update the semaphore for exclusive access to the vmdk directory if this is not the same directory as the nonpersistent directory
+	# The original semaphore is automatically released when the variable is reassigned
+	if ($vmdk_semaphore_id ne $nonpersistent_vmdk_semaphore_id) {
+		$vmdk_semaphore = $self->get_semaphore($vmdk_semaphore_id, (60 * 1)) || return;
+	}
+	
+	# If the VM is persistent, check if the persistent vmdk already file exists on the host, delete it if necessary
+	if ($is_vm_persistent && $self->vmhost_os->file_exists($host_vmdk_directory_path)) {
+		notify($ERRORS{'WARNING'}, 0, "VM is persistent and persistent vmdk directory already exists on VM host $vmhost_hostname: $host_vmdk_directory_path, existing directory will be deleted");
+		if (!$self->vmhost_os->delete_file($host_vmdk_directory_path)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to delete existing persistent vmdk directory on VM host $vmhost_hostname: $host_vmdk_directory_path");
+			return;
+		}
+	}
+	
+	# Check if the VM is persistent, if so, attempt to copy files locally from the nonpersistent directory if they exist
+	if ($is_vm_persistent && $nonpersistent_vmdk_exists) {
+		notify($ERRORS{'DEBUG'}, 0, "VM is persistent and nonpersistent vmdk exists on the VM host $vmhost_hostname, attempting to make a copy");
+		if ($self->copy_vmdk($host_vmdk_file_path_nonpersistent, $host_vmdk_file_path)) {
+			notify($ERRORS{'OK'}, 0, "copied vmdk from nonpersistent to persistent directory on VM host $vmhost_hostname");
+			return 1;
 		}
 		else {
-			# vmdk file exists and not persistent
-			# No copying necessary, proceed to check the disk type
-			return $self->check_vmdk_disk_type();
+			notify($ERRORS{'WARNING'}, 0, "failed to copy vmdk from nonpersistent to persistent directory on VM host $vmhost_hostname");
+			return;
 		}
 	}
-	else {
-		notify($ERRORS{'DEBUG'}, 0, "vmdk file does NOT exist on VM host: $host_vmdk_file_path");
-	}
-	
-	## Figure out how much additional space is required for the vmdk 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
-	## The subroutine checks if the vmdk files already exist on the VM host
-	#my $vm_additional_vmdk_bytes_required = $self->get_vm_additional_vmdk_bytes_required();
-	#return if !defined($vm_additional_vmdk_bytes_required);
-	#
-	## Get the number of bytes available on the device where the base vmdk directory resides
-	#my $host_vmdk_bytes_available = $self->vmhost_os->get_available_space($self->get_vmdk_base_directory_path());
-	#return if !defined($host_vmdk_bytes_available);
-	#
-	## Check if there is enough space available for the VM's vmdk files
-	#if ($vm_additional_vmdk_bytes_required > $host_vmdk_bytes_available) {
-	#	my $vmdk_deficit_bytes = ($vm_additional_vmdk_bytes_required - $host_vmdk_bytes_available);
-	#	my $vmdk_deficit_mb = format_number($vmdk_deficit_bytes / 1024 / 1024);
-	#	notify($ERRORS{'WARNING'}, 0, "not enough space is available for the vmdk files on the VM host, deficit: $vmdk_deficit_bytes bytes ($vmdk_deficit_mb MB)");
-	#	return;
-	#}
-	#else {
-	#	notify($ERRORS{'DEBUG'}, 0, "enough space is available for the vmdk files on the VM host");
-	#}
 	
-	# Check if the VM is persistent, if so, attempt to copy files locally from the nonpersistent directory if they exist
-	if ($is_vm_persistent && $self->vmhost_os->file_exists($host_vmdk_file_path_nonpersistent)) {
-		# Attempt to use the API's copy_virtual_disk subroutine
-		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");
-			return $self->check_vmdk_disk_type();
+	# Check if the image repository is mounted on the VM host
+	# Copy vmdk files from mounted repository datastore if it's mounted
+	if ($self->is_repository_mounted_on_vmhost()) {
+		notify($ERRORS{'DEBUG'}, 0, "files will be copied from this image repository directory mounted on the VM host");
+		
+		# Check if the vmdk file exists in the mounted repository
+		my $repository_vmdk_file_path = $self->get_repository_vmdk_file_path();
+		if (!$self->vmhost_os->file_exists($repository_vmdk_file_path)) {
+			notify($ERRORS{'WARNING'}, 0, "vmdk file does not exist in image repository directory mounted on VM host $vmhost_hostname: $repository_vmdk_file_path");
+			return;
+		}
+		
+		# Attempt to copy the vmdk file from the mounted repository to the VM host datastore
+		if ($self->copy_vmdk($repository_vmdk_file_path, $host_vmdk_file_path)) {
+			notify($ERRORS{'OK'}, 0, "copied vmdk from image repository to VM host $vmhost_hostname");
+			return 1;
 		}
 		else {
-			# Unable to use the API's copy_virtual_disk subroutine, use VM host OS's copy_file subroutine
-			my $host_vmdk_directory_path_nonpersistent = $self->get_vmdk_directory_path_nonpersistent() || return;
-			
-			my $vmdk_file_prefix = $self->get_vmdk_file_prefix() || return;
-			
-			if (my @vmdk_nonpersistent_file_paths = $self->vmhost_os->find_files($host_vmdk_directory_path_nonpersistent, "$vmdk_file_prefix*.vmdk")) {
-				my $start_time = time;
-				
-				# Loop through the files, copy each file from the non-persistent directory to the persistent directory
-				for my $vmdk_nonpersistent_file_path (sort @vmdk_nonpersistent_file_paths) {
-					# Extract the file name from the path
-					my ($vmdk_copy_file_name) = $vmdk_nonpersistent_file_path =~ /([^\/]+)$/g;
-					
-					# Attempt to copy the file on the VM host
-					if (!$self->vmhost_os->copy_file($vmdk_nonpersistent_file_path, "$host_vmdk_directory_path/$vmdk_copy_file_name")) {
-						notify($ERRORS{'WARNING'}, 0, "failed to copy vmdk file from the non-persistent to the persistent directory on the VM host:\n'$vmdk_nonpersistent_file_path' --> '$host_vmdk_directory_path/$vmdk_copy_file_name'");
-						return;
-					}
-				}
-				
-				# All vmdk files were copied
-				my $duration = (time - $start_time);
-				notify($ERRORS{'OK'}, 0, "copied vmdk files from nonpersistent to persistent directory on VM host, took " . format_number($duration) . " seconds");
-				return $self->check_vmdk_disk_type();
-			}
-			else {
-				notify($ERRORS{'DEBUG'}, 0, "non-persistent set of vmdk files does not exist: '$host_vmdk_directory_path_nonpersistent'");
-			}
+			notify($ERRORS{'WARNING'}, 0, "failed to copy vmdk from image repository to VM host $vmhost_hostname");
+			return;
 		}
 	}
 	
-	# VM is either non-persistent or persistent and could not copy files from existing non-persistent directory
-	# Copy the vmdk files from the image repository to the vmdk directory
+	# Copy the vmdk files from the image repository on the management node to the vmdk directory
+	my $repository_vmdk_directory_path = $self->get_repository_vmdk_directory_path() || return;
 	my $start_time = time;
 	
 	# Find the vmdk file paths in the image repository directory
 	my @vmdk_repository_file_paths;
-	my $command = "find \"$repository_vmdk_directory_path\" -type f -iname \"*.vmdk\"";
+	my $command = "find \"$repository_vmdk_directory_path\" -type f -iname \"$image_name*.vmdk\"";
 	my ($exit_status, $output) = run_command($command, 1);
 	if (!defined($output)) {
 		notify($ERRORS{'WARNING'}, 0, "failed to run command to find files in image repository directory: '$repository_vmdk_directory_path', pattern: '*.vmdk', command:\n$command");
@@ -1565,31 +1644,73 @@ sub prepare_vmdk {
 	my $duration = (time - $start_time);
 	notify($ERRORS{'OK'}, 0, "copied vmdk files from management node image repository to the VM host, took " . format_number($duration) . " seconds");
 	
-	return $self->check_vmdk_disk_type();
+	# Check if the vmdk disk type is compatible with the VMware product installed on the host
+	return 1 if $self->is_vmdk_compatible();
+
+	# Disk type is not compatible with the VMware product installed on the host
+	# Attempt to make a copy - copy_vmdk should create a copy in a compatible format
+	# The destination copy is stored in a directory with the same name as the normal vmdk directory followed by a ~
+	# Once the copy is done, delete the original vmdk directory and rename the copied directory
+	my $vmdk_file_name = $self->get_vmdk_file_name();
+	my $temp_vmdk_file_path = "$host_vmdk_directory_path~/$vmdk_file_name";
+	notify($ERRORS{'DEBUG'}, 0, "attempting to copy the vmdk using a compatible disk type on VM host $vmhost_hostname: '$host_vmdk_file_path' --> '$temp_vmdk_file_path'");
+	
+	if (!$self->copy_vmdk($host_vmdk_file_path, $temp_vmdk_file_path)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to copy the vmdk using a compatible disk type on VM host $vmhost_hostname: '$host_vmdk_file_path' --> '$temp_vmdk_file_path'");
+		return;
+	}
+	
+	if (!$self->vmhost_os->delete_file($host_vmdk_directory_path)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to delete the directory containing the incompatible vmdk on VM host $vmhost_hostname: '$host_vmdk_directory_path'");
+		return;
+	}
+	
+	if (!$self->vmhost_os->move_file("$host_vmdk_directory_path~", $host_vmdk_directory_path)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to rename the directory containing the compatible vmdk on VM host $vmhost_hostname: '$host_vmdk_directory_path~' --> '$host_vmdk_directory_path'");
+		return;
+	}
+
+	## Figure out how much additional space is required for the vmdk 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
+	## The subroutine checks if the vmdk files already exist on the VM host
+	#my $vm_additional_vmdk_bytes_required = $self->get_vm_additional_vmdk_bytes_required();
+	#return if !defined($vm_additional_vmdk_bytes_required);
+	#
+	## Get the number of bytes available on the device where the base vmdk directory resides
+	#my $host_vmdk_bytes_available = $self->vmhost_os->get_available_space($self->get_vmdk_base_directory_path());
+	#return if !defined($host_vmdk_bytes_available);
+	#
+	## Check if there is enough space available for the VM's vmdk files
+	#if ($vm_additional_vmdk_bytes_required > $host_vmdk_bytes_available) {
+	#	my $vmdk_deficit_bytes = ($vm_additional_vmdk_bytes_required - $host_vmdk_bytes_available);
+	#	my $vmdk_deficit_mb = format_number($vmdk_deficit_bytes / 1024 / 1024);
+	#	notify($ERRORS{'WARNING'}, 0, "not enough space is available for the vmdk files on the VM host, deficit: $vmdk_deficit_bytes bytes ($vmdk_deficit_mb MB)");
+	#	return;
+	#}
+	#else {
+	#	notify($ERRORS{'DEBUG'}, 0, "enough space is available for the vmdk files on the VM host");
+	#}
+	
+	return 1;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 check_vmdk_disk_type
+=head2 is_vmdk_compatible
 
  Parameters  : none
  Returns     : boolean
  Description : Determines if the vmdk disk type is compatible with the VMware
                product being used on the VM host. This subroutine currently only
-               checks if ESX is being used and the vmdk disk type is flat. If
-               using ESX and the disk type is not flat, a copy of the vmdk is
-               created using the thin virtual disk type in the same directory as
-               the incompatible vmdk directory. The name of the copied vmdk file
-               is the same as the incompatible vmdk file with 'thin_' inserted
-               at the beginning. Example:
-               'vmwarewinxp-base1-v0.vmdk' --> 'thin_vmwarewinxp-base1-v0.vmdk'
-               
-               This subroutine returns true unless ESX is being used, the
-               virtual disk type is not flat, and a thin copy cannot be created.
+               checks if ESX is being used and the vmdk disk type is flat.
+					
+					Returns false if:
+               -VM host is using ESX
+					-vmdk disk type is not flat
 
 =cut
 
-sub check_vmdk_disk_type {
+sub is_vmdk_compatible {
 	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");
@@ -1598,71 +1719,29 @@ 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")) {
-		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because required subroutines are not implemented by the API object");
-		return 1;
-	}
 	
 	# Retrieve the VMware product name
 	my $vmware_product_name = $self->get_vmhost_product_name();
 	if (!$vmware_product_name) {
-		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because VMware product name could not be retrieved from the API object");
-		return 1;
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if vmdk is compatible with VM host, VMware product name could not be retrieved");
+		return;
 	}
 	
 	# Retrieve the virtual disk type from the API object
 	my $virtual_disk_type = $self->api->get_virtual_disk_type($vmdk_file_path);
 	if (!$virtual_disk_type) {
-		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because virtual disk type could not be retrieved from the API object");
-		return 1;
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if vmdk is compatible with VM host, vmdk disk type could not be retrieved");
+		return;
 	}
 	
-	if ($vmware_product_name =~ /esx/i) {
-		if ($virtual_disk_type !~ /flat/i) {
-			notify($ERRORS{'DEBUG'}, 0, "virtual disk type is not compatible with $vmware_product_name: $virtual_disk_type");
-			
-			my $vmdk_file_path = $self->get_vmdk_file_path() || return;
-			my $vmdk_directory_path = $self->get_vmdk_directory_path() || return;
-			my $vmdk_file_prefix = $self->get_vmdk_file_prefix() || return;
-			my $thin_vmdk_file_path = "$vmdk_directory_path/thin_$vmdk_file_prefix.vmdk";
-			
-			if ($self->vmhost_os->file_exists($thin_vmdk_file_path)) {
-				notify($ERRORS{'DEBUG'}, 0, "thin virtual disk already exists: $thin_vmdk_file_path");
-			}
-			else {
-				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')) {
-					notify($ERRORS{'DEBUG'}, 0, "created a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
-				}
-				else {
-					notify($ERRORS{'WARNING'}, 0, "failed to create a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
-					return;
-				}
-			}
-			
-			# Update this object to use the thin vmdk file path
-			if ($self->set_vmdk_file_path($thin_vmdk_file_path)) {
-				return 1;
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to update the VMware module object to use the thin virtual disk path");
-				return;
-			}
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "flat virtual disk ($virtual_disk_type) does not need to be converted for $vmware_product_name");
-			return 1;
-		}
+	if ($vmware_product_name =~ /esx/i && $virtual_disk_type !~ /flat/i) {
+		notify($ERRORS{'DEBUG'}, 0, "virtual disk type is not compatible with $vmware_product_name: $virtual_disk_type");
+		return 0;
 	}
 	else {
-		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because VMware product is not ESX: $vmware_product_name");
+		notify($ERRORS{'DEBUG'}, 0, "virtual disk type is compatible with $vmware_product_name: $virtual_disk_type");
 		return 1;
 	}
-	
-	return 1;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2519,6 +2598,9 @@ sub check_file_paths {
 	# Assemble a string of all of the components
 	my $check_paths_string;
 	
+	$check_paths_string .= "VM profile VM path:                '" . ($self->data->get_vmhost_profile_vmpath() || $undefined_string) . "'\n";
+	$check_paths_string .= "VM profile datastore path:         '" . ($self->data->get_vmhost_profile_datastore_path() || $undefined_string) . "'\n";
+	
 	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";
@@ -2784,7 +2866,7 @@ sub is_vm_registered {
 		}
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "VM is not registered: '$vmx_file_path', registered paths:\n" . join("\n", @registered_vmx_file_paths));
+	notify($ERRORS{'DEBUG'}, 0, "VM is not registered: '$vmx_file_path', registered paths:\n" . (join("\n", @registered_vmx_file_paths) || '<none>'));
 	return 0;
 }
 
@@ -2838,6 +2920,9 @@ sub get_image_size_bytes {
 	}
 	
 	my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
+	my $vmprofile_vmdisk = $self->data->get_vmhost_profile_vmdisk() || return;
+	my $management_node_hostname = $self->data->get_management_node_short_name() || 'management node';
+	my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
 	
 	# Attempt to get the image name argument
 	my $image_name = shift;
@@ -2845,59 +2930,88 @@ sub get_image_size_bytes {
 		$image_name = $self->data->get_image_name() || return;
 	}
 	
-	my $image_size_bytes;
+	my $image_size_bytes_repository;
+	my $image_size_bytes_datastore;
 	
 	# Try to retrieve the image size from the repository if localdisk is being used
-	if (my $repository_vmdk_base_directory_path = $self->get_repository_vmdk_base_directory_path()) {
-		
-		my $search_path = "$repository_vmdk_base_directory_path/$image_name/$image_name*.vmdk";
-		
-		notify($ERRORS{'DEBUG'}, 0, "checking size of image in image repository: $search_path");
-		
-		# Run du specifying image repository directory as an argument
-		my ($exit_status, $output) = run_command("du -bc $search_path", 1);
-		if (!defined($output)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to run command to determine size of image in image repository: $search_path");
-		}
-		elsif (grep(/no such file/i, @$output)) {
-			notify($ERRORS{'DEBUG'}, 0, "image does not exist in image repository");
-		}
-		elsif (grep(/du: /i, @$output)) {
-			notify($ERRORS{'WARNING'}, 0, "error occurred attempting to determine size of image in image repository: $search_path, output:\n" . join("\n", @$output));
+	if ($vmprofile_vmdisk eq 'localdisk') {
+		my $repository_vmdk_base_directory_path = $self->get_repository_vmdk_base_directory_path();
+		my $repository_search_path = "$repository_vmdk_base_directory_path/$image_name/$image_name*.vmdk";
+		
+		notify($ERRORS{'DEBUG'}, 0, "VM profile vmdisk is set to '$vmprofile_vmdisk', attempting to retrieve image size from image repository");
+		if ($self->is_repository_mounted_on_vmhost()) {
+			notify($ERRORS{'DEBUG'}, 0, "checking size of image in image repository mounted on VM host: $vmhost_hostname:$repository_vmdk_base_directory_path");
+			
+			# Get the size of the files on the VM host
+			$image_size_bytes_repository = $self->vmhost_os->get_file_size($repository_search_path);
 		}
-		elsif (my ($total_line) = grep(/total/, @$output)) {
-			($image_size_bytes) = $total_line =~ /(\d+)/;
-			if (defined($image_size_bytes)) {
-				notify($ERRORS{'DEBUG'}, 0, "retrieved size of image in image repository: $image_size_bytes");
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "checking size of image in image repository in management node: $management_node_hostname:$repository_vmdk_base_directory_path");
+			
+			# Run du on the mangement node
+			my $command = "du -bc $repository_search_path";
+			my ($exit_status, $output) = run_command($command, 1);
+			if (!defined($output)) {
+				notify($ERRORS{'WARNING'}, 0, "failed to run command on management node to determine size of image in image repository: $repository_search_path");
 			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to parse du output to determine size of vmdk directory in image repository: $search_path, output:\n" . join("\n", @$output));
+			elsif (grep(/no such file/i, @$output)) {
+				notify($ERRORS{'DEBUG'}, 0, "image '$image_name' does not exist in image repository, command:\n'$command'");
+			}
+			elsif (grep(/du: /i, @$output)) {
+				notify($ERRORS{'WARNING'}, 0, "error occurred attempting to determine size of image in image repository: $repository_search_path, output:\n" . join("\n", @$output));
+			}
+			elsif (my ($total_line) = grep(/total/, @$output)) {
+				($image_size_bytes_repository) = $total_line =~ /(\d+)/;
+				if (defined($image_size_bytes_repository)) {
+					notify($ERRORS{'DEBUG'}, 0, "retrieved size of image in image repository: " . format_number($image_size_bytes_repository));
+				}
+				else {
+					notify($ERRORS{'WARNING'}, 0, "failed to parse du output to determine size of vmdk directory in image repository: $repository_search_path, output:\n" . join("\n", @$output));
+				}
 			}
-		}
-		else {
-			notify($ERRORS{'WARNING'}, 0, "unable to locate 'total' line in du output while attempting to determine size of vmdk directory in image repository: $search_path, output:\n" . join("\n", @$output));
 		}
 	}
-	
-	# Unable to determine the image size from the image repository, attempt to retrieve size from VM host
-	if (!defined($image_size_bytes)) {
-		# Assemble a search path
-		my $vmdk_base_directory_path = $self->get_vmdk_base_directory_path() || return;
-		my $search_path = "$vmdk_base_directory_path/$image_name/$image_name*.vmdk";
-		
-		# Get the size of the files on the VM host
-		$image_size_bytes = $self->vmhost_os->get_file_size($search_path);
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "VM profile vmdisk is set to '$vmprofile_vmdisk', image size will not be retrieved from image repository");
 	}
 	
+	# Attempt to retrieve size from the datastore on the VM host whether or not the size was retrieved from the image repository
+	my $search_path_datastore = "$vmdk_base_directory_path/$image_name/$image_name*.vmdk";
+	$image_size_bytes_datastore = $self->vmhost_os->get_file_size($search_path_datastore);
+	if (defined($image_size_bytes_datastore)) {
+		notify($ERRORS{'DEBUG'}, 0, "retrieved the size of the image from the datastore on the VM host: " . format_number($image_size_bytes_datastore));
+	}
 	
-	if (!defined($image_size_bytes)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine the size of image in image repository or on VM host");
+	my $image_size_bytes;
+	if (!defined($image_size_bytes_repository) && !defined($image_size_bytes_datastore)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine the size of image in image repository or on the VM host");
 		return;
 	}
+	elsif (defined($image_size_bytes_repository) && defined($image_size_bytes_datastore)) {
+		notify($ERRORS{'DEBUG'}, 0, "image size retrieved from both the image repository and VM host datastore:\n" .
+				 "image repository: " . format_number($image_size_bytes_repository) . "\n" .
+				 "VM host datastore: " . format_number($image_size_bytes_datastore));
+		
+		if ($image_size_bytes_repository > $image_size_bytes_datastore) {
+			$image_size_bytes = $image_size_bytes_repository;
+		}
+		else {
+			$image_size_bytes = $image_size_bytes_datastore;
+		}
+	}
+	elsif (defined($image_size_bytes_repository)) {
+		$image_size_bytes = $image_size_bytes_repository;
+	}
+	else {
+		$image_size_bytes = $image_size_bytes_datastore;
+	}
 	
-	my $mb_used = format_number(($image_size_bytes / 1024 / 1024));
-	my $gb_used = format_number(($image_size_bytes / 1024 / 1024 / 1024), 2);
-	notify($ERRORS{'DEBUG'}, 0, "size of $image_name image: " . format_number($image_size_bytes) . " bytes ($mb_used MB, $gb_used GB)");
+	my $image_size_mb = format_number(($image_size_bytes / 1024 / 1024));
+	my $image_size_gb = format_number(($image_size_bytes / 1024 / 1024 / 1024), 2);
+	notify($ERRORS{'DEBUG'}, 0, "size of $image_name image:\n" .
+			 format_number($image_size_bytes) . " bytes\n" .
+			 "$image_size_mb MB\n" .
+			 "$image_size_gb GB");
 	return $image_size_bytes;
 }
 
@@ -2922,7 +3036,9 @@ sub does_image_exist {
 		return;
 	}
 	
+	my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
 	my $vmprofile_vmdisk = $self->data->get_vmhost_profile_vmdisk() || return;
+	my $management_node_hostname = $self->data->get_management_node_short_name() || 'management node';
 	
 	# Get the non-persistent vmdk file path used on the VM host
 	my $vmhost_vmdk_file_path_nonpersistent = $self->get_vmdk_file_path_nonpersistent();
@@ -2936,11 +3052,14 @@ sub does_image_exist {
 		notify($ERRORS{'OK'}, 0, "image exists in the non-persistent directory on the VM host: $vmhost_vmdk_file_path_nonpersistent");
 		return 1;
 	}
+	elsif ($vmprofile_vmdisk eq 'networkdisk') {
+		notify($ERRORS{'DEBUG'}, 0, "image does not exist in the non-persistent directory on the VM host, image repository will not be checked because VM profile vmdisk is '$vmprofile_vmdisk', returning false");
+		return 0;
+	}
 	else {
-		notify($ERRORS{'DEBUG'}, 0, "image does not exist in the non-persistent directory on the VM host, checking the image repository");
+		notify($ERRORS{'DEBUG'}, 0, "image does not exist in the non-persistent directory on the VM host, image repository will be checked because VM profile vmdisk is '$vmprofile_vmdisk'");
 	}
 	
-	
 	# Get the image repository file path
 	my $repository_vmdk_file_path = $self->get_repository_vmdk_file_path();
 	if (!$repository_vmdk_file_path) {
@@ -2948,24 +3067,43 @@ sub does_image_exist {
 		return;
 	}
 	
-	
-	# Remove any trailing slashes and separate the directory path and name pattern
-	$repository_vmdk_file_path =~ s/\/*$//g;
-	my ($directory_path, $name_pattern) = $repository_vmdk_file_path =~ /^(.*)\/([^\/]*)/g;
-	
-	# Check if the file exists
-	(my ($exit_status, $output) = run_command("find \"$directory_path\" -iname \"$name_pattern\"")) || return;
-	if (!grep(/find: /i, @$output) && grep(/$directory_path/i, @$output)) {
-		notify($ERRORS{'OK'}, 0, "image exists in the image repository: $repository_vmdk_file_path");
-		return 1;
-	}
-	elsif (grep(/find: /i, @$output) && !grep(/no such file/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine if file exists in repository: $repository_vmdk_file_path, output:\n" . join("\n", @$output));
-		return;
+	if ($self->is_repository_mounted_on_vmhost()) {
+		notify($ERRORS{'DEBUG'}, 0, "checking if vmdk file exists in image repository mounted on VM host: $vmhost_hostname:$repository_vmdk_file_path");
+		if ($self->vmhost_os->file_exists($repository_vmdk_file_path)) {
+			notify($ERRORS{'DEBUG'}, 0, "vmdk file exists in image repository mounted on VM host: $vmhost_hostname:$repository_vmdk_file_path");
+			return 1;
+		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "vmdk file does not exist in image repository mounted on VM host: $vmhost_hostname:$repository_vmdk_file_path");
+			return 0;
+		}
 	}
 	else {
-		notify($ERRORS{'DEBUG'}, 0, "image does not exist in image repository: $repository_vmdk_file_path");
-		return 0;
+		notify($ERRORS{'DEBUG'}, 0, "checking if vmdk file exists in image repository on managment node $management_node_hostname: $repository_vmdk_file_path");
+		
+		# Escape all spaces in the path
+		my $escaped_repository_vmdk_file_path = escape_file_path($repository_vmdk_file_path);
+		
+		# Check if the file or directory exists
+		# Do not enclose the path in quotes or else wildcards won't work
+		my $command = "stat $escaped_repository_vmdk_file_path";
+		my ($exit_status, $output) = run_command($command, 1);
+		if (!defined($output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to run command to determine if vmdk file exists on management node:\npath: '$repository_vmdk_file_path'\ncommand: '$command'");
+			return;
+		}
+		elsif (grep(/no such file/i, @$output)) {
+			notify($ERRORS{'DEBUG'}, 0, "vmdk file does not exist on management node: '$repository_vmdk_file_path'");
+			return 0;
+		}
+		elsif (grep(/^\s*Size:.*file$/i, @$output)) {
+			notify($ERRORS{'DEBUG'}, 0, "vmdk file exists on management node: '$repository_vmdk_file_path'");
+			return 1;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to determine if vmdk file exists on management node:\npath: '$repository_vmdk_file_path'\ncommand: '$command'\nexit status: $exit_status, output:\n" . join("\n", @$output));
+			return;
+		}
 	}
 }
 
@@ -3660,6 +3798,121 @@ sub get_vm_additional_vmx_bytes_required
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 copy_vmdk
+
+ Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path
+ Returns     : boolean
+ Description : Copies a vmdk. The full paths to the source and destination vmdk
+               paths are required.
+
+=cut
+
+sub copy_vmdk {
+	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 arguments
+	my ($source_vmdk_file_path, $destination_vmdk_file_path) = @_;
+	if (!$source_vmdk_file_path || !$destination_vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "source and destination vmdk file path arguments were not specified");
+		return;
+	}
+	
+	# Make sure the arguments end with .vmdk
+	if ($source_vmdk_file_path !~ /\.vmdk$/i || $destination_vmdk_file_path !~ /\.vmdk$/i) {
+		notify($ERRORS{'WARNING'}, 0, "source vmdk file path ($source_vmdk_file_path) and destination vmdk file path ($destination_vmdk_file_path) arguments do not end with .vmdk");
+		return;
+	}
+	
+	# Make sure the source vmdk file exists
+	if (!$self->vmhost_os->file_exists($source_vmdk_file_path)) {
+		notify($ERRORS{'WARNING'}, 0, "source vmdk file path does not exist: $source_vmdk_file_path");
+		return;
+	}
+	
+	# Make sure the destination vmdk file doesn't already exist
+	if ($self->vmhost_os->file_exists($destination_vmdk_file_path)) {
+		notify($ERRORS{'WARNING'}, 0, "destination vmdk file path already exists: $destination_vmdk_file_path");
+		return;
+	}
+	
+	# Get the destination parent directory path and create the directory
+	my ($destination_directory_path) = $destination_vmdk_file_path =~ /(.+)\/[^\/]+/;
+	if (!$self->vmhost_os->create_directory($destination_directory_path)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to copy vmdk, destination directory could not be created on the VM host: $destination_directory_path");
+		return;
+	}
+	
+	my $start_time = time;
+	
+	# Attempt to use the API's copy_virtual_disk subroutine
+	if ($self->api->can('copy_virtual_disk') && $self->api->copy_virtual_disk($source_vmdk_file_path, $destination_vmdk_file_path)) {
+		notify($ERRORS{'OK'}, 0, "copied vmdk using API's copy_virtual_disk subroutine");
+	}
+	else {
+		# Unable to use API's copy_virtual_disk subroutine, try running vmkfstools or vmware-vdiskmanager
+		my $command;
+		if ($self->get_vmhost_product_name() =~ /VMware Server 1/i) {
+			# Use vmware-vdiskmanager if the VM host is running VMware Server 1.x
+			# Disk type 1 is 2GB sparse
+			$command = "vmware-vdiskmanager -r \"$source_vmdk_file_path\" -t 1 \"$destination_vmdk_file_path\"";
+			notify($ERRORS{'DEBUG'}, 0, "attempting to copy virtual disk using vmware-vdiskmanager, disk type: 2gbsparse: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+		}
+		else {
+			# Use vmkfstools if the VM host is running anything else
+			$command = "vmkfstools -i \"$source_vmdk_file_path\" \"$destination_vmdk_file_path\" -d thin";
+			notify($ERRORS{'DEBUG'}, 0, "attempting to copy virtual disk using vmkfstools, disk type: thin: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+		}
+		
+		my ($exit_status, $output) = $self->vmhost_os->execute($command);
+		if (!defined($output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host: $command");
+			return;
+		}
+		elsif (!grep(/(100\% done|success)/, @$output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to copy virtual disk, output does not contain '100% done' or 'success', command: '$command', output:\n" . join("\n", @$output));
+			return;
+		}
+		else {
+			notify($ERRORS{'OK'}, 0, "copied virtual disk on VM host: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+		}
+	}
+	
+	# Calculate how long it took to copy
+	my $duration_seconds = (time - $start_time);
+	my $minutes = ($duration_seconds / 60);
+	$minutes =~ s/\..*//g;
+	my $seconds = ($duration_seconds - ($minutes * 60));
+	$seconds = "0$seconds" if length($seconds) == 1;
+	
+	# Get the size of the copied vmdk files
+	my $search_path = $destination_vmdk_file_path;
+	$search_path =~ s/\.vmdk$//g;
+	$search_path .= '*.vmdk';
+	my $image_size_bytes = $self->vmhost_os->get_file_size($search_path);
+	
+	my $bytes_per_second = ($image_size_bytes / $duration_seconds);
+	my $bits_per_second = ($image_size_bytes * 8 / $duration_seconds);
+	my $mb_per_second = ($image_size_bytes / $duration_seconds / 1024 / 1024);
+	my $mbit_per_second = ($image_size_bytes * 8 / $duration_seconds / 1024 / 1024);
+	my $gbyte_per_minute = ($image_size_bytes / $duration_seconds / 1024 / 1024 / 1024 * 60);
+	
+	notify($ERRORS{'OK'}, 0, "copied vmdk: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'\n" .
+		"bytes copied: " . format_number($image_size_bytes) . ", time to copy: $minutes:$seconds (" . format_number($duration_seconds) . " seconds)\n" .
+		"b/s:  " . format_number($bits_per_second) . "\n" .
+		"B/s:  " . format_number($bytes_per_second) . "\n" .
+		"Mb/s: " . format_number($mbit_per_second, 2) . "\n" .
+		"MB/s: " . format_number($mb_per_second, 2) . "\n" .
+		"GB/m: " . format_number($gbyte_per_minute, 2));
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 rename_vmdk
 
  Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path
@@ -4141,6 +4394,42 @@ sub post_maintenance_action {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 is_repository_mounted_on_vmhost
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Checks if the image repository specified for the VM host profile
+               is mounted on the VM host.
+
+=cut
+
+sub is_repository_mounted_on_vmhost {
+	my $self = shift;
+	if (ref($self) !~ /VCL::Module/) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $vmhost_hostname = $self->data->get_vmhost_hostname();
+	
+	my $repository_vmdk_base_directory_path = $self->get_repository_vmdk_base_directory_path();
+	if (!$repository_vmdk_base_directory_path) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if image repository is mounted on the VM host, repository vmdk base directory path could not be determined");
+		return;
+	}
+	
+	if ($self->vmhost_os->file_exists($repository_vmdk_base_directory_path)) {
+		notify($ERRORS{'DEBUG'}, 0, "image repository is mounted on VM host $vmhost_hostname: $repository_vmdk_base_directory_path");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "image repository is NOT mounted on VM host $vmhost_hostname: $repository_vmdk_base_directory_path");
+		return 0;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

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=1005854&r1=1005853&r2=1005854&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 Oct  8 15:01:19 2010
@@ -525,25 +525,7 @@ sub copy_virtual_disk {
 		return;
 	}
 	
-	my $end_time = time;
-	my $duration_seconds = ($end_time - $start_time);
-	my $minutes = ($duration_seconds / 60);
-	$minutes =~ s/\..*//g;
-	my $seconds = ($duration_seconds - ($minutes * 60));
-	my $bytes_per_second = ($source_file_size_bytes / $duration_seconds);
-	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 $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" .
-			 "time to copy: $minutes:$seconds (" . format_number($duration_seconds) . " seconds)\n" .
-			 "B/s: " . format_number($bytes_per_second) . "\n" .
-			 "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($gbyte_per_minute, 2));
+	notify($ERRORS{'OK'}, 0, "copied vmdk: '$source_path' --> '$destination_path'");
 	return 1;
 }
 
@@ -1626,7 +1608,7 @@ sub get_file_size {
 	
 	# Check if there are any keys in the file info hash - no keys indicates no files were found
 	if (!keys(%{$file_info})) {
-		notify($ERRORS{'WARNING'}, 0, "file does not exist on $computer_name: $file_path");
+		notify($ERRORS{'DEBUG'}, 0, "unable to determine size of file on $computer_name because it does not exist: $file_path");
 		return;
 	}
 	
@@ -1781,12 +1763,12 @@ sub initialize {
 		notify($ERRORS{'WARNING'}, 0, "VM host name could not be retrieved");
 		return;
 	}
-	elsif (!$vmhost_hostname) {
-		notify($ERRORS{'WARNING'}, 0, "VM host username is not configured in the database for the VM profile");
+	elsif (!$vmhost_username) {
+		notify($ERRORS{'DEBUG'}, 0, "unable to use vSphere SDK, VM host username is not configured in the database for the VM profile");
 		return;
 	}
 	elsif (!$vmhost_password) {
-		notify($ERRORS{'WARNING'}, 0, "VM host password is not configured in the database for the VM profile");
+		notify($ERRORS{'DEBUG'}, 0, "unable to use vSphere SDK, VM host password is not configured in the database for the VM profile");
 		return;
 	}
 	

Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm?rev=1005854&view=auto
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm (added)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm Fri Oct  8 15:01:19 2010
@@ -0,0 +1,677 @@
+#!/usr/bin/perl -w
+###############################################################################
+# $Id$
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+=head1 NAME
+
+VCL::Module::Provisioning::VMware::vmware_cmd;
+
+=head1 SYNOPSIS
+
+ my $vmhost_datastructure = $self->get_vmhost_datastructure();
+ my $vmware_cmd = VCL::Module::Provisioning::VMware::vmware_cmd->new({data_structure => $vmhost_datastructure});
+ my @registered_vms = $vmware_cmd->get_registered_vms();
+
+=head1 DESCRIPTION
+
+ This module provides support for VMs to be controlled using VMware Server 1.x's
+ vmware-cmd command via SSH.
+
+=cut
+
+##############################################################################
+package VCL::Module::Provisioning::VMware::vmware_cmd;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::Provisioning::VMware::VMware);
+
+# Specify the version of this module
+our $VERSION = '2.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+
+use VCL::utils;
+
+##############################################################################
+
+=head1 PRIVATE OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 initialize
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Initializes the vmware_cmd object by by checking if vmware-cmd is
+               available on the VM host.
+
+=cut
+
+sub initialize {
+	my $self = shift;
+	if (ref($self) !~ /VCL::Module/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $args  = shift;
+
+	# Check to make sure the VM host OS object is available
+	if (!defined $args->{vmhost_os}) {
+		notify($ERRORS{'WARNING'}, 0, "required 'vmhost_os' argument was not passed");
+		return;
+	}
+	elsif (ref $args->{vmhost_os} !~ /VCL::Module::OS/) {
+		notify($ERRORS{'CRITICAL'}, 0, "'vmhost_os' argument passed is not a reference to a VCL::Module::OS object, type: " . ref($args->{vmhost_os}));
+		return;
+	}
+
+	# Store a reference to the VM host OS object in this object
+	$self->{vmhost_os} = $args->{vmhost_os};
+	
+	# Check if vmware-cmd is available on the VM host
+	my $command = 'vmware-cmd';
+	my ($exit_status, $output) = $self->vmhost_os->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to determine if vmware-cmd is available on the VM host");
+		return;
+	}
+	elsif (grep(/not found/i, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "vmware-cmd is not available on the VM host, output:\n" . join("\n", @$output));
+		return;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "vmware-cmd is available on VM host");
+	}
+	
+	notify($ERRORS{'DEBUG'}, 0, ref($self) . " object initialized");
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _run_vmware_cmd
+
+ Parameters  : $vmware_cmd_arguments
+ Returns     : array ($exit_status, $output)
+ Description : Runs vmware-cmd on the VMware host.
+
+=cut
+
+sub _run_vmware_cmd {
+	my $self = shift;
+	if (ref($self) !~ /VCL::Module/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $vmware_cmd_arguments = shift;
+	if (!$vmware_cmd_arguments) {
+		notify($ERRORS{'WARNING'}, 0, "vmware-cmd arguments were not specified");
+		return;
+	}
+	
+	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
+	
+	my $command = "vmware-cmd $vmware_cmd_arguments";
+	
+	my ($exit_status, $output) = $self->vmhost_os->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run vmware-cmd on VM host $vmhost_computer_name: '$command'");
+	}
+	else {
+		#notify($ERRORS{'DEBUG'}, 0, "executed vmware-cmd on VM host $vmhost_computer_name: '$command'");
+		return ($exit_status, $output);
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _get_file_name
+
+ Parameters  : $file_path
+ Returns     : string
+ Description : Extracts the file name from a file path.
+
+=cut
+
+sub _get_file_name {
+	my $self = shift;
+	if (ref($self) !~ /VCL::Module/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $file_path = shift;
+	my ($file_name) = $file_path =~ /([^\/]+)$/;
+	return $file_name || $file_path;
+}
+
+##############################################################################
+
+=head1 API OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_registered_vms
+
+ Parameters  : none
+ Returns     : array
+ Description : Returns an array containing the vmx file paths of the VMs running
+               on the VM host.
+
+=cut
+
+sub get_registered_vms {
+	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;
+	}
+	
+	# Run 'vmware-cmd -l'
+	my $vmware_cmd_arguments = "-l";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	my @vmx_file_paths = grep(/^\//, @$output);
+	notify($ERRORS{'DEBUG'}, 0, "registered VMs found: " . scalar(@vmx_file_paths));
+	return @vmx_file_paths;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_vm_power_state
+
+ Parameters  : $vmx_file_path
+ Returns     : string
+ Description : Returns a string containing the power state of the VM indicated
+					by the vmx file path argument. The string returned may be one of
+					the following values:
+					on
+					off
+					suspended
+
+=cut
+
+sub get_vm_power_state {
+	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 file path argument
+	my $vmx_file_path = shift;
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	my $vmx_file_name = $self->_get_file_name($vmx_file_path);
+	
+	# Run 'vmware-cmd <cfg> getstate'
+	my $vmware_cmd_arguments = "\"$vmx_file_path\" getstate";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	# The output should look like this:
+	# getstate() = off
+	
+	my $vm_power_state;
+	if (grep(/=\s*on/i, @$output)) {
+		$vm_power_state = 'on';
+	}
+	elsif (grep(/=\s*off/i, @$output)) {
+		$vm_power_state = 'off';
+	}
+	elsif (grep(/=\s*suspended/i, @$output)) {
+		$vm_power_state = 'suspended';
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to determine power state of '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments' output:\n" . join("\n", @$output));
+		return;
+	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "power state of VM '$vmx_file_name': $vm_power_state");
+	return $vm_power_state;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 vm_power_on
+
+ Parameters  : $vmx_file_path
+ Returns     : boolean
+ Description : Powers on the VM indicated by the vmx file path argument.
+
+=cut
+
+sub vm_power_on {
+	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 file path argument
+	my $vmx_file_path = shift;
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	my $vmx_file_name = $self->_get_file_name($vmx_file_path);
+	
+	my $vmware_cmd_arguments = "\"$vmx_file_path\" start";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	# Expected output if the VM was not previously powered on:
+	# start() = 1
+	
+	# Expected output if the VM was previously powered on:
+	# VMControl error -8: Invalid operation for virtual machine's current state:
+	# The requested operation ("start") could not be completed because it
+	# conflicted with the state of the virtual machine ("on") at the time the
+	# request was received. This error often occurs because the state of the
+	# virtual machine changed before it received the request.
+	
+	# Expected output if the VM is not registered: /usr/bin/vmware-cmd: Could not
+	# connect to VM /var/lib/vmware/Virtual Machines/Windows XP
+	# Professional/Windows XP Professional.vmx
+	#  (VMControl error -11: No such virtual machine: The config file
+	#  /var/lib/vmware/Virtual Machines/Windows XP Professional/Windows XP
+	#  Professional.vmx is not registered.
+	# Please register the config file on the server. For example: vmware-cmd -s
+	# register "/var/lib/vmware/Virtual Machines/Windows XP Professional/Windows
+	# XP Professional.vmx")
+	
+	if (grep(/\(\"on\"\)/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "VM is already powered on: '$vmx_file_name'");
+		return 1;
+	}
+	elsif (grep(/=\s*1/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "powered on VM: '$vmx_file_name'");
+		return 1;
+	}
+	elsif (grep(/error -11/i, @$output)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to power on VM because it is not registered: '$vmx_file_path'");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power on VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 vm_power_off
+
+ Parameters  : $vmx_file_path
+ Returns     : boolean
+ Description : Powers off the VM indicated by the vmx file path argument.
+
+=cut
+
+sub vm_power_off {
+	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 file path argument
+	my $vmx_file_path = shift;
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	my $vmx_file_name = $self->_get_file_name($vmx_file_path);
+	
+	my $vmware_cmd_arguments = "\"$vmx_file_path\" stop hard";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	# Expected output if the VM was not previously powered on:
+	# stop(hard) = 1
+	
+	# Expected output if the VM was previously powered on: VMControl error -8:
+	# Invalid operation for virtual machine's current state: The requested
+	# operation ("stop") could not be completed because it conflicted with the
+	# state of the virtual machine ("off") at the time the request was received.
+	# This error often occurs because the state of the virtual machine changed
+	# before it received the request.
+	
+	# Expected output if the VM is not registered: /usr/bin/vmware-cmd: Could not
+	# connect to VM /var/lib/vmware/Virtual Machines/Windows XP
+	# Professional/Windows XP Professional.vmx
+	#  (VMControl error -11: No such virtual machine: The config file
+	#  /var/lib/vmware/Virtual Machines/Windows XP Professional/Windows XP
+	#  Professional.vmx is not registered.
+	# Please register the config file on the server. For example: vmware-cmd -s
+	# register "/var/lib/vmware/Virtual Machines/Windows XP Professional/Windows
+	# XP Professional.vmx")
+	
+	if (grep(/\(\"off\"\)/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "VM is already powered off: '$vmx_file_name'");
+		return 1;
+	}
+	elsif (grep(/=\s*1/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "powered off VM: '$vmx_file_name'");
+		return 1;
+	}
+	elsif (grep(/error -11/i, @$output)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to power off VM because it is not registered: '$vmx_file_path'");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power off VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 vm_register
+
+ Parameters  : $vmx_file_path
+ Returns     : boolean
+ Description : Registers the VM indicated by the vmx file path argument.
+
+=cut
+
+sub vm_register {
+	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 file path argument
+	my $vmx_file_path = shift;
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	my $vmx_file_name = $self->_get_file_name($vmx_file_path);
+	
+	my $vmware_cmd_arguments = "-s register \"$vmx_file_path\"";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	# Expected output if the VM is already registered:
+	# VMControl error -20: Virtual machine already exists
+	
+	# Expected output if the VM is successfully registered:
+	# register(<vmx path>) = 1
+	
+	if (grep(/error -20/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "VM is already registered: '$vmx_file_name'");
+		return 1;
+	}
+	elsif (grep(/=\s*1/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "registered VM: '$vmx_file_name'");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to register VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 vm_unregister
+
+ Parameters  : $vmx_file_path
+ Returns     : boolean
+ Description : Unregisters the VM indicated by the vmx file path argument.
+
+=cut
+
+sub vm_unregister {
+	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 file path argument
+	my $vmx_file_path = shift;
+	if (!$vmx_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
+		return;
+	}
+	my $vmx_file_name = $self->_get_file_name($vmx_file_path);
+	
+	# Check if the VM is not registered
+	if (!$self->is_vm_registered($vmx_file_path)) {
+		notify($ERRORS{'OK'}, 0, "VM not unregistered because it is not registered: '$vmx_file_name'");
+		return 1;
+	}
+	
+	# Power off the VM if it is on
+	my $vm_power_state = $self->get_vm_power_state($vmx_file_path) || '';
+	if ($vm_power_state =~ /on/i && !$self->vm_power_off($vmx_file_path)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to power off VM before unregistering it: '$vmx_file_name', VM power state: $vm_power_state");
+		return;
+	}
+	
+	my $vmware_cmd_arguments = "-s unregister \"$vmx_file_path\"";
+	my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
+	return if !$output;
+	
+	# Expected output if the VM is not registered:
+	# VMControl error -11: No such virtual machine
+	
+	# Expected output if the VM is successfully unregistered:
+	# unregister(<vmx path>) = 1
+	
+	if (grep(/error -11/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "VM is not registered: '$vmx_file_name'");
+	}
+	elsif (grep(/=\s*1/i, @$output)) {
+		notify($ERRORS{'OK'}, 0, "unregistered VM: '$vmx_file_name'");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to unregister VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
+		return;
+	}
+	
+	# Make sure the VM is not registered
+	if ($self->is_vm_registered($vmx_file_path)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to unregister VM, it appears to still be registered: '$vmx_file_path'");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_virtual_disk_controller_type
+
+ Parameters  : $vmdk_file_path
+ Returns     : 
+ Description : Retrieves the disk controller type configured for the virtual
+					disk specified by the vmdk file path argument. A string is
+					returned containing one of the following values:
+               -ide
+					-buslogic
+					-lsilogic
+
+=cut
+
+sub get_virtual_disk_controller_type {
+	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 vmdk file path argument
+	my $vmdk_file_path = shift;
+	if (!$vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
+		return;
+	}
+	my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
+	
+	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
+	
+	my $command = "grep -i adapterType \"$vmdk_file_path\"";
+	my ($exit_status, $output) = $self->vmhost_os->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
+	}
+	
+	my ($adapter_type) = "@$output" =~ /adapterType\s*=\s*\"(\w+)\"/i;
+	
+	if ($adapter_type) {
+		notify($ERRORS{'DEBUG'}, 0, "adapter type configured in '$vmdk_file_name': $adapter_type");
+		return $adapter_type;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine adapter type configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_virtual_disk_type
+
+ Parameters  : $vmdk_file_path
+ Returns     : 
+ Description : Retrieves the disk type configured for the virtual
+					disk specified by the vmdk file path argument. A string is
+					returned containing one of the following values:
+               -monolithicSparse
+					-twoGbMaxExtentSparse
+					-monolithicFlat
+					-twoGbMaxExtentFlat
+
+=cut
+
+sub get_virtual_disk_type {
+	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 vmdk file path argument
+	my $vmdk_file_path = shift;
+	if (!$vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
+		return;
+	}
+	my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
+	
+	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
+	
+	my $command = "grep -i createType \"$vmdk_file_path\"";
+	my ($exit_status, $output) = $self->vmhost_os->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
+	}
+	
+	my ($disk_type) = "@$output" =~ /createType\s*=\s*\"(\w+)\"/i;
+	
+	if ($disk_type) {
+		notify($ERRORS{'DEBUG'}, 0, "disk type configured in '$vmdk_file_name': $disk_type");
+		return $disk_type;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine disk type configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_virtual_disk_hardware_version
+
+ Parameters  : $vmdk_file_path
+ Returns     : integer
+ Description : Retrieves the hardware version configured for the virtual
+					disk specified by the vmdk file path argument. False is returned
+					if the hardware version cannot be retrieved.
+
+=cut
+
+sub get_virtual_disk_hardware_version {
+	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 vmdk file path argument
+	my $vmdk_file_path = shift;
+	if (!$vmdk_file_path) {
+		notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
+		return;
+	}
+	my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
+	
+	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
+	
+	my $command = "grep -i virtualHWVersion \"$vmdk_file_path\"";
+	my ($exit_status, $output) = $self->vmhost_os->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
+	}
+	
+	my ($hardware_version) = "@$output" =~ /virtualHWVersion\s*=\s*\"(\w+)\"/i;
+	
+	if (defined($hardware_version)) {
+		notify($ERRORS{'DEBUG'}, 0, "hardware version configured in '$vmdk_file_name': $hardware_version");
+		return $hardware_version;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine hardware version configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 SEE ALSO
+
+L<http://cwiki.apache.org/VCL/>
+
+=cut

Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id