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/07/21 22:41:33 UTC

svn commit: r966408 [2/2] - in /incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware: VIM_SSH.pm VIX_API.pm VMware.pm vSphere_SDK.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=966408&r1=966407&r2=966408&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 Wed Jul 21 20:41:33 2010
@@ -59,9 +59,6 @@ use File::Temp qw( tempfile );
 
 use VCL::utils;
 
-use VCL::Module::Provisioning::VMware::vSphere_SDK;
-use VCL::Module::Provisioning::VMware::VIX_API;
-
 ##############################################################################
 
 =head1 CLASS VARIABLES
@@ -71,8 +68,8 @@ use VCL::Module::Provisioning::VMware::V
 =head2 %VM_OS_CONFIGURATION
 
  Data type   : hash
- Description : Maps OS names to the appropriate guestOS and Ethernet virtualDev
-               values to be used in the vmx file.
+ Description : Maps OS names to the appropriate guestOS, Ethernet, and SCSI
+					virtualDev values to be used in the vmx file.
 
 =cut
 
@@ -81,69 +78,85 @@ our %VM_OS_CONFIGURATION = (
 	"linux-x86" => {
 		"guestOS" => "otherlinux",
 		"ethernet-virtualDev" => "vlance",
+		"scsi-virtualDev" => "busLogic",
 	},
 	"linux-x86_64" => {
 		"guestOS" => "otherlinux-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	# Windows configurations:
 	"xp-x86" => {
 		"guestOS" => "winXPPro",
 		"ethernet-virtualDev" => "vlance",
+		"scsi-virtualDev" => "busLogic",
 	},
 	"xp-x86_64" => {
 		"guestOS" => "winXPPro-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"vista-x86" => {
 		"guestOS" => "winvista",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"vista-x86_64" => {
 		"guestOS" => "winvista-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	}, 
 	"7-x86" => {
 		"guestOS" => "winvista",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"7-x86_64" => {
 		"guestOS" => "winvista-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	}, 
 	"2003-x86" => {
 		"guestOS" => "winNetEnterprise",
 		"ethernet-virtualDev" => "vlance",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"2003-x86_64" => {
 		"guestOS" => "winNetEnterprise-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"2008-x86" => {
 		"guestOS" => "winServer2008Enterprise-32",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	"2008-x86_64" => {
 		"guestOS" => "winServer2008Enterprise-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	# Default Windows configuration if Windows version isn't found above:
 	"windows-x86" => {
 		"guestOS" => "winXPPro",
 		"ethernet-virtualDev" => "vlance",
+		"scsi-virtualDev" => "busLogic",
 	},
 	"windows-x86_64" => {
 		"guestOS" => "winXPPro-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 	# Default configuration if OS is not Windows or Linux:
 	"default-x86" => {
 		"guestOS" => "other",
 		"ethernet-virtualDev" => "vlance",
+		"scsi-virtualDev" => "busLogic",
 	},
 	"default-x86_64" => {
 		"guestOS" => "other-64",
 		"ethernet-virtualDev" => "e1000",
+		"scsi-virtualDev" => "lsiLogic",
 	},
 );
 
@@ -165,6 +178,15 @@ our $VSPHERE_SDK_PACKAGE = 'VCL::Module:
 
 our $VIX_API_PACKAGE = 'VCL::Module::Provisioning::VMware::VIX_API';
 
+=head2 $VIM_SSH_PACKAGE
+
+ Data type   : string
+ Description : Perl package name for the VIM SSH command module.
+
+=cut
+
+our $VIM_SSH_PACKAGE = 'VCL::Module::Provisioning::VMware::VIM_SSH';
+
 ##############################################################################
 
 =head1 OBJECT METHODS
@@ -199,46 +221,59 @@ sub initialize {
 	my $vmhost_os;
 	
 	# Create an API object which will be used to control the VM (register, power on, etc.)
-	if (($vmware_api = $self->get_vsphere_sdk_object()) && !$vmware_api->is_restricted()) {
-		notify($ERRORS{'DEBUG'}, 0, "vSphere SDK object will be used to control the VM: $vm_computer_name, and to control the OS of the VM host: $vmhost_computer_name");
-		$vmhost_os = $vmware_api;
-	}
-	elsif (($vmware_api = $self->get_vix_api_object()) && !$vmware_api->is_restricted()) {
-		notify($ERRORS{'DEBUG'}, 0, "VIX API object will be used to control the VM: $vm_computer_name");
-	}
-	# Add code here to create an API object to control free ESXi via SSH once the utility module has been implemented
-	# elsif (...) {
-	# }
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to create an API object to control the VM: $vm_computer_name");
-		return;
+	if ($vmware_api = $self->get_vmhost_api_object($VSPHERE_SDK_PACKAGE)) {
+		if ($vmware_api->is_restricted()) {
+			undef $vmware_api;
+		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "vSphere SDK object will be used to control the VM: $vm_computer_name, and to control the OS of the VM host: $vmhost_computer_name");
+			$vmhost_os = $vmware_api;
+		}
 	}
 	
-	# Create a VM host OS object if the vSphere SDK can't be used to control the VM host OS
 	if (!$vmhost_os) {
+		# vSphere SDK is not available, SSH access to the VM host is required
 		# Get a DataStructure object containing the VM host's data and get the VM host OS module Perl package name
 		my $vmhost_image_name = $vmhost_data->get_image_name();
 		my $vmhost_os_module_package = $vmhost_data->get_image_os_module_perl_package();
 		
 		notify($ERRORS{'DEBUG'}, 0, "attempting to create OS object for the image currently loaded on the VM host: $vmhost_computer_name\nimage name: $vmhost_image_name\nOS module: $vmhost_os_module_package");
-		
 		if ($vmhost_os = $self->get_vmhost_os_object($vmhost_os_module_package)) {
-			if ($vmhost_os->is_ssh_responding()) {
-				notify($ERRORS{'DEBUG'}, 0, "OS of VM host $vmhost_computer_name will be controlled via SSH using OS object: " . ref($vmhost_os));
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "unable to control OS of VM host $vmhost_computer_name using OS object: " . ref($vmhost_os) . ", VM host is not responding to SSH");
-				return;
-			}
+			notify($ERRORS{'DEBUG'}, 0, "created OS object to control the OS of VM host: $vmhost_computer_name");
 		}
 		else {
 			notify($ERRORS{'WARNING'}, 0, "failed to create OS object to control the OS of VM host: $vmhost_computer_name");
 			return;
 		}
+		
+		# Check if SSH is responding
+		if ($vmhost_os->is_ssh_responding()) {
+			notify($ERRORS{'DEBUG'}, 0, "OS of VM host $vmhost_computer_name will be controlled via SSH using OS object: " . ref($vmhost_os));
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "unable to control OS of VM host $vmhost_computer_name using OS object: " . ref($vmhost_os) . ", VM host is not responding to SSH");
+			return;
+		}
 	}
 	
-	# Store the VM host and API objects in this object
+	# Store the VM host OS object in this object
 	$self->{vmhost_os} = $vmhost_os;
+	
+	
+	if (!$vmware_api) {
+		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");
+		#}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to create an API object to control the VM: $vm_computer_name");
+			return;
+		}
+	}
+	
+	# Store the VM host API object in this object
 	$self->{api} = $vmware_api;
 	
 	# Make sure the vmx and vmdk base directories can be accessed
@@ -623,6 +658,12 @@ sub vmhost_os {
 		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
 		return;
 	}
+	
+	if (!$self->{vmhost_os}) {
+		notify($ERRORS{'WARNING'}, 0, "VM host OS object is not defined");
+		return;
+	}
+	
 	return $self->{vmhost_os};
 }
 
@@ -679,15 +720,26 @@ sub get_vmhost_datastructure {
 	my $vmhost_profile_image_id = $self->data->get_vmhost_profile_image_id() || return;
 	
 	# Create a DataStructure object containing computer data for the VM host
-	my $vmhost_data = new VCL::DataStructure({request_data => $request_data,
+	my $vmhost_data;
+	eval {
+		$vmhost_data= new VCL::DataStructure({request_data => $request_data,
 																		 reservation_id => $reservation_id,
 																		 computer_id => $vmhost_computer_id,
 																		 image_id => $vmhost_profile_image_id});
-	if (!$vmhost_data) {
-		notify($ERRORS{'WARNING'}, 0, "unable to create DataStructure object for VM host");
+	};
+	
+	if ($EVAL_ERROR) {
+		notify($ERRORS{'WARNING'}, 0, "unable to create DataStructure object for VM host, exception thrown, error: $EVAL_ERROR");
+		return;
+	}
+	
+	elsif (!$vmhost_data) {
+		notify($ERRORS{'WARNING'}, 0, "unable to create DataStructure object for VM host, DataStructure object is not defined");
 		return;
 	}
 	
+	notify($ERRORS{'OK'}, 0, "\$vmhost_data: $vmhost_data, ref(\$vmhost_data): " . ref($vmhost_data));
+	
 	# Get the VM host nodename from the DataStructure object which was created for it
 	# This acts as a test to make sure the DataStructure object is working
 	my $vmhost_computer_node_name = $vmhost_data->get_computer_node_name();
@@ -766,61 +818,25 @@ sub get_vmhost_os_object {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_vsphere_sdk_object
+=head2 get_vmhost_api_object
 
  Parameters  : none
- Returns     : vSphere SDK object
- Description : Creates and returns a vSphere SDK object which can be used to
-               control VMs on a VM host.
+ Returns     : VMware API object
+ Description : 
 
 =cut
 
-sub get_vsphere_sdk_object {
+sub get_vmhost_api_object {
 	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 a DataStructure object containing the VM host's data
-	my $vmhost_datastructure = $self->get_vmhost_datastructure() || return;
-	
-	# Get the VM host nodename from the DataStructure object which was created for it
-	# This acts as a test to make sure the DataStructure object is working
-	my $vmhost_nodename = $vmhost_datastructure->get_computer_node_name();
-	if (!$vmhost_nodename) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM host node name from DataStructure object created for VM host");
-		return;
-	}
-	
-	# Create a vSphere SDK object
-	my $vsphere_sdk;
-	eval { $vsphere_sdk = VCL::Module::Provisioning::VMware::vSphere_SDK->new({data_structure => $vmhost_datastructure}) };
-	if (!$vsphere_sdk) {
-		my $error = $EVAL_ERROR || 'no eval error';
-		notify($ERRORS{'WARNING'}, 0, "vSphere SDK object could not be created, VM host: $vmhost_nodename, $error");
-		return;
-	}
-	
-	notify($ERRORS{'DEBUG'}, 0, "created vSphere SDK object, VM host: $vmhost_nodename");
-	return $vsphere_sdk;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 get_vix_api_object
-
- Parameters  : none
- Returns     : VIX API object reference
- Description : Creates and returns a VMware VIX API object which may be used to
-               control the VMs on a VM host.
-
-=cut
-
-sub get_vix_api_object {
-	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");
+	# Get the Perl package argument
+	my $api_perl_package = shift;
+	if (!$api_perl_package) {
+		notify($ERRORS{'WARNING'}, 0, "API Perl package argument was not specified");
 		return;
 	}
 	
@@ -835,17 +851,28 @@ sub get_vix_api_object {
 		return;
 	}
 	
-	# Create a VIX API object
-	my $vix_api;
-	eval { $vix_api = VCL::Module::Provisioning::VMware::VIX_API->new({data_structure => $vmhost_datastructure}) };
-	if (!$vix_api) {
+	# Load the VMware control module
+	notify($ERRORS{'DEBUG'}, 0, "attempting to load VMware control module: $api_perl_package");
+	eval "use $api_perl_package";
+	if ($EVAL_ERROR) {
+		notify($ERRORS{'WARNING'}, 0, "failed to load VMware control module: $api_perl_package");
+		return 0;
+	}
+	notify($ERRORS{'DEBUG'}, 0, "loaded VMware control module: $api_perl_package");
+	
+	# Create an API object to control the VM host and VMs
+	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, "VIX API object could not be created, VM host: $vmhost_nodename, $error");
+		notify($ERRORS{'WARNING'}, 0, "API object could not be created: $api_perl_package, $error");
 		return;
 	}
 	
-	notify($ERRORS{'OK'}, 0, "created VIX API object, VM host: $vmhost_nodename");
-	return $vix_api;
+	$api->{api} = $api;
+	
+	notify($ERRORS{'DEBUG'}, 0, "created API object: $api_perl_package");
+	return $api;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -892,7 +919,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;
-
+	
 	## 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();
@@ -915,7 +942,10 @@ sub prepare_vmx {
 	# 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
 	my $host_vmx_info = $self->get_vmx_info();
+	
 	for my $host_vmx_path (keys %$host_vmx_info) {
+		notify($ERRORS{'DEBUG'}, 0, "checking existing vmx file on VM host: $host_vmx_path");
+		
 		my $host_vmx_computer_id = $host_vmx_info->{$host_vmx_path}{computer_id} || 'unknown';
 		
 		# If existing VM is for this computer, delete it
@@ -926,6 +956,9 @@ sub prepare_vmx {
 				return;
 			}
 		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "found vmx file on VM host with different computer id: $host_vmx_path\ncomputer id in file: $host_vmx_computer_id\nreservation computer id: $computer_id");
+		}
 	}
 	
 	# Get a list of the registered VMs
@@ -960,18 +993,20 @@ sub prepare_vmx {
 	my $vm_disk_mode;
 	my $vm_disk_write_through;
 	if ($vm_persistent) {
-		$display_name = "$computer_name (persistent: $image_name)";
+		$display_name = "$computer_name:$image_name (persistent)";
 		$vm_disk_mode = 'independent-persistent';
 		$vm_disk_write_through = "TRUE";
 	}
 	else {
-		$display_name = "$computer_name (nonpersistent: $image_name)";
+		$display_name = "$computer_name:$image_name (nonpersistent)";
 		$vm_disk_mode = "independent-nonpersistent";
 		#$vm_disk_mode = "undoable";
 		$vm_disk_write_through = "FALSE";
 	}
 	
 	notify($ERRORS{'DEBUG'}, 0, "vm info:
+			 display name: $display_name
+			 
 			 image ID: $image_id
 			 imagerevision ID: $imagerevision_id
 			 
@@ -1017,21 +1052,15 @@ sub prepare_vmx {
 		
 		"ethernet0.address" => "$vm_eth0_mac",
 		"ethernet0.addressType" => "static",
-		"ethernet0.allowGuestConnectionControl" => "FALSE",
-		"ethernet0.connectionType" => "custom",
 		"ethernet0.present" => "TRUE",
 		"ethernet0.virtualDev" => "$vm_ethernet_adapter_type",
-		"ethernet0.vnet" => "$virtual_switch_0",
-		"ethernet0.wakeOnPcktRcv" => "FALSE",
+		"ethernet0.networkName" => "$virtual_switch_0",
 		
 		"ethernet1.address" => "$vm_eth1_mac",
 		"ethernet1.addressType" => "static",
-		"ethernet1.allowGuestConnectionControl" => "FALSE",
-		"ethernet1.connectionType" => "custom",
 		"ethernet1.present" => "TRUE",
 		"ethernet1.virtualDev" => "$vm_ethernet_adapter_type",
-		"ethernet1.vnet" => "$virtual_switch_1",
-		"ethernet1.wakeOnPcktRcv" => "FALSE",
+		"ethernet1.networkName" => "$virtual_switch_1",
 		
 		"floppy0.present" => "FALSE",
 		
@@ -1136,12 +1165,14 @@ sub prepare_vmdk {
 	}
 	
 	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 $repository_vmdk_directory_path = $self->get_repository_vmdk_directory_path() || return;
 	my $image_name = $self->data->get_image_name() || return;
 	my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
 	
 	# Check if the first .vmdk file exists on the host
-	my $host_vmdk_file_path = $self->get_vmdk_file_path() || return;
 	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();
@@ -1173,30 +1204,39 @@ 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()) {
-		my $host_vmdk_directory_path_nonpersistent = $self->get_vmdk_directory_path_nonpersistent() || return;
 		
-		if (my @vmdk_nonpersistent_file_paths = $self->vmhost_os->find_files($host_vmdk_directory_path_nonpersistent, '*.vmdk')) {
-			my $start_time = time;
+		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();
+		}
+		else {
+			my $host_vmdk_directory_path_nonpersistent = $self->get_vmdk_directory_path_nonpersistent() || return;
 			
-			# 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;
+			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;
 				
-				# 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;
+				# 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'");
 			}
-			
-			# 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'");
 		}
 	}
 	
@@ -1252,9 +1292,9 @@ sub prepare_vmdk {
                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
-               before '.vmdk'. Example:
-               'vmwarewinxp-base1-v0.vmdk' --> 'vmwarewinxp-base1-v0-thin.vmdk'
+               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.
@@ -1271,20 +1311,20 @@ 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_vmware_product_name")
-			  && $self->api->can("get_virtual_disk_type")
-			  && $self->api->can("copy_virtual_disk")
-			  && $self->api->can("get_virtual_disk_controller_type")) {
+	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 and virtual disk type from the API object
-	my $vmware_product_name = $self->api->get_vmware_product_name();
+	# 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;
 	}
+	
+	# Retrieve the virtual disk type from the API object
 	my $virtual_disk_type = $self->api->get_virtual_disk_type($vmdk_file_path);
 	if (!$vmware_product_name) {
 		notify($ERRORS{'DEBUG'}, 0, "skipping vmdk disk type check because virtual disk type could not be retrieved from the API object");
@@ -1298,7 +1338,9 @@ sub check_vmdk_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/$vmdk_file_prefix-thin.vmdk";
+			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");
@@ -1306,15 +1348,8 @@ sub check_vmdk_disk_type {
 			else {
 				notify($ERRORS{'DEBUG'}, 0, "attempting to create a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
 				
-				# Get the controller type from the incompatible vmdk file, use it to create the copy
-				my $virtual_disk_controller_type = $self->api->get_virtual_disk_controller_type($vmdk_file_path);
-				if (!$virtual_disk_controller_type) {
-					notify($ERRORS{'WARNING'}, 0, "unable to create a copy of the virtual disk using the thin virtual disk type because the controller type used by the original vmdk file cannot be retrieved");
-					return;
-				}
-				
 				# Attempt to create a thin copy of the virtual disk
-				if ($self->api->copy_virtual_disk($vmdk_file_path, $thin_vmdk_file_path, $virtual_disk_controller_type, 'thin')) {
+				if ($self->api->copy_virtual_disk($vmdk_file_path, $thin_vmdk_file_path, 'thin', $vm_disk_adapter_type)) {
 					notify($ERRORS{'DEBUG'}, 0, "created a copy of the virtual disk using the thin virtual disk type: $thin_vmdk_file_path");
 				}
 				else {
@@ -1856,7 +1891,8 @@ sub get_vmdk_file_path {
  Returns     : string
  Description : Returns the image repository directory path on the management
                node under which the vmdk directories for all of the images
-               reside.  Example:
+               reside.  The preferred database value to use is vmprofile.repositorypath. If this is not available, managementnode.installpath is retrieved and "/vmware_images" is appended. If this is not available, "/install/vmware
+					Example:
                repository vmdk file path: /install/vmware_images/vmwarewinxp-base234-v12/vmwarewinxp-base234-v12.vmdk
                repository vmdk base directory path: /install/vmware_images
 					
@@ -1871,21 +1907,27 @@ sub get_repository_vmdk_base_directory_p
 	}
 	
 	# Return the path stored in this object if it has already been determined
-	return $self->{repository_base_directory} if (defined $self->{repository_base_directory});
+	return $self->{repository_base_directory_path} if (defined $self->{repository_base_directory_path});
+	
+	my $repository_vmdk_base_directory_path;
 	
-	my $repository_vmdk_base_directory;
-	if (my $management_node_install_path = $self->data->get_management_node_install_path()) {
-		$repository_vmdk_base_directory = "$management_node_install_path/vmware_images";
-		notify($ERRORS{'DEBUG'}, 0, "using managementnode installpath database value: $repository_vmdk_base_directory");
+	# Attempt the retrieve vmhost.repositorypath
+	if ($repository_vmdk_base_directory_path = $self->data->get_vmhost_profile_repository_path()) {
+		$repository_vmdk_base_directory_path = normalize_file_path($repository_vmdk_base_directory_path);
+		notify($ERRORS{'DEBUG'}, 0, "retrieved VM profile repository path: $repository_vmdk_base_directory_path");
+	}
+	elsif ($repository_vmdk_base_directory_path = $self->data->get_management_node_install_path()) {
+		$repository_vmdk_base_directory_path = normalize_file_path($repository_vmdk_base_directory_path) . "/vmware_images";
+		notify($ERRORS{'DEBUG'}, 0, "VM profile repository path is not set in the database, using management node install path: $repository_vmdk_base_directory_path");
 	}
 	else {
-		$repository_vmdk_base_directory = "install/vmware_images";
-		notify($ERRORS{'DEBUG'}, 0, "using hard-coded path: $repository_vmdk_base_directory");
+		$repository_vmdk_base_directory_path = '/install/vmware_images';
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve VM profile repository path or management node install path from the database, returning '/install/vmware_images'");
 	}
 	
-	# Set a value in this object so this doesn't have to be figured out more than once
-	$self->{repository_base_directory} = $repository_vmdk_base_directory;
-	return $repository_vmdk_base_directory;
+	# Set a value in this object so this doesn't have to be retrieved more than once
+	$self->{repository_base_directory_path} = $repository_vmdk_base_directory_path;
+	return $self->{repository_base_directory_path};
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2023,7 +2065,8 @@ sub get_image_size {
 	
 	my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
 	my $vmprofile_vmdisk = $self->data->get_vmhost_profile_vmdisk() || return;
-
+	my $image_name = $self->data->get_image_name() || return;
+	
 	# Attempt to get the vmdk file path argument
 	# If not supplied, use the default vmdk file path for this reservation
 	my $vmdk_file_path = shift;
@@ -2051,7 +2094,7 @@ sub get_image_size {
 				if ($bytes_used =~ /^\d+$/) {
 					my $mb_used = format_number(($bytes_used / 1024 / 1024), 1);
 					my $gb_used = format_number(($bytes_used / 1024 / 1024 / 1024), 2);
-					notify($ERRORS{'DEBUG'}, 0, "size of vmdk directory in image repository $repository_vmdk_directory_path: " . format_number($bytes_used) . " bytes ($mb_used MB, $gb_used GB)");
+					notify($ERRORS{'DEBUG'}, 0, "size of $image_name image in image repository: " . format_number($bytes_used) . " bytes ($mb_used MB, $gb_used GB)");
 					return $bytes_used;
 				}
 				else {
@@ -2086,7 +2129,7 @@ sub get_image_size {
 		return;
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "size of vmdk file on VM host $vmhost_hostname $vmdk_file_path: " . format_number($vmdk_size) . " bytes");
+	notify($ERRORS{'DEBUG'}, 0, "size of $image_name image on VM host $vmhost_hostname: " . format_number($vmdk_size) . " bytes");
 	return $vmdk_size;
 }
 
@@ -2171,15 +2214,18 @@ sub get_vmdk_parameter_value {
 		return;
 	}
 	
+	my $vmdk_file_path = $self->get_vmdk_file_path() || return;
 	my $image_repository_vmdk_file_path = $self->get_repository_vmdk_file_path() || return;
-	notify($ERRORS{'DEBUG'}, 0, "attempting to locate $vmdk_parameter value in $image_repository_vmdk_file_path");
 	
 	# Open the vmdk file for reading
-	if (open FILE, "<", $image_repository_vmdk_file_path) {
-		notify($ERRORS{'DEBUG'}, 0, "opened vmdk file for reading: $image_repository_vmdk_file_path");
+	if (open FILE, "<", $vmdk_file_path) {
+		notify($ERRORS{'DEBUG'}, 0, "attempting to locate $vmdk_parameter value in vmdk file: $vmdk_file_path");
+	}
+	elsif (open FILE, "<", $image_repository_vmdk_file_path) {
+		notify($ERRORS{'DEBUG'}, 0, "attempting to locate $vmdk_parameter value in vmdk file: $image_repository_vmdk_file_path");
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to open vmdk file for reading: $image_repository_vmdk_file_path");
+		notify($ERRORS{'WARNING'}, 0, "unable to open either vmdk file for reading: $vmdk_file_path, $image_repository_vmdk_file_path");
 		return;
 	}
 	
@@ -2239,11 +2285,34 @@ sub get_vm_disk_adapter_type {
 		return;
 	}
 	
+	my $vm_host_product_name = $self->get_vmhost_product_name() || return;
+	
+	my $vmdk_controller_type;
 	if ($self->api->can("get_virtual_disk_controller_type")) {
-		return $self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path());
+		$vmdk_controller_type = $self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path());
+		notify($ERRORS{'DEBUG'}, 0, "retrieved vm disk adapter type from api object: $vmdk_controller_type");
+	}
+	elsif ($vmdk_controller_type = $self->get_vmdk_parameter_value('adapterType')) {
+		notify($ERRORS{'DEBUG'}, 0, "retrieved vm disk adapter type from vmdk file: $vmdk_controller_type");
+	}
+	elsif (!$vmdk_controller_type || ($vm_host_product_name =~ /esx/i && $vmdk_controller_type =~ /ide/i)) {
+		
+		my $vm_os_configuration = $self->get_vm_os_configuration();
+		if (!$vm_os_configuration) {
+			notify($ERRORS{'WARNING'}, 0, "unable to determine vm disk adapter type because unable to retrieve default VM OS configuration");
+			return;
+		}
+		
+		$vmdk_controller_type = $vm_os_configuration->{"scsi-virtualDev"};
+	}
+	
+	if ($vmdk_controller_type) {
+		notify($ERRORS{'DEBUG'}, 0, "retrieved vm disk adapter type: $vmdk_controller_type");
+		return $vmdk_controller_type;
 	}
 	else {
-		return $self->get_vmdk_parameter_value('adapterType');
+		notify($ERRORS{'WARNING'}, 0, "unable to determine vm disk adapter type");
+		return;
 	}
 }
 
@@ -2550,10 +2619,12 @@ sub get_vmx_file_paths {
 		return;
 	}
 	
+	notify($ERRORS{'DEBUG'}, 0, "attempting to find existing vmx files on the VM host");
+	
 	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")) || return;
-	notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@vmx_paths) . " vmx files on VM host:\n" . join("\n", @vmx_paths));
+	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;
 }
 
@@ -3064,29 +3135,56 @@ sub rename_vmdk {
 	
 	# Check if the VM host OS object implements an execute subroutine and attempt to run vmware-vdiskmanager
 	if ($self->vmhost_os->can("execute")) {
-		notify($ERRORS{'OK'}, 0, "attempting to rename vmdk file using vmware-vdiskmanager: $source_vmdk_file_path --> $destination_vmdk_file_path");
-		
-		my $command = "vmware-vdiskmanager -n \"$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 execute 'vmware-vdiskmanager' command on VM host to rename vmdk file:\n$command");
+		# Try vmware-vdiskmanager
+		notify($ERRORS{'OK'}, 0, "attempting to rename vmdk file using vmware-vdiskmanager: $source_vmdk_file_path --> $destination_vmdk_file_path");
+		my $vdisk_command = "vmware-vdiskmanager -n \"$source_vmdk_file_path\" \"$destination_vmdk_file_path\"";
+		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 rename vmdk file:\n$vdisk_command");
 		}
-		elsif (grep(/success/i, @$output)) {
-			notify($ERRORS{'OK'}, 0, "renamed vmdk file by executing 'vmware-vdiskmanager' command on VM host:\ncommand: $command\noutput: " . join("\n", @$output));
+		elsif (grep(/success/i, @$vdisk_output)) {
+			notify($ERRORS{'OK'}, 0, "renamed vmdk file by executing 'vmware-vdiskmanager' command on VM host:\ncommand: $vdisk_command\noutput: " . join("\n", @$vdisk_output));
 			return 1;
 		}
-		elsif (grep(/command not found/i, @$output)) {
+		elsif (grep(/command not found/i, @$vdisk_output)) {
 			notify($ERRORS{'DEBUG'}, 0, "unable to rename vmdk using 'vmware-vdiskmanager' because the command is not available on VM host");
 		}
 		else {
-			notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware-vdiskmanager' command on VM host to rename vmdk file:\n$command\noutput:\n" . join("\n", @$output));
+			notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware-vdiskmanager' command on VM host to rename vmdk file:\n$vdisk_command\noutput:\n" . join("\n", @$vdisk_output));
+		}
+		
+		
+		# Try vmkfstools
+		notify($ERRORS{'OK'}, 0, "attempting to rename vmdk file using vmkfstools: $source_vmdk_file_path --> $destination_vmdk_file_path");
+		my $vmkfs_command = "vmkfstools -E \"$source_vmdk_file_path\" \"$destination_vmdk_file_path\"";
+		my ($vmkfs_exit_status, $vmkfs_output) = $self->vmhost_os->execute($vmkfs_command);
+		
+		# There is no output if the command succeeded
+		# Check to make sure the source file doesn't exist and the destination file does exist
+		if (!defined($vmkfs_output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmkfstools' command on VM host: $vmkfs_command");
+		}
+		elsif (grep(/command not found/i, @$vmkfs_output)) {
+			notify($ERRORS{'DEBUG'}, 0, "unable to rename vmdk using 'vmkfstools' because the command is not available on VM host");
+		}
+		elsif ($self->vmhost_os->file_exists($source_vmdk_file_path)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to rename vmdk file using vmkfstools, source file still exists: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+		}
+		elsif (!$self->vmhost_os->file_exists($destination_vmdk_file_path)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to rename vmdk file using vmkfstools, destination file does not exist: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+		}
+		else {
+			notify($ERRORS{'OK'}, 0, "rename vmdk file using vmkfstools: '$source_vmdk_file_path' --> '$destination_vmdk_file_path'");
+			return 1;
 		}
 	}
 	else {
-		notify($ERRORS{'DEBUG'}, 0, "unable to execute 'vmware-vdiskmanager' on VM host because 'execute' subroutine has not been implemented by the VM host OS: " . ref($self->vmhost_os));
+		notify($ERRORS{'DEBUG'}, 0, "unable to execute 'vmware-vdiskmanager' or 'vmkfstools' on VM host because 'execute' subroutine has not been implemented by the VM host OS: " . ref($self->vmhost_os));
 	}
 	
+	# Unable to rename vmdk file using any VMware utilities or APIs
+	# Attempt to manually rename the files
 	
 	# Determine the source vmdk directory path
 	my ($source_vmdk_directory_path) = $source_vmdk_file_path =~ /(.+)\/[^\/]+\.vmdk$/;
@@ -3238,6 +3336,47 @@ sub rename_vmdk {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 mount_repository_datastore
+
+ Parameters  : 
+ Returns     : boolean
+ Description : 
+
+=cut
+
+sub mount_repository_datastore {
+	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 $datastore_name = 'vcl-repository';
+	
+	my $management_node_short_name = $self->data->get_management_node_short_name();
+	if (!$management_node_short_name) {
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve management short name");
+		return;
+	}
+	
+	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 retrieve repository vmdk base directory path");
+		return;
+	}
+	
+	if ($self->api->can("create_nfs_datastore")) {
+		if ($self->api->create_nfs_datastore($datastore_name, '10.25.0.245', $repository_vmdk_base_directory_path)) {
+			notify($ERRORS{'OK'}, 0, "repository datastore mounted on VM host: $datastore_name");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "unable to mount repository datastore on VM host: $datastore_name");
+		}
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 power_on
 
  Parameters  : none
@@ -3321,6 +3460,55 @@ sub power_status {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_vmhost_product_name
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns a string containing the full VMware product name being
+               used on the VM host. 
+
+=cut
+
+sub get_vmhost_product_name {
+	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_computer_name = $self->data->get_vmhost_hostname() || return;
+	my $product_name;
+	
+	# Attempt to retrieve the product name using the API object
+	if ($self->api->can("get_vmware_product_name") && ($product_name = $self->api->get_vmware_product_name())) {
+		return $product_name;
+	}
+	
+	# Attempt to retrieve the product name by running 'vmware -v' on the VM host
+	elsif ($self->vmhost_os->can("execute")) {
+		my $command = "vmware -v";
+		my ($exit_status, $output) = $self->vmhost_os->execute($command);
+		if (!defined($output)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware -v' command on VM host $vmhost_computer_name to retrieve the VMware product name, command: $command");
+		}
+		elsif (my ($product_name) = grep(/vmware/i, @$output)) {
+			notify($ERRORS{'OK'}, 0, "VMware product being used on VM host $vmhost_computer_name: '$product_name'");
+			return $product_name;
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "failed to execute 'vmware -v' command on VM host $vmhost_computer_name to retrieve the VMware product name, command: $command\noutput:\n" . join("\n", @$output));
+		}
+	}
+	
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve VMware product name being used on VM host $vmhost_computer_name using the API or VM host OS object");
+	}
+	
+	return;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 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=966408&r1=966407&r2=966408&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 Wed Jul 21 20:41:33 2010
@@ -363,7 +363,7 @@ sub get_vm_power_state {
 
 =head2 copy_virtual_disk
 
- Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path, $adapter_type (optional), $disk_type (optional)
+ Parameters  : $source_vmdk_file_path, $destination_vmdk_file_path, $disk_type (optional), $adapter_type (optional)
  Returns     : boolean
  Description : Copies a virtual disk (set of vmdk files). This subroutine allows
                a virtual disk to be converted to a different disk type or
@@ -439,11 +439,11 @@ 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_disk_type = shift || 'sparseMonolithic';
 	
 	# Check the adapter type argument, the string must match exactly or the copy will fail
-	my @valid_adapter_types = qw( busLogic lsiLogic ide);
+	my @valid_adapter_types = qw( busLogic lsiLogic ide );
 	if (!grep(/^$destination_adapter_type$/, @valid_adapter_types)) {
 		notify($ERRORS{'WARNING'}, 0, "adapter type argument is not valid: '$destination_adapter_type', it must exactly match (case sensitive) one of the following strings:\n" . join("\n", @valid_adapter_types));
 		return;
@@ -494,7 +494,9 @@ sub copy_virtual_disk {
 	notify($ERRORS{'DEBUG'}, 0, "attempting to copy file: '$source_path' --> '$destination_path'
 			 adapter type: $source_adapter_type --> $destination_adapter_type
 			 disk type: $source_disk_type --> $destination_disk_type
-			 source file size: " . format_number($source_file_size_bytes));
+			 source file size: " . format_number($source_file_size_bytes) .
+			 "disk spec:\n" . format_data($virtual_disk_spec));
+	
 	my $start_time = time;
 	eval { $virtual_disk_manager->CopyVirtualDisk(sourceName => $source_path,
 																 destName => $destination_path,
@@ -737,6 +739,7 @@ sub create_nfs_datastore {
 	local $SIG{__DIE__} = sub{};
 	
 	# Attempt to cretae the NAS datastore
+	notify($ERRORS{'DEBUG'}, 0, "attempting to create NAS datastore:\n" . format_data($host_nas_volume_spec));
 	eval { $datastore_system->CreateNasDatastore(spec => $host_nas_volume_spec); };
 	if (my $fault = $@) {
 		notify($ERRORS{'WARNING'}, 0, "failed to create NAS datastore on VM host:\ndatastore name: $datastore_name\nremote host: $remote_host\nremote path: $remote_path\nerror:\n$@");
@@ -790,20 +793,23 @@ sub get_virtual_disk_controller_type {
 	}
 	
 	my $controller_type = $vmdk_file_info->{controllerType};
-	notify($ERRORS{'DEBUG'}, 0, "retrieved controllerType value from vmdk file info: $controller_type");
 	
+	my $return_controller_type;
 	if ($controller_type =~ /lsi/i) {
-		return 'lsiLogic';
+		$return_controller_type = 'lsiLogic';
 	}
 	elsif ($controller_type =~ /bus/i) {
-		return 'busLogic';
+		$return_controller_type = 'busLogic';
 	}
 	elsif ($controller_type =~ /ide/i) {
-		return 'ide';
+		$return_controller_type = 'ide';
 	}
 	else {
-		return $controller_type;
+		$return_controller_type = $controller_type;
 	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "retrieved controllerType value from vmdk file info: $return_controller_type($controller_type)");
+	return $return_controller_type;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -908,8 +914,10 @@ sub get_virtual_disk_hardware_version {
 
  Parameters  : none
  Returns     : string
- Description : Returns the VMware product name installed on the VM host.
-               Example: 'VMware ESXi'
+ Description : Returns the full VMware product name installed on the VM host.
+               Examples:
+					VMware Server 2.0.2 build-203138
+					VMware ESXi 4.0.0 build-208167
 
 =cut
 
@@ -926,15 +934,15 @@ sub get_vmware_product_name {
 	
 	# Get the host view
 	my $host_view = VIExt::get_host_view(1);
-	my $product_name = $host_view->config->product->name;
+	my $product_name = $host_view->config->product->fullName;
 	
 	if ($product_name) {
-		notify($ERRORS{'DEBUG'}, 0, "retrieved product name for VM host $computer_name: $product_name");
+		notify($ERRORS{'DEBUG'}, 0, "VMware product being used on VM host $computer_name: '$product_name'");
 		$self->{product_name} = $product_name;
 		return $self->{product_name};
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve product name for VM host $computer_name");
+		notify($ERRORS{'WARNING'}, 0, "unable to retrieve VMware product name being used on VM host $computer_name");
 		return;
 	}
 }
@@ -978,6 +986,36 @@ sub get_vmware_product_version {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_network_names
+
+ Parameters  : none
+ Returns     : array
+ Description : Retrieves the network names configured on the VM host.
+
+=cut
+
+sub get_network_names {
+	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 host view
+	my $host_view = VIExt::get_host_view(1);
+	
+	# Retrieve the network info, check if each network is accessible
+	my @network_names;
+	for my $network (@{Vim::get_views(mo_ref_array => $host_view->network)}) {
+		push @network_names, $network->name;
+	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "retrieved network names:\n" . join("\n", @network_names));
+	return @network_names;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 is_restricted
 
  Parameters  : none
@@ -1054,6 +1092,9 @@ sub create_directory {
 	# Get and check the directory path argument
 	my $directory_path = $self->get_datastore_path(shift) || return;
 	
+	# Check if the directory already exists
+	return 1 if $self->file_exists($directory_path);
+	
 	# Get the VM host name
 	my $computer_node_name = $self->data->get_computer_node_name() || return;
 	
@@ -1350,6 +1391,8 @@ sub get_file_contents {
 		return;
 	}
 	
+	# TODO: add file size check before retrieving file in case file is huge
+	
 	# Get the source and destination arguments
 	my ($path) = shift;
 	if (!$path) {
@@ -1472,6 +1515,7 @@ 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 =~ /^\[(.+)\]$/) {
@@ -1626,7 +1670,7 @@ sub find_files {
 	}
 	
 	@file_paths = sort @file_paths;
-	notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@file_paths) . " matching files");
+	notify($ERRORS{'DEBUG'}, 0, "matching file count: " . scalar(@file_paths));
 	return @file_paths;
 }