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 2017/06/12 16:33:35 UTC

svn commit: r1798487 [4/7] - in /vcl/trunk/managementnode/lib/VCL/Module: OS/ OS/Linux/ OS/Linux/firewall/ OS/Windows/ OS/Windows/Version_5/ OS/Windows/Version_6/ Predictive/ Provisioning/ Provisioning/VMware/

Modified: vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm?rev=1798487&r1=1798486&r2=1798487&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm Mon Jun 12 16:33:35 2017
@@ -1,4007 +1,4007 @@
-#!/usr/bin/perl -w
-###############################################################################
-# $Id: VIM_SSH.pm 952366 2010-06-07 18:59:25Z arkurth $
-###############################################################################
-# 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::VIM_SSH;
-
-=head1 SYNOPSIS
-
- my $vmhost_datastructure = $self->get_vmhost_datastructure();
- my $VIM_SSH = VCL::Module::Provisioning::VMware::VIM_SSH->new({data_structure => $vmhost_datastructure});
- my @registered_vms = $VIM_SSH->get_registered_vms();
-
-=head1 DESCRIPTION
-
- This module provides support for the vSphere SDK. The vSphere SDK can be used
- to manage VMware Server 2.x, ESX 3.0.x, ESX/ESXi 3.5, ESX/ESXi 4.0, vCenter
- Server 2.5, and vCenter Server 4.0.
-
-=cut
-
-###############################################################################
-package VCL::Module::Provisioning::VMware::VIM_SSH;
-
-# 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.4.2';
-
-# Specify the version of Perl to use
-use 5.008000;
-
-use strict;
-use warnings;
-use diagnostics;
-
-use English '-no_match_vars';
-use VCL::utils;
-
-###############################################################################
-
-=head1 PRIVATE OBJECT METHODS
-
-=cut
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 initialize
-
- Parameters  : none
- Returns     : boolean
- Description : Initializes the vSphere SDK object by establishing a connection
-               to 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;
-	
-	if (!defined($self->{vmhost_os})) {
-		# 
-		if (!defined $args->{vmhost_os}) {
-			notify($ERRORS{'WARNING'}, 0, "required 'vmhost_os' argument was not passed");
-			return;
-		}
-		
-		# 
-		if (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;
-		}
-	
-		# 
-		$self->{vmhost_os} = $args->{vmhost_os};
-	}
-	
-	if (!$self->vmhost_os) {
-		return;
-	}
-	
-	my @required_vmhost_os_subroutines = (
-		'execute',
-	);
-	
-	for my $required_vmhost_os_subroutine (@required_vmhost_os_subroutines) {
-		if (!$self->vmhost_os->can($required_vmhost_os_subroutine)) {
-			notify($ERRORS{'WARNING'}, 0, "required VM host OS subroutine is not implemented: $required_vmhost_os_subroutine");
-			return;
-		}
-	}
-	
-	# Determine which VIM executable is installed on the VM host
-	my $command = 'vim-cmd ; vmware-vim-cmd';
-	my ($exit_status, $output) = $self->vmhost_os->execute($command);
-	if (!defined($output)) {
-		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, "VIM executable is not available on the VM host, output:\n" . join("\n", @$output));
-		return;
-	}
-	elsif (grep(/: vim-cmd:.*not found/i, @$output)) {
-		# Output contains the line: 'vim-cmd: command not found'
-		$self->{vim_cmd} = 'vmware-vim-cmd';
-	}
-	else {
-		# Output contains the line: 'vmware-vim-cmd: command not found'
-		# Note: VMware ESX 4.1 has BOTH vim-cmd and vmware-vim-cmd
-		$self->{vim_cmd} = 'vim-cmd';
-	}
-	notify($ERRORS{'DEBUG'}, 0, "VIM executable available on VM host: $self->{vim_cmd}");
-	
-	notify($ERRORS{'DEBUG'}, 0, ref($self) . " object initialized");
-	return 1;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _run_vim_cmd
-
- Parameters  : $vim_arguments, $timeout_seconds (optional), $attempt_limit (optional)
- Returns     : array ($exit_status, $output)
- Description : Runs vim-cmd command on the VMware host. This was designed to
-               allow it to handle most of the error checking.
-               
-               By default, 5 attempts are made.
-               
-               If the exit status of the vim-cmd command is 0 after any attempt,
-               $exit_status and $output are returned to the calling subroutine.
-               
-               If the exit $attempt_limit > 1 and the status is not 0 after all
-               attempts are made, undefined is returned. This allows the calling
-               subroutine to simply check if result is true if it does not care
-               about the output.
-               
-               There is a special condition if the $attempt_limit is 1 and the
-               exit status is not 0. $exit_status and $output are always
-               returned so calling subroutine can handle the logic.
-
-=cut
-
-sub _run_vim_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 $vim_arguments = shift;
-	if (!$vim_arguments) {
-		notify($ERRORS{'WARNING'}, 0, "VIM command arguments were not specified");
-		return;
-	}
-	
-	my $timeout_seconds = shift || 60;
-	my $attempt_limit = shift || 5;
-	
-	my $request_state_name = $self->data->get_request_state_name();
-	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
-	
-	my $command = "$self->{vim_cmd} $vim_arguments";
-	
-	my $attempt = 0;
-	my $wait_seconds = 5;
-	
-	my $connection_reset_errors = 0;
-	
-	ATTEMPT: while ($attempt++ < $attempt_limit) {
-		
-		my $semaphore;
-		if ($attempt > 1) {
-			# Wait before making next attempt
-			notify($ERRORS{'OK'}, 0, "sleeping $wait_seconds seconds before making attempt $attempt/$attempt_limit");
-			sleep_uninterrupted($wait_seconds);
-			$semaphore = $self->get_semaphore($vmhost_computer_name, 120, 1) || next ATTEMPT;
-		}
-		
-		# The following error is somewhat common if several processes are adding/removing VMs at the same time:
-		# (vmodl.fault.ManagedObjectNotFound) {
-		#	 dynamicType = <unset>,
-		#	 faultCause = (vmodl.MethodFault) null,
-		# 	 obj = 'vim.VirtualMachine:672',
-		# 	 msg = "The object has already been deleted or has not been completely created",
-		# }
-		
-		# Keep a count of the number of times vim-cmd is executed for the entire vcld state process
-		# This will be used to improve performance by reducing the number of calls necessary
-		$self->{vim_cmd_calls}++;
-		#notify($ERRORS{'DEBUG'}, 0, "vim-cmd call count: $self->{vim_cmd_calls} ($vim_arguments)");
-		
-		#my $register_semaphore;
-		#if ($command =~ /(getallvms|register)/) {
-		#	$register_semaphore = $self->get_semaphore($vmhost_computer_name, 120, 1);
-		#	if (!$register_semaphore) {
-		#		next ATTEMPT;
-		#	}
-		#}
-		
-		my ($exit_status, $output) = $self->vmhost_os->execute({
-			'command' => $command,
-			'display_output' => 0,
-			'timeout_seconds' => $timeout_seconds,
-			#'max_attempts' => 1
-		});
-		
-		if (!defined($output)) {
-			notify($ERRORS{'WARNING'}, 0, "attempt $attempt/$attempt_limit: failed to run VIM command on VM host $vmhost_computer_name: $command");
-		}
-		elsif (grep(/already been deleted/i, @$output)) {
-			notify($ERRORS{'OK'}, 0, "attempt $attempt/$attempt_limit: fault occurred attempting to run command on VM host $vmhost_computer_name: $command, output:\n" . join("\n", @$output));
-		}
-		elsif (grep(/(Failed to login|connection reset|SSL Exception)/i, @$output)) {
-			# Try to catch these errors:
-			# Failed to login: Connection reset by peer
-			# Failed to login: SSL Exception: The SSL handshake timed out local: 127.0.0.1:52713 peer: 127.0.0.1:443.
-			$connection_reset_errors++;
-			notify($ERRORS{'OK'}, 0, "attempt $attempt/$attempt_limit: connection reset while attempting to run command on VM host $vmhost_computer_name: $command, output:\n" . join("\n", @$output));
-			
-			# If 2 connection reset errors occured, attempt to run services.sh restart
-			if ($connection_reset_errors == 2) {
-				if ($self->{services_restarted}) {
-					notify($ERRORS{'WARNING'}, 0, "encountered $connection_reset_errors connection reset errors on VM host $vmhost_computer_name, not calling 'services.sh restart', it was already attempted");
-				}
-				else {
-					notify($ERRORS{'OK'}, 0, "calling 'services.sh restart', encountered $connection_reset_errors connection reset errors on VM host $vmhost_computer_name");
-					$self->_services_restart();
-					$self->{services_restarted} = 1;
-					next ATTEMPT;
-				}
-			}
-			elsif ($connection_reset_errors > 2) {
-				notify($ERRORS{'WARNING'}, 0, "encountered $connection_reset_errors connection reset errors on VM host $vmhost_computer_name");
-			}
-			else {
-				next ATTEMPT;
-			}
-			
-			# Problem probably won't correct itself
-			# If request state is 'inuse', set the reservation.lastcheck value to 20 minutes before request.end
-			# This avoids 'inuse' processes from being created over and over again which will fail
-			if ($request_state_name eq 'inuse') {
-				my $reservation_id = $self->data->get_reservation_id();
-				my $request_end_time_epoch = convert_to_epoch_seconds($self->data->get_request_end_time());
-				my $current_time_epoch = time;
-				my $reservation_lastcheck_epoch = ($request_end_time_epoch-(20*60));
-				set_reservation_lastcheck($reservation_lastcheck_epoch, $reservation_id);
-			}
-			return;
-		}
-		elsif (grep(/^(vim-cmd:|Killed|terminate called|Aborted|what\()/i, @$output)) {
-			# terminate called after throwing an instance of 'std::bad_alloc'
-			# what():  std::bad_alloc
-			# Aborted
-			notify($ERRORS{'WARNING'}, 0, "attempt $attempt/$attempt_limit: failed to execute command on VM host $vmhost_computer_name: $command, exit status: $exit_status, output:\n" . join("\n", @$output));
-			next ATTEMPT;
-		}
-		elsif ($exit_status != 0) {
-			if ($attempt_limit == 1) {
-				notify($ERRORS{'DEBUG'}, 0, "command failed on VM host $vmhost_computer_name, not making another attempt because attempt limit argument is set to $attempt_limit, error checking will be done by calling subroutine, command: $command, exit status: $exit_status, output:\n" . join("\n", @$output));
-				return ($exit_status, $output);
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "attempt $attempt/$attempt_limit: command failed on VM host $vmhost_computer_name: $command, exit status: $exit_status, output:\n" . join("\n", @$output));
-				next ATTEMPT;
-			}
-		}
-		else {
-			# VIM command command was executed
-			if ($attempt > 1) {
-				notify($ERRORS{'DEBUG'}, 0, "attempt $attempt/$attempt_limit: executed command on VM host $vmhost_computer_name: $command, exit status: $exit_status");
-			}
-			else {
-				notify($ERRORS{'DEBUG'}, 0, "executed command on VM host $vmhost_computer_name: $command, exit status: $exit_status");
-			}
-			return ($exit_status, $output);
-		}
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "failed to run VIM command on VM host $vmhost_computer_name: '$command', made $attempt_limit attempts");
-	return;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _services_restart
-
- Parameters  : none
- Returns     : boolean
- Description : Calls 'services.sh restart' on the VM host. This may resolve
-               problems where the host is not responding due to a problem with
-               one or more services. This should rarely be called.
-
-=cut
-
-sub _services_restart {
-	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 $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
-	
-	my $semaphore = $self->get_semaphore("$vmhost_computer_name-vmware_services_restart", 0);
-	if (!$semaphore) {
-		notify($ERRORS{'OK'}, 0, "unable to obtain semaphore, another process is likely restarting services on $vmhost_computer_name, sleeping for 30 seconds and then proceeding");
-		sleep_uninterrupted(30);
-		return 1;
-	}
-	
-	my $check_services = {
-		'hostd-worker' => '/var/run/vmware/vmware-hostd.PID',
-		'sfcb-vmware_bas' => '/var/run/vmware/vicimprovider.PID',
-		'vmkdevmgr' => '/var/run/vmware/vmkdevmgr.pid',
-		'vmkeventd' => '/var/run/vmware/vmkeventd.pid',
-		'vmsyslogd' => '/var/run/vmware/vmsyslogd.pid',
-		'rhttpproxy-work' => '/var/run/vmware/vmware-rhttpproxy.PID',
-		'vpxa-worker' => '/var/run/vmware/vmware-vpxa.PID',
-	};
-	
-	# Check if the PID files for the following services are correct
-	for my $service_name (keys %$check_services) {
-		my $pid_file_path = $check_services->{$service_name};
-		$self->_check_service_pid($service_name, $pid_file_path);
-	}
-	
-	my $services_command = "services.sh restart";
-	notify($ERRORS{'DEBUG'}, 0, "restarting VMware services on $vmhost_computer_name");
-	my ($services_exit_status, $services_output) = $self->vmhost_os->execute($services_command, 0, 120);
-	if (!defined($services_output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: $services_command");
-		return;
-	}
-	else {
-		notify($ERRORS{'OK'}, 0, "executed command to restart VMware services on $vmhost_computer_name, command: '$services_command', output:\n" . join("\n", @$services_output));
-	}
-	return 1;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _check_service_pid
-
- Parameters  : $process_name, $pid_file_path
- Returns     : boolean
- Description : Checks if the PID stored in the PID file matches the parent PID
-               of the running service process. Problems occur if the file does
-               not match the running process PID. Most often, vim-cmd commands
-               fail with an error such as:
-               Connect to localhost failed: Connection failure
-               
-               The PID file is updated with the correct PID if the PID file
-               contents cannot be retrieved and parsed or if the PID stored in
-               the file does not match the running process.
-
-=cut
-
-sub _check_service_pid {
-	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 ($process_name, $pid_file_path) = @_;
-	if (!defined($process_name) || !defined($pid_file_path)) {
-		notify($ERRORS{'WARNING'}, 0, "process name and PID file path arguments were not supplied");
-		return;
-	}
-	
-	my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
-	
-	# Retrieve the running PID
-	my $running_pid;
-	my $ps_command = "ps |grep $process_name |awk '{print \$2}'";
-	my ($ps_exit_status, $ps_output) = $self->vmhost_os->execute($ps_command);
-	if (!defined($ps_output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to run command to determine main $process_name PID on $vmhost_computer_name");
-	}
-	else {
-		($running_pid) = "@$ps_output" =~ /(\d+)/g;
-		if ($running_pid && $running_pid > 1) {
-			notify($ERRORS{'DEBUG'}, 0, "retrieved parent $process_name PID: $running_pid");
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "parent $process_name process is not running");
-		}
-	}
-	
-	# Check if the .pid file exists
-	my $pid_file_exists = $self->vmhost_os->file_exists($pid_file_path);
-	if (!$running_pid) {
-		if ($pid_file_exists) {
-			notify($ERRORS{'DEBUG'}, 0, "running $process_name process was not detected but PID file exists: $pid_file_path, deleting file");
-			if ($self->vmhost_os->delete_file($pid_file_path)) {
-				notify($ERRORS{'DEBUG'}, 0, "deleted file on $vmhost_computer_name: $pid_file_path");
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to delete file on $vmhost_computer_name: $pid_file_path");
-			}
-			return 1;
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "running $process_name process was not detected and PID file does not exist: $pid_file_path");
-			return 1;
-		}
-	}
-	else {
-		if ($pid_file_exists) {
-			# Retrieve the PID stored in the PID file
-			my @pid_file_contents = $self->vmhost_os->get_file_contents($pid_file_path);
-			if (@pid_file_contents) {
-				my ($file_pid) = "@pid_file_contents" =~ /(\d+)/g;
-				if ($file_pid) {
-					notify($ERRORS{'DEBUG'}, 0, "retrieved PID stored in $pid_file_path: $file_pid");
-					if ($file_pid eq $running_pid) {
-						notify($ERRORS{'OK'}, 0, "PID in $pid_file_path ($file_pid) matches PID of parent $process_name process ($running_pid), update not necessary");
-						return 1;
-					}
-					else {
-						notify($ERRORS{'OK'}, 0, "PID in $pid_file_path ($file_pid) does not match PID of parent $process_name process ($running_pid), updating $pid_file_path to contain $running_pid");
-					}
-				}
-				else {
-					notify($ERRORS{'WARNING'}, 0, "unable to determine PID stored in $pid_file_path, contents:\n" . join("\n", @pid_file_contents));
-				}
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to retrieve contents of $pid_file_path");
-			}
-		}
-		
-		# Update the PID file with the correct PID
-		my $echo_command = "echo -n $running_pid > $pid_file_path";
-		my ($echo_exit_status, $echo_output) = $self->vmhost_os->execute($echo_command);
-		if (!defined($echo_output)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to run command to update $pid_file_path on $vmhost_computer_name");
-			return;
-		}
-		elsif (grep(/(ash:|echo:)/, @$echo_output)) {
-			notify($ERRORS{'WARNING'}, 0, "error occurred updating $pid_file_path on $vmhost_computer_name, command: '$echo_command', output:\n" . joini("\n", @$echo_output));
-			return;
-		}
-		else {
-			notify($ERRORS{'OK'}, 0, "updated $pid_file_path on $vmhost_computer_name to contain the correct PID: $running_pid");
-		}
-	}
-	
-	return 1;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_vm_list
-
- Parameters  : none
- Returns     : hash
- Description : Returns an hash with keys containing the IDs of the VMs running
-               on the VM host. The values are the vmx file paths.
-
-=cut
-
-sub _get_vm_list {
-	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 $vim_cmd_arguments = "vmsvc/getallvms";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Check the vim-cmd output
-	# Format of the output from "vim-cmd vmsvc/getallvms":
-	# Vmid Name                                                          File                                                              Guest OS        Version Annotation
-	# 496  vm-ark-mcnc-9 (nonpersistent: vmwarewinxp-base234-v12)        [nfs-datastore] vm-ark-mcnc-9_234-v12/vm-ark-mcnc-9_234-v12.vmx   winXPProGuest   vmx-04      
-	# 512  vm-ark-mcnc-10 (nonpersistent: vmwarelinux-centosbase1617-v1) [nfs-datastore] vm-ark-mcnc-10_1617-v1/vm-ark-mcnc-10_1617-v1.vmx otherLinuxGuest vmx-04
-	if (!grep(/Vmid\s+Name/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM IDs, unexpected output returned, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	my %vms;
-	for my $line (@$output) {
-		my ($vm_id, $vmx_file_path) = $line =~ /^(\d+).*(\[.+\.vmx)/;
-		
-		# Skip lines that don't begin with a number
-		next if !defined($vm_id);
-		
-		# Make sure the vmx file path was parsed
-		if (!$vmx_file_path) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine vmx file path, VIM command arguments: '$vim_cmd_arguments', output line: $line");
-			return;
-		}
-		
-		# Get the normal path
-		my $vmx_normal_path = $self->_get_normal_path($vmx_file_path);
-		if (!$vmx_normal_path) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine normal path: $vmx_file_path");
-			#return;
-		}
-		
-		$vms{$vm_id} = $vmx_normal_path;
-	}
-	
-	#notify($ERRORS{'DEBUG'}, 0, "registered VMs IDs found: " . keys(%vms));
-	return \%vms;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_vm_id
-
- Parameters  : $vmx_file_path
- Returns     : integer
- Description : 
-
-=cut
-
-sub _get_vm_id {
-	my $self = shift;
-	if (ref($self) !~ /VCL::Module/i) {
-		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
-		return;
-	}
-	
-	my $vmx_file_path = shift;
-	if (!$vmx_file_path) {
-		notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not specified");
-		return;
-	}
-	
-	return $self->{vm_id}{$vmx_file_path} if $self->{vm_id}{$vmx_file_path};
-	
-	# Get the VM IDs and vmx paths
-	my $vm_list = $self->_get_vm_list();
-	if (!defined($vm_list)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM ID, failed to retrieve list of registered VMs and their IDs");
-		return;
-	}
-	
-	for my $vm_id (keys %$vm_list) {
-		if ($vm_list->{$vm_id} && $vmx_file_path eq $vm_list->{$vm_id}) {
-			$self->{vm_id}{$vmx_file_path} = $vm_id;
-			return $vm_id;
-		}
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "unable to determine VM ID, vmx file is not registered: $vmx_file_path, registered VMs:\n" . format_data($vm_list));
-	return;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_vm_summary
-
- Parameters  : $vm_id
- Returns     : string
- Description : Runs "vim-cmd vmsvc/get.summary <VM ID>" to retrive a summary
-               of the configuration of a VM.
-
-=cut
-
-sub _get_vm_summary {
-	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 || $self->get_vmx_file_path();
-	if (!$vmx_file_path) {
-		notify($ERRORS{'WARNING'}, 0, "vmx file path argument could not be determined");
-		return;
-	}
-	
-	my $vm_id = $self->_get_vm_id($vmx_file_path) || return;
-	
-	my $vim_cmd_arguments = "vmsvc/get.summary $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The output should look like this:
-	# Listsummary:
-	# (vim.vm.Summary) {
-	#   dynamicType = <unset>,
-	#   vm = 'vim.VirtualMachine:496',
-	#   runtime = (vim.vm.RuntimeInfo) {
-	#      dynamicType = <unset>,
-	#      host = 'vim.HostSystem:ha-host',
-	#      connectionState = "connected",
-	#      powerState = "poweredOn",
-	#      faultToleranceState = "notConfigured",
-	#      toolsInstallerMounted = false,
-	#      suspendTime = <unset>,
-	#      bootTime = "2010-06-08T14:26:48.658743Z",
-	#      suspendInterval = 0,
-	#      question = (vim.vm.QuestionInfo) null,
-	#      memoryOverhead = 119189504,
-	#      maxCpuUsage = 2000,
-	#      maxMemoryUsage = 1024,
-	#      numMksConnections = 0,
-	#      recordReplayState = "inactive",
-	#      cleanPowerOff = <unset>,
-	#      needSecondaryReason = <unset>,
-	#   },
-	#   guest = (vim.vm.Summary.GuestSummary) {
-	#      dynamicType = <unset>,
-	#      guestId = "winXPProGuest",
-	#      guestFullName = "Microsoft Windows XP Professional (32-bit)",
-	#      toolsStatus = "toolsOld",
-	#      toolsVersionStatus = "guestToolsNeedUpgrade",
-	#      toolsRunningStatus = "guestToolsRunning",
-	#      hostName = "APACHE-44896D77.dcs.mcnc.org",
-	#      ipAddress = "152.46.16.235",
-	#   },
-	#   config = (vim.vm.Summary.ConfigSummary) {
-	#      dynamicType = <unset>,
-	#      name = "vm-ark-mcnc-9 (nonpersistent: vmwarewinxp-base234-v12)",
-	#      template = false,
-	#      vmPathName = "[nfs-datastore] vm-ark-mcnc-9_234-v12/vm-ark-mcnc-9_234-v12.vmx",
-	#      memorySizeMB = 1024,
-	#      cpuReservation = <unset>,
-	#      memoryReservation = <unset>,
-	#      numCpu = 1,
-	#      numEthernetCards = 2,
-	#      numVirtualDisks = 1,
-	#      uuid = "564d36cf-6988-c91d-0f5f-a62628d46553",
-	#      instanceUuid = "",
-	#      guestId = "winXPProGuest",
-	#      guestFullName = "Microsoft Windows XP Professional (32-bit)",
-	#      annotation = "",
-	#      product = (vim.vApp.ProductInfo) null,
-	#      installBootRequired = <unset>,
-	#      ftInfo = (vim.vm.FaultToleranceConfigInfo) null,
-	#   },
-	#   storage = (vim.vm.Summary.StorageSummary) {
-	#      dynamicType = <unset>,
-	#      committed = 4408509391,
-	#      uncommitted = 11697668096,
-	#      unshared = 4408509391,
-	#      timestamp = "2010-06-08T14:26:30.312473Z",
-	#   },
-	#   quickStats = (vim.vm.Summary.QuickStats) {
-	#      dynamicType = <unset>,
-	#      overallCpuUsage = 20,
-	#      overallCpuDemand = <unset>,
-	#      guestMemoryUsage = 40,
-	#      hostMemoryUsage = 652,
-	#      guestHeartbeatStatus = "yellow",
-	#      distributedCpuEntitlement = <unset>,
-	#      distributedMemoryEntitlement = <unset>,
-	#      staticCpuEntitlement = <unset>,
-	#      staticMemoryEntitlement = <unset>,
-	#      privateMemory = <unset>,
-	#      sharedMemory = <unset>,
-	#      swappedMemory = <unset>,
-	#      balloonedMemory = <unset>,
-	#      consumedOverheadMemory = <unset>,
-	#      ftLogBandwidth = <unset>,
-	#      ftSecondaryLatency = <unset>,
-	#      ftLatencyStatus = <unset>,
-	#   },
-	#   overallStatus = "green",
-	# }
-	if (!grep(/vim\.vm\.Summary/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve VM summary, unexpected output returned, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	my $vm_summary_info = $self->_parse_vim_cmd_output($output);
-	if (defined($vm_summary_info->{'vim.vm.Summary'})) {
-		return $vm_summary_info->{'vim.vm.Summary'};
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to retrieve summary of VM: $vmx_file_path, parsed output does not contain a 'vim.vm.Summary' key:\n" . format_data($vm_summary_info));
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_datastore_info
-
- Parameters  : none
- Returns     : hash reference
- Description : 
-
-=cut
-
-sub _get_datastore_info {
-	my $self = shift;
-	if (ref($self) !~ /VCL::Module/i) {
-		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
-		return;
-	}
-	
-	# Return previously retrieved datastore name array if it is defined in this object
-	if ($self->{datastore}) {
-		return $self->{datastore};
-	}
-	
-	my $vmhost_hostname = $self->data->get_vmhost_hostname();
-	
-	my $vim_cmd_arguments = "hostsvc/datastore/listsummary";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The output should look like this:
-	# (vim.Datastore.Summary) [
-	#	(vim.Datastore.Summary) {
-	#		dynamicType = <unset>,
-	#		datastore = 'vim.Datastore:4bcf0efe-c426acc4-c7e1-001a644d1cc0',
-	#		name = "local-datastore",
-	#		url = "/vmfs/volumes/4bcf0efe-c426acc4-c7e1-001a644d1cc0",
-	#		capacity = 31138512896,
-	#		freeSpace = 26277314560,
-	#		uncommitted = 0,
-	#		accessible = true,
-	#		multipleHostAccess = <unset>,
-	#		type = "VMFS",
-	#	},
-	#	(vim.Datastore.Summary) {
-	#		dynamicType = <unset>,
-	#		datastore = 'vim.Datastore:10.25.0.245:/vmfs/volumes/nfs-datastore',
-	#		name = "nfs-datastore",
-	#		url = "/vmfs/volumes/95e378c2-863dd2b4",
-	#		capacity = 975027175424,
-	#		freeSpace = 108854874112,
-	#		uncommitted = 0,
-	#		accessible = true,
-	#		multipleHostAccess = <unset>,
-	#		type = "NFS",
-	#	},
-	# ]
-	if (!grep(/vim\.Datastore\.Summary/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine datastore names, unexpected output returned, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	my $datastore_info;
-	
-	# Split the output into sections for each datastore
-	my @output_sections = split(/vim\.Datastore\.Summary/i, join("\n", @$output));
-	
-	for my $output_section (@output_sections) {
-		my ($datastore_name) = $output_section =~ /name\s*=\s*"(.+)"/;
-		next if (!defined($datastore_name));
-		
-		for my $line (split(/[\r\n]+/, $output_section)) {
-			# Skip lines which don't contain a '='
-			next if $line !~ /=/;
-			
-			# Parse the line
-			my ($parameter, $value) = $line =~ /^\s*(\w+)\s*=[\s"']*([^"',]+)/g;
-			if (defined($parameter) && defined($value)) {
-				$datastore_info->{$datastore_name}{$parameter} = $value if ($parameter ne 'name');
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "unable to parse parameter and value from line: '$line'");
-			}
-		}
-		
-		# Check if the accessible value was retrieved and is not false
-		my $datastore_accessible = $datastore_info->{$datastore_name}{accessible};
-		if (!$datastore_accessible || $datastore_accessible =~ /false/i) {
-			notify($ERRORS{'DEBUG'}, 0, "datastore '$datastore_name' is mounted on $vmhost_hostname but not accessible");
-			delete $datastore_info->{$datastore_name};
-			next;
-		}
-		
-		# Add a 'normal_path' key to the hash based on the datastore url
-		my $datastore_url = $datastore_info->{$datastore_name}{url};
-		if (!defined($datastore_url)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to determine datastore url from 'vim-cmd $vim_cmd_arguments' output section, datastore name: $datastore_name:\n$output_section");
-			delete $datastore_info->{$datastore_name};
-			next;
-		}
-		
-		my $datastore_normal_path;
-		if ($datastore_url =~ /^\/vmfs\/volumes/i) {
-			$datastore_normal_path = "/vmfs/volumes/$datastore_name";
-		}
-		else {
-			$datastore_normal_path = $datastore_url;
-		}
-		$datastore_info->{$datastore_name}{normal_path} = $datastore_normal_path;
-	}
-
-	return $datastore_info;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_task_ids
-
- Parameters  : $vmx_file_path, $task_type
- Returns     : array
- Description : Returns an array containing the task IDs recently executed on
-               the VM indicated by the $vm_id argument. The task type argument
-               must be specified. Example task type values:
-               powerOn
-               powerOff
-               registerVm
-               unregisterVm
-
-=cut
-
-sub _get_task_ids {
-	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 || $self->get_vmx_file_path();
-	if (!$vmx_file_path) {
-		notify($ERRORS{'WARNING'}, 0, "vmx file path argument could not be determined");
-		return;
-	}
-	
-	# Get the task type argument
-	my $task_type = shift;
-	
-	my $vm_id = $self->_get_vm_id($vmx_file_path) || return;
-	
-	my $vim_cmd_arguments = "vmsvc/get.tasklist $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Expected output:
-	# (ManagedObjectReference) [
-	#   'vim.Task:haTask-512-vim.VirtualMachine.powerOn-2826',
-	#   'vim.Task:haTask-512-vim.VirtualMachine.powerOn-2843',
-	#   'vim.Task:haTask-512-vim.VirtualMachine.powerOn-2856'
-	# ]
-	
-	# Expected output if there are no recent tasks:
-	# (ManagedObjectReference) []
-	
-	if (!grep(/ManagedObjectReference/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to retrieve task list, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	elsif (grep(/\(ManagedObjectReference\)\s*\[\]/i, @$output)) {
-		notify($ERRORS{'DEBUG'}, 0, "there are no recent tasks for VM $vm_id");
-		return ();
-	}
-	
-	#notify($ERRORS{'DEBUG'}, 0, "task list output:\n" . join("\n", @$output));
-	
-	# Reverse the output array so the newest tasks are listed first
-	my @reversed_output = reverse(@$output);
-	
-	#notify($ERRORS{'DEBUG'}, 0, "reversed task list output:\n" . join("\n", @reversed_output));
-	
-	#my (@task_ids) = grep(/haTask-$vm_id-.+$task_type-/, @reversed_output);
-	my @task_ids;
-	if ($task_type) {
-		@task_ids = map { /(haTask-$vm_id-.+$task_type-\d+)/ } @reversed_output;
-	}
-	else {
-		@task_ids = map { /(haTask-$vm_id-.+-\d+)/ } @reversed_output;
-		$task_type = 'all';
-	}
-	
-	# Check if a matching task was found
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine task IDs from output for VM $vm_id, task type: $task_type, output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	#notify($ERRORS{'DEBUG'}, 0, "retrieved task IDs for VM $vm_id, task type: $task_type:\n" . join("\n", @task_ids));
-	return @task_ids;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _get_task_info
-
- Parameters  : $task_id
- Returns     : hash reference
- Description : 
-
-=cut
-
-sub _get_task_info {
-	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 task ID path argument
-	my (@task_ids) = @_;
-	@task_ids = $self->_get_task_ids() if (!@task_ids);
-	
-	my $task_info = {};
-	
-	for my $task_id (@task_ids) {
-		my $vim_cmd_arguments = "vimsvc/task_info $task_id";
-		my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-		
-		# Expected output:
-		# (vim.TaskInfo) {
-		#   dynamicType = <unset>,
-		#   key = "haTask-496-vim.VirtualMachine.powerOn-3072",
-		#   task = 'vim.Task:haTask-496-vim.VirtualMachine.powerOn-3072',
-		#   description = (vmodl.LocalizableMessage) null,
-		#   name = "vim.VirtualMachine.powerOn",
-		#   descriptionId = "VirtualMachine.powerOn",
-		#   entity = 'vim.VirtualMachine:496',
-		#   entityName = "vm-ark-mcnc-9 (nonpersistent: vmwarewinxp-base234-v12)",
-		#   state = "error",
-		#   cancelled = false,
-		#   cancelable = false,
-		#   error = (vmodl.fault.RequestCanceled) {
-		#      dynamicType = <unset>,
-		#      faultCause = (vmodl.MethodFault) null,
-		#      msg = "The task was canceled by a user.",
-		#   },
-		#   result = <unset>,
-		#   progress = 100,
-		#   reason = (vim.TaskReasonUser) {
-		#      dynamicType = <unset>,
-		#      userName = "root",
-		#   },
-		#   queueTime = "2010-06-30T08:48:44.187347Z",
-		#   startTime = "2010-06-30T08:48:44.187347Z",
-		#   completeTime = "2010-06-30T08:49:26.381383Z",
-		#   eventChainId = 3072,
-		#   changeTag = <unset>,
-		#   parentTaskKey = <unset>,
-		#   rootTaskKey = <unset>,
-		# }
-		
-		# Expected output if the task is not found:
-		# (vmodl.fault.ManagedObjectNotFound) {
-		#   dynamicType = <unset>,
-		#   faultCause = (vmodl.MethodFault) null,
-		#   obj = 'vim.Task:haTask-496-vim.VirtualMachine.powerOn-3072x',
-		#   msg = "The object has already been deleted or has not been completely created",
-		# }
-		
-		if (!defined($output)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to execute command to retrieve info for task ID: $task_id");
-			next;
-		}
-		elsif (grep(/ManagedObjectNotFound/i, @$output)) {
-			notify($ERRORS{'WARNING'}, 0, "task was not found, task ID: $task_id, output:\n" . join("\n", @$output));
-			next;
-		}
-		elsif (!grep(/vim.TaskInfo/i, @$output)) {
-			notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to retrieve task list, VIM command arguments: '$vim_cmd_arguments' output:\n" . join("\n", @$output));
-			next;
-		}
-		else {
-			#notify($ERRORS{'DEBUG'}, 0, "retrieved info for task $task_id");	
-			$task_info->{$task_id} = join("\n", @$output);
-		}
-	}
-	
-	return $task_info;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 _wait_for_task
-
- Parameters  : $task_id, $timeout_seconds (optional)
- Returns     : boolean
- Description : Waits for the vim task to complete. Returns true if the task
-               completes successfully.
-
-=cut
-
-sub _wait_for_task {
-	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 task ID path argument
-	my $task_id = shift;
-	if (!$task_id) {
-		notify($ERRORS{'WARNING'}, 0, "task ID argument was not supplied");
-		return;
-	}
-	
-	my $timeout_seconds = shift || 30;
-	
-	my $start_time = time();
-	
-	while (time() - $start_time < $timeout_seconds) {
-		notify($ERRORS{'DEBUG'}, 0, "checking status of task: $task_id");
-		
-		# Get the task info
-		my $task_info = $self->_get_task_info($task_id);
-		my $task_info_output = $task_info->{$task_id};
-		if (!$task_info || !$task_info_output) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine if task $task_id has completed, task info could not be retrieved");
-			return;
-		}
-		
-		# Parse the output to get the task state and progress
-		my ($task_state) = $task_info_output =~ /state\s*=\s*"([^"]+)/is;
-		if (!$task_state) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine task state from task info output:\n$task_info_output");
-			return;
-		}
-		
-		my ($error_message) = $task_info_output =~ /msg\s*=\s*"([^"]+)/;
-		$error_message = $task_info_output if !$error_message;
-		
-		my ($progress)= $task_info_output =~ /progress\s*=\s*(\d+)/;
-		$progress = 'unknown' if !defined($progress);
-		
-		if ($task_state =~ /success/) {
-			notify($ERRORS{'DEBUG'}, 0, "task completed successfully: $task_id");
-			return 1;
-		}
-		elsif ($task_state =~ /error|cancelled/) {
-			
-			# Check if the task failed with the message: 'Operation failed since another task is in progress.'
-			if ($error_message =~ /another task is in progress/i) {
-				# Retrieve info for all of the VMs recent tasks
-				my $task_info_all = $self->_get_task_info();
-				notify($ERRORS{'WARNING'}, 0, "task $task_id did not complete successfully, state: $task_state, error message: $error_message, task info:\n" . format_data($task_info_all));
-			}
-			elsif ($error_message =~ /state of the virtual machine has not changed since the last snapshot/i) {
-				# Snapshot may fail if VM is suspended and snapshot was already taken after suspension, message will be:
-				# message = "An error occurred while taking a snapshot: The state of the virtual machine has not changed since the last snapshot operation."
-				notify($ERRORS{'DEBUG'}, 0, "snapshot task is not necessary: $task_id, message: $error_message");
-				return 1;
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "task $task_id did not complete successfully, state: $task_state, error message: $error_message");
-			}
-			return;
-		}
-		elsif ($task_state =~ /running/) {
-			notify($ERRORS{'DEBUG'}, 0, "task state: $task_state, progress: $progress, sleeping for 3 seconds before checking task state again");
-			sleep 3;
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "task state: $task_state, progress: $progress, sleeping for 3 seconds before checking task state again, output:\n$task_info_output");
-			sleep 3;
-		}
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "timeout was reached: $timeout_seconds seconds, task never completed");
-	return;
-}
-
-###############################################################################
-
-=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;
-	}
-	
-	# Get the VM IDs
-	my $vm_list = $self->_get_vm_list();
-	if (!defined($vm_list)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve registered VMs, failed to retrieve list of registered VMs and their IDs");
-		return;
-	}
-	
-	# Get the vmx path values for each VM
-	my @vmx_paths = sort { lc($a) cmp lc($b) } values(%$vm_list);
-	
-	notify($ERRORS{'DEBUG'}, 0, "found " . scalar(@vmx_paths) . " registered VMs");
-	return @vmx_paths;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=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 $vm_id = $self->_get_vm_id($vmx_file_path) || return;
-	
-	my $vim_cmd_arguments = "vmsvc/power.getstate $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The output should look like this:
-	# Retrieved runtime info
-	# Powered on
-	
-	# Retrieved runtime info
-	# Powered off
-	
-	# 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';
-	}
-	elsif (grep(/powered off/i, @$output)) {
-		notify($ERRORS{'DEBUG'}, 0, "VM is powered off: $vmx_file_path");
-		return 'off';
-	}
-	elsif (grep(/suspended/i, @$output)) {
-		notify($ERRORS{'DEBUG'}, 0, "VM is suspended: $vmx_file_path");
-		return 'suspended';
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to determine power state of $vmx_file_path, VIM command arguments: '$vim_cmd_arguments' output:\n" . join("\n", @$output));
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=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;
-	}
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to power on VM because VM ID could not be determined");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/power.on $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 360);
-	return if !$output;
-	
-	# Expected output if the VM was not previously powered on:
-	# Powering on VM:
-	
-	# Expected output if the VM was previously powered on:
-	# Powering on VM:
-	# (vim.fault.InvalidPowerState) {
-	#   dynamicType = <unset>,
-	#   faultCause = (vmodl.MethodFault) null,
-	#   requestedState = "poweredOn",
-	#   existingState = "poweredOn",
-	#   msg = "The attempted operation cannot be performed in the current state (Powered On).",
-	# }
-	
-	if (grep(/existingState = "poweredOn"/i, @$output)) {
-		notify($ERRORS{'OK'}, 0, "VM is already powered on: $vmx_file_path");
-		return 1;
-	}
-	elsif (!grep(/Powering on VM/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power on VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	# Get the task ID
-	my @task_ids = $self->_get_task_ids($vmx_file_path, 'powerOn');
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to power on the VM");
-		return;
-	}
-	
-	# Wait for the task to complete
-	if ($self->_wait_for_task($task_ids[0])) {
-		notify($ERRORS{'OK'}, 0, "powered on VM: $vmx_file_path");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to power on VM: $vmx_file_path, the vim power on task did not complete successfully, vim-cmd $vim_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;
-	}
-	
-	# Check if the VM is already powered off
-	my $vm_power_state = $self->get_vm_power_state($vmx_file_path);
-	if ($vm_power_state && $vm_power_state =~ /off/i) {
-		notify($ERRORS{'DEBUG'}, 0, "VM is already powered off: $vmx_file_path");
-		return 1;
-	}
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to power off VM because VM ID could not be determined");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/power.off $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Expected output if the VM was not previously powered off:
-	# Powering off VM:
-	
-	# Expected output if the VM was previously powered off:
-	# Powering off VM:
-	# (vim.fault.InvalidPowerState) {
-	#   dynamicType = <unset>,
-	#   faultCause = (vmodl.MethodFault) null,
-	#   requestedState = "poweredOff",
-	#   existingState = "poweredOff",
-	#   msg = "The attempted operation cannot be performed in the current state (Powered Off).",
-	# }
-	
-	if (grep(/existingState = "poweredOff"/i, @$output)) {
-		notify($ERRORS{'DEBUG'}, 0, "VM is already powered off: $vmx_file_path");
-		return 1;
-	}
-	elsif (!grep(/Powering off VM/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power off VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-
-	# Get the task ID
-	my @task_ids = $self->_get_task_ids($vmx_file_path, 'powerOff');
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to power off the VM");
-		return;
-	}
-	
-	# Wait for the task to complete
-	if ($self->_wait_for_task($task_ids[0])) {
-		notify($ERRORS{'OK'}, 0, "powered off VM: $vmx_file_path");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to power off VM: $vmx_file_path, the vim power off task did not complete successfully, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 vm_suspend
-
- Parameters  : $vmx_file_path
- Returns     : boolean
- Description : Suspends the VM indicated by the vmx file path argument.
-
-=cut
-
-sub vm_suspend {
-	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;
-	}
-	
-	# Check if the VM is already powered off
-	my $vm_power_state = $self->get_vm_power_state($vmx_file_path);
-	if ($vm_power_state) {
-		if ($vm_power_state =~ /off/i) {
-			notify($ERRORS{'DEBUG'}, 0, "VM is already powered off: $vmx_file_path");
-			return 1;
-		}
-		elsif ($vm_power_state =~ /suspend/i) {
-			notify($ERRORS{'DEBUG'}, 0, "VM is already suspended: $vmx_file_path");
-			return 1;
-		}
-	}
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to power off VM because VM ID could not be determined");
-		return;
-	}
-	
-	notify($ERRORS{'DEBUG'}, 0, "suspending VM: $vmx_file_path ($vm_id)");
-	my $start_time = time;
-	my $vim_cmd_arguments = "vmsvc/power.suspend $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 400);
-	return if !$output;
-	
-	# Expected output if the VM was not previously suspended:
-	# Suspending VM:
-	
-	# Expected output if the VM was previously suspended or powered off:
-	# Suspending VM:
-	# Suspend failed
-	
-	if (!grep(/Suspending VM/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to suspend VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-
-	# Get the task ID
-	my @task_ids = $self->_get_task_ids($vmx_file_path, 'suspend');
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to suspend the VM");
-		return;
-	}
-	
-	# Wait for the task to complete
-	if ($self->_wait_for_task($task_ids[0])) {
-		my $duration = (time - $start_time);
-		notify($ERRORS{'OK'}, 0, "suspended VM: $vmx_file_path, took $duration seconds");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to suspend VM: $vmx_file_path, the vim power off task did not complete successfully, vim-cmd $vim_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;
-	}
-	
-	# Check if the VM is already registered
-	if ($self->is_vm_registered($vmx_file_path)) {
-		notify($ERRORS{'OK'}, 0, "VM is already registered: $vmx_file_path");
-		return 1;
-	}
-	
-	$vmx_file_path =~ s/\\* /\\ /g;
-	my $vim_cmd_arguments = "solo/registervm \"$vmx_file_path\"";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 60, 1);
-	return if !$output;
-	
-	# Note: registervm does not produce any output if it was successful
-	
-	# Expected output if the vmx file path does not exist:
-	# (vim.fault.NotFound) {
-	#   dynamicType = <unset>,
-	#   faultCause = (vmodl.MethodFault) null,
-	#   msg = "The object or item referred to could not be found.",
-	# }
-	
-	if (grep(/vim.fault.NotFound/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to register VM, vmx file was not found: $vmx_file_path, output:\n" . join("\n", @$output));
-		return;
-	}
-	elsif (grep(/vim.fault.AlreadyExists/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to register VM on the 1st attempt, an existing invalid VM using the same vmx file path may already already be registered, output:\n" . join("\n", @$output));
-		
-		# If an "invalid" VM exists using the same .vmx path, this fault will be generated:
-		#    (vim.fault.AlreadyExists) {
-		#    faultCause = (vmodl.MethodFault) null,
-		#    name = "51",
-		#    msg = "The specified key, name, or identifier '51' already exists."
-		my ($vm_id) = join("\n", @$output) =~ /name\s*=\s*"(\d+)"/;
-		if ($vm_id) {
-			if ($self->vm_unregister($vm_id)) {
-				notify($ERRORS{'DEBUG'}, 0, "unregistered existing invalid VM $vm_id, making another attempt to register VM: $vmx_file_path");
-			}
-			else {
-				notify($ERRORS{'WARNING'}, 0, "failed to register VM: $vmx_file_path, unable to unregister existing invalid VM $vm_id");
-				return;
-			}
-		}
-		else {
-			notify($ERRORS{'WARNING'}, 0, "failed to register VM: $vmx_file_path, ID of existing invalid VM could not be determined, was expecting a line beginning with 'name = \"<ID>\"' in output:\n" . join("\n", @$output));
-			return;
-		}
-	}
-	
-	if (grep(/fault/i, @$output)) {
-		# Only made 1 attempt so far, try again if fault occurred, allow 4 more attempts
-		($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 60, 4);
-		return if !$output;
-	}
-	
-	if (grep(/fault/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to register VM: $vmx_file_path, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	# Check to make sure the VM is registered
-	if ($self->is_vm_registered($vmx_file_path)) {
-		notify($ERRORS{'OK'}, 0, "registered VM: '$vmx_file_path'");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to register VM: '$vmx_file_path'");
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 vm_unregister
-
- Parameters  : $vm_identifier 
- Returns     : boolean
- Description : Unregisters the VM indicated by the argument which may either be
-               the .vmx file path or VM ID.
-
-=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;
-	}
-	
-	# Note: allow the VM ID to be passed in case the .vmx file path cannot be determined
-	# This allows an invalid VM with a missing .vmx file to be unregistered
-	
-	my $vm_identifier = shift;
-	if (!$vm_identifier) {
-		notify($ERRORS{'WARNING'}, 0, "VM identifier argument was not supplied");
-		return;
-	}
-	
-	my $vm_id;
-	my $vmx_file_path;
-	if ($vm_identifier =~ /^\d+$/) {
-		$vm_id = $vm_identifier;
-	}
-	else {
-		# Argument should be the vmx file path
-		$vmx_file_path = $vm_identifier;
-		
-		# 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_path");
-			return 1;
-		}
-		
-		# Power of the VM if it is powered on or the unregister command will fail
-		my $vm_power_state = $self->get_vm_power_state($vmx_file_path);
-		if ($vm_power_state && $vm_power_state =~ /on/i) {
-			if (!$self->vm_power_off($vmx_file_path)) {
-				notify($ERRORS{'WARNING'}, 0, "failed to unregister VM because it could not be powered off: $vmx_file_path");
-				return;
-			}
-		}
-		
-		$vm_id = $self->_get_vm_id($vmx_file_path);
-		if (!defined($vm_id)) {
-			notify($ERRORS{'OK'}, 0, "unable to unregister VM because VM ID could not be determined for vmx path argument: $vmx_file_path");
-			return;
-		}
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/unregister $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	
-	# Delete cached .vmx - VM ID mapping if previously retrieved
-	delete $self->{vm_id}{$vm_identifier};
-	
-	return if !$output;
-	
-	# Expected output if the VM is not registered:
-	# (vim.fault.NotFound) {
-	#   dynamicType = <unset>,
-	#   faultCause = (vmodl.MethodFault) null,
-	#   msg = "Unable to find a VM corresponding to "/vmfs/volumes/nfs-datastore/vm-ark-mcnc-9_234-v12/vm-ark-mcnc-9_234-v12.vmx"",
-	# }
-	
-	if (grep(/fault/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to unregister VM, VIM command arguments: '$vim_cmd_arguments'\noutput:\n" . join("\n", @$output));
-		return;
-	}
-	
-	# Check to make sure the VM is not registered
-	if ($vmx_file_path && $self->is_vm_registered($vmx_file_path)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to unregister VM: $vmx_file_path (ID: $vm_id), it still appears to be registered");
-		return;
-	}
-	else {
-		notify($ERRORS{'OK'}, 0, "unregistered VM: $vm_identifier");
-		return 1;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=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:
-               -FlatVer1
-               -FlatVer2
-               -RawDiskMappingVer1
-               -SparseVer1
-               -SparseVer2
-
-=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_directory_path, $vmdk_file_name) = $vmdk_file_path =~ /^(.+)\/([^\/]+\.vmdk)/;
-	if (!$vmdk_directory_path || !$vmdk_file_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine directory path and file name from vmdk file path: $vmdk_directory_path");
-		return;
-	}
-	
-	my $vmdk_directory_datastore_path = $self->_get_datastore_path($vmdk_directory_path);
-	if (!$vmdk_directory_datastore_path) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk directory datastore path from vmdk directory path: $vmdk_directory_path");
-		return;
-	}
-	
-	# The output of 'vim-cmd hostsvc/datastorebrowser/disksearch' differs for VMware Server 2.x and ESXi
-	# The value of 'thin' is not returned if disksearch is run under ESXi
-	my $vmware_product_name = $self->get_vmhost_product_name();
-	my $vim_cmd_arguments;
-	if ($vmware_product_name =~ /esx/i) {
-		$vim_cmd_arguments = "hostsvc/datastorebrowser/search 0 \"$vmdk_directory_datastore_path\"";
-	}
-	else {
-		$vim_cmd_arguments = "hostsvc/datastorebrowser/disksearch \"$vmdk_directory_datastore_path\"";
-	}
-	
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Expected output:
-	#(vim.host.DatastoreBrowser.SearchResults) {
-	#   dynamicType = <unset>,
-	#   datastore = 'vim.Datastore:10.10.14.20:/nfs-datastore1',
-	#   folderPath = "[nfs-datastore1] vclv17-149_234-v14",
-	#   file = (vim.host.DatastoreBrowser.FileInfo) [
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "vmwarewinxp-base234-v14.vmdk",
-	#         fileSize = 5926510592,
-	#         modification = "2010-11-24T17:06:44Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.FlatVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 4,
-	#         controllerType = "vim.vm.device.VirtualIDEController",
-	#         diskExtents = (string) [
-	#            "[nfs-datastore1] vclv17-149_234-v14/vmwarewinxp-base234-v14-flat.vmdk"
-	#         ],
-	#         thin = true,
-	#      }
-	#   ],
-	#}
-
-
-	my $output_string = join("\n", @$output);
-	my (@disk_info_sections) = split(/vim.host.DatastoreBrowser.VmDiskInfo/, $output_string);
-	
-	for my $disk_info (@disk_info_sections) {
-		my ($disk_path) = $disk_info =~ /\spath = "(.+)"/i;
-		
-		if (!$disk_path || $disk_path ne $vmdk_file_name) {
-			next;
-		}
-		
-		my ($disk_type) = $disk_info =~ /\sdiskType = "(.+)"/i;
-		if (!$disk_type) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine disk type, disk path: $disk_path, disk info section from vim-cmd $vim_cmd_arguments output:\n$disk_info");
-			next;
-		}
-		
-		# Disk type format: vim.vm.device.VirtualDisk.FlatVer2BackingInfo
-		# Remove everything but "FlatVer2"
-		$disk_type =~ s/(^.*\.|BackingInfo$)//g;
-		
-		# Return 'thin' if thin is set to true
-		my ($thin) = $disk_info =~ /\sthin\s*=\s*(.+)/i;
-		if (defined($thin) && $thin =~ /true/) {
-			$disk_type = 'thin';
-		}
-		
-		notify($ERRORS{'DEBUG'}, 0, "$disk_path disk type: $disk_type");
-		return $disk_type;
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "unable to determine disk type for disk: $vmdk_file_path, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-	return;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 get_virtual_disk_controller_type
-
- Parameters  : $vmdk_file_path
- Returns     : string
- Description : Retrieves the disk controller type configured for the virtual
-					disk specified by the vmdk file path argument. False is returned
-					if the controller type cannot be retrieved. A string is returned
-					containing one of the following values:
-					-IDE
-					-lsiLogic
-					-busLogic
-
-=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_directory_path, $vmdk_file_name) = $vmdk_file_path =~ /^(.+)\/([^\/]+\.vmdk)/;
-	if (!$vmdk_directory_path || !$vmdk_file_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine directory path and file name from vmdk file path: $vmdk_directory_path");
-		return;
-	}
-	
-	my $vmdk_directory_datastore_path = $self->_get_datastore_path($vmdk_directory_path);
-	if (!$vmdk_directory_datastore_path) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk directory datastore path from vmdk directory path: $vmdk_directory_path");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "hostsvc/datastorebrowser/searchsubfolders 0 \"$vmdk_directory_datastore_path\"";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Expected output:
-	# (vim.host.DatastoreBrowser.SearchResults) {
-	#   dynamicType = <unset>,
-	#   datastore = 'vim.Datastore:10.25.0.245:/vmfs/volumes/nfs-datastore',
-	#   folderPath = "[nfs-datastore] vmwarewinxp-base234-v12",
-	#   file = (vim.host.DatastoreBrowser.FileInfo) [
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "vmwarewinxp-base234-v12.vmdk",
-	#         fileSize = 4774187008,
-	#         modification = "2010-06-30T21:03:45Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.SparseVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 4,
-	#         controllerType = "vim.vm.device.VirtualBusLogicController",
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s001.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s002.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s003.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s004.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s005.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s006.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s007.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s008.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s009.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s010.vmdk"
-	#         ],
-	#         thin = false,
-	#      },
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "esx_2gb_sparse.vmdk",
-	#         fileSize = 4410286080,
-	#         modification = "2010-07-01T18:38:04Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.SparseVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 7,
-	#         controllerType = "vim.vm.device.VirtualIDEController",
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s001.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s002.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s003.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s004.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s005.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s006.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s007.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s008.vmdk"
-	#         ],
-	#         thin = true,
-	#      },
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "thin_vmwarewinxp-base234-v12.vmdk",
-	#         fileSize = 4408459264,
-	#         modification = "2010-06-30T20:53:51Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.FlatVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 4,
-	#         controllerType = <unset>,
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/thin_vmwarewinxp-base234-v12-flat.vmdk"
-	#         ],
-	#         thin = true,
-	#      }
-	#   ],
-	# }
-
-	my $output_string = join("\n", @$output);
-	my (@disk_info_sections) = split(/vim.host.DatastoreBrowser.VmDiskInfo/, $output_string);
-	
-	for my $disk_info (@disk_info_sections) {
-		my ($disk_path) = $disk_info =~ /\spath = "(.+)"/i;
-		
-		if (!$disk_path) {
-			next;
-		}
-		elsif ($disk_path ne $vmdk_file_name) {
-			#notify($ERRORS{'DEBUG'}, 0, "ignoring disk because the file name does not match $vmdk_file_name: $disk_path");
-			next;
-		}
-		
-		my ($controller_type) = $disk_info =~ /\scontrollerType\s*=\s*(.+)/i;
-		if (!$controller_type) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine disk controller type, disk path: $disk_path, disk info section from vim-cmd $vim_cmd_arguments output:\n$disk_info");
-			next;
-		}
-		
-		if ($controller_type =~ /unset/i) {
-			notify($ERRORS{'DEBUG'}, 0, "disk controller type is not set in the vmdk file: $disk_path");
-			return 0;
-		}
-		else {
-			# Extract just the controller type name from the value: vim.vm.device.VirtualIDEController --> IDE
-			$controller_type =~ s/(.*vim.vm.device.Virtual|Controller.*)//ig;
-			notify($ERRORS{'DEBUG'}, 0, "retrieved controller type for $disk_path: '$controller_type'");
-			return $controller_type;
-		}
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "unable to determine disk controller type for disk: $vmdk_file_path, vim-cmd $vim_cmd_arguments 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_directory_path, $vmdk_file_name) = $vmdk_file_path =~ /^(.+)\/([^\/]+\.vmdk)/;
-	if (!$vmdk_directory_path || !$vmdk_file_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine directory path and file name from vmdk file path: $vmdk_directory_path");
-		return;
-	}
-	
-	my $vmdk_directory_datastore_path = $self->_get_datastore_path($vmdk_directory_path);
-	if (!$vmdk_directory_datastore_path) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk directory datastore path from vmdk directory path: $vmdk_directory_path");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "hostsvc/datastorebrowser/searchsubfolders 0 \"$vmdk_directory_datastore_path\"";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# Expected output:
-	# (vim.host.DatastoreBrowser.SearchResults) {
-	#   dynamicType = <unset>,
-	#   datastore = 'vim.Datastore:10.25.0.245:/vmfs/volumes/nfs-datastore',
-	#   folderPath = "[nfs-datastore] vmwarewinxp-base234-v12",
-	#   file = (vim.host.DatastoreBrowser.FileInfo) [
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "vmwarewinxp-base234-v12.vmdk",
-	#         fileSize = 4774187008,
-	#         modification = "2010-06-30T21:03:45Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.SparseVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 4,
-	#         controllerType = "vim.vm.device.VirtualBusLogicController",
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s001.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s002.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s003.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s004.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s005.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s006.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s007.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s008.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s009.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/vmwarewinxp-base234-v12-s010.vmdk"
-	#         ],
-	#         thin = false,
-	#      },
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "esx_2gb_sparse.vmdk",
-	#         fileSize = 4410286080,
-	#         modification = "2010-07-01T18:38:04Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.SparseVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 7,
-	#         controllerType = "vim.vm.device.VirtualIDEController",
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s001.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s002.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s003.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s004.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s005.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s006.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s007.vmdk",
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/esx_2gb_sparse-s008.vmdk"
-	#         ],
-	#         thin = true,
-	#      },
-	#      (vim.host.DatastoreBrowser.VmDiskInfo) {
-	#         dynamicType = <unset>,
-	#         path = "thin_vmwarewinxp-base234-v12.vmdk",
-	#         fileSize = 4408459264,
-	#         modification = "2010-06-30T20:53:51Z",
-	#         owner = <unset>,
-	#         diskType = "vim.vm.device.VirtualDisk.FlatVer2BackingInfo",
-	#         capacityKb = 14680064,
-	#         hardwareVersion = 4,
-	#         controllerType = <unset>,
-	#         diskExtents = (string) [
-	#            "[nfs-datastore] vmwarewinxp-base234-v12/thin_vmwarewinxp-base234-v12-flat.vmdk"
-	#         ],
-	#         thin = true,
-	#      }
-	#   ],
-	# }
-
-	my $output_string = join("\n", @$output);
-	my (@disk_info_sections) = split(/vim.host.DatastoreBrowser.VmDiskInfo/, $output_string);
-	
-	for my $disk_info (@disk_info_sections) {
-		my ($disk_path) = $disk_info =~ /\spath = "(.+)"/i;
-		
-		if (!$disk_path) {
-			next;
-		}
-		elsif ($disk_path ne $vmdk_file_name) {
-			notify($ERRORS{'DEBUG'}, 0, "ignoring disk because the file name does not match $vmdk_file_name: $disk_path");
-			next;
-		}
-		
-		my ($hardware_version) = $disk_info =~ /\shardwareVersion\s*=\s*(\d+)/ig;
-		if (!$hardware_version) {
-			notify($ERRORS{'WARNING'}, 0, "unable to determine disk hardware version, disk path: $disk_path, disk info section from vim-cmd $vim_cmd_arguments output:\n$disk_info");
-			next;
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "retrieved hardware version for $disk_path: '$hardware_version'");
-			return $hardware_version;
-		}
-	}
-	
-	notify($ERRORS{'WARNING'}, 0, "unable to determine hardware version for disk: $vmdk_file_path, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-	return;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=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;
-	}
-	
-	my $vim_cmd_arguments = "solo/environment";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The output should contain a network section:
-   #network = (vim.vm.NetworkInfo) [
-   #   (vim.vm.NetworkInfo) {
-   #      dynamicType = <unset>,
-   #      name = "Private",
-   #      network = (vim.Network.Summary) {
-   #         dynamicType = <unset>,
-   #         network = 'vim.Network:HaNetwork-Private',
-   #         name = "Private",
-   #         accessible = true,
-   #         ipPoolName = "",
-   #      },
-   #   },
-   #   (vim.vm.NetworkInfo) {
-   #      dynamicType = <unset>,
-   #      name = "Public",
-   #      network = (vim.Network.Summary) {
-   #         dynamicType = <unset>,
-   #         network = 'vim.Network:HaNetwork-Public',
-   #         name = "Public",
-   #         accessible = true,
-   #         ipPoolName = "",
-   #      },
-   #   },
-   #],
-	
-	# Convert the output line array to a string then split it by network sections
-	my ($network_info) = join("\n", @$output) =~ /(vim\.vm\.NetworkInfo[^\]]+)/;
-	if ($network_info) {
-		notify($ERRORS{'DEBUG'}, 0, "network info:\n$network_info");
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to retrieve network info, vim-cmd arguments: '$vim_cmd_arguments', $exit_status: $exit_status, output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	my (@network_sections) = split(/vim.vm.NetworkInfo/, $network_info);
-	
-	# Extract the network names from the network sections
-	my @network_names;
-	for my $network_info (@network_sections) {
-		my ($network_name) = $network_info =~ /\sname = "(.+)"/i;
-		next if !$network_name;
-		push @network_names, $network_name;
-	}
-	
-	notify($ERRORS{'DEBUG'}, 0, "retrieved network names:\n" . join("\n", @network_names));
-	return @network_names;
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 create_snapshot
-
- Parameters  : $vmx_file_path, $name (optional)
- Returns     : boolean
- Description : Creates a snapshot of the VM.
-
-=cut
-
-sub create_snapshot {
-	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 $snapshot_name = shift || ("VCL: " . convert_to_datetime());
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to create snapshot because VM ID could not be determined");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/snapshot.create $vm_id '$snapshot_name'";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 60, 1);
-	return if !$output;
-	
-	notify($ERRORS{'DEBUG'}, 0, "create snapshot output:\n" . join("\n", @$output));
-	
-	# IMPORTANT: Don't check for 'failed' in the output, it may contain failed but the snapshot is not necessary:
-	# Snapshot not taken since the state of the virtual machine has not changed since the last snapshot operation.
-	#if (grep(/failed|invalid/i, @$output)) {
-	#	notify($ERRORS{'WARNING'}, 0, "failed to create snapshot of VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-	#	return;
-	#}
-	
-	# Get the task ID
-	my @task_ids = $self->_get_task_ids($vmx_file_path, 'createSnapshot');
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to create snapshot");
-		return;
-	}
-	
-	# Wait for the task to complete
-	if ($self->_wait_for_task($task_ids[0])) {
-		notify($ERRORS{'OK'}, 0, "created snapshot of VM: $vmx_file_path, snapshot name: $snapshot_name");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to create snapshot VM: $vmx_file_path, the vim task did not complete successfully, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 remove_snapshots
-
- Parameters  : $vmx_file_path
- Returns     : boolean
- Description : Removes all snapshots for a VM.
-
-=cut
-
-sub remove_snapshots {
-	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;
-	}
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to create snapshot because VM ID could not be determined");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/snapshot.removeall $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments, 7200);
-	return if !$output;
-	
-	notify($ERRORS{'DEBUG'}, 0, "remove snapshots output:\n" . join("\n", @$output));
-	
-	if (grep(/failed|invalid/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to remove snapshots for VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	# Get the task ID
-	my @task_ids = $self->_get_task_ids($vmx_file_path, 'removeAllSnapshots');
-	if (!@task_ids) {
-		notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to remove snapshots");
-		return;
-	}
-	
-	# Wait for the task to complete
-	if ($self->_wait_for_task($task_ids[0], 7200)) {
-		notify($ERRORS{'OK'}, 0, "removed snapshots for VM: $vmx_file_path");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to remove snapshots for VM: $vmx_file_path, the vim task did not complete successfully, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output));
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 snapshot_exists
-
- Parameters  : $vmx_file_path
- Returns     : boolean
- Description : Determines if a snapshot exists for the VM.
-
-=cut
-
-sub snapshot_exists {
-	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;
-	}
-	
-	# Get the VM ID
-	my $vm_id = $self->_get_vm_id($vmx_file_path);
-	if (!defined($vm_id)) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine if snapshot exists because VM ID could not be determined");
-		return;
-	}
-	
-	my $vim_cmd_arguments = "vmsvc/snapshot.get $vm_id";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	notify($ERRORS{'DEBUG'}, 0, "snapshot.get output:\n" . join("\n", @$output));
-	
-	if (grep(/failed|invalid/i, @$output)) {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine if snapshot exists for VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output));
-		return;
-	}
-	
-	# Expected output if shapshot exists:
-	# Get Snapshot:
-	# |-ROOT
-	# --Snapshot Name        : 1311966951
-	# --Snapshot Desciption  :
-	# --Snapshot Created On  : 7/29/2011 19:15:59
-	# --Snapshot State       : powered off
-	
-	# Expected output if snapshot does not exist:
-	# Get Snapshot:
-
-	if (grep(/-ROOT/, @$output)) {
-		notify($ERRORS{'DEBUG'}, 0, "snapshot exists for VM $vmx_file_path");
-		return 1;
-	}
-	else {
-		notify($ERRORS{'DEBUG'}, 0, "snapshot does NOT exist for VM $vmx_file_path");
-		return 0;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 get_cpu_core_count
-
- Parameters  : none
- Returns     : integer
- Description : Retrieves the quantitiy of CPU cores the VM host has.
-
-=cut
-
-sub get_cpu_core_count {
-	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 $vmhost_hostname = $self->data->get_vmhost_hostname();
-	
-	my $vim_cmd_arguments = "hostsvc/hosthardware";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The CPU info should be contained in the output:
-	#	cpuInfo = (vim.host.CpuInfo) {
-	#      dynamicType = <unset>,
-	#      numCpuPackages = 2,
-	#      numCpuCores = 8,
-	#      numCpuThreads = 8,
-	#      hz = 2000070804,
-	#   },
-	
-	my ($cpu_cores_line) = grep(/^\s*numCpuCores\s*=/i, @$output);
-	if (!$cpu_cores_line) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM host $vmhost_hostname CPU core count, output does not contain a 'numCpuCores =' line:\n" . join("\n", @$output));
-		return;
-	}
-	elsif ($cpu_cores_line =~ /(\d+)/) {
-		my $cpu_core_count = $1;
-		notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_hostname CPU core count: $cpu_core_count");
-		return $cpu_core_count;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine VM host $vmhost_hostname CPU core count from line: $cpu_cores_line");
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 get_cpu_speed
-
- Parameters  : none
- Returns     : integer
- Description : Retrieves the speed of the VM host's CPUs in MHz.
-
-=cut
-
-sub get_cpu_speed {
-	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 $vmhost_hostname = $self->data->get_vmhost_hostname();
-	
-	my $vim_cmd_arguments = "hostsvc/hosthardware";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The CPU info should be contained in the output:
-	#	cpuInfo = (vim.host.CpuInfo) {
-	#      dynamicType = <unset>,
-	#      numCpuPackages = 2,
-	#      numCpuCores = 8,
-	#      numCpuThreads = 8,
-	#      hz = 2000070804,
-	#   },
-	
-	my ($hz_line) = grep(/^\s*hz\s*=/i, @$output);
-	if (!$hz_line) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM host $vmhost_hostname CPU speed, output does not contain a 'hz =' line:\n" . join("\n", @$output));
-		return;
-	}
-	elsif ($hz_line =~ /(\d+)/) {
-		my $mhz = int($1 / 1000000);
-		notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_hostname CPU speed: $mhz MHz");
-		return $mhz;
-	}
-	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to determine VM host $vmhost_hostname CPU speed from line: $hz_line");
-		return;
-	}
-}
-
-#//////////////////////////////////////////////////////////////////////////////
-
-=head2 get_total_memory
-
- Parameters  : none
- Returns     : integer
- Description : Retrieves the VM host's total memory capacity in MB.
-
-=cut
-
-sub get_total_memory {
-	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 $vmhost_hostname = $self->data->get_vmhost_hostname();
-	
-	my $vim_cmd_arguments = "hostsvc/hosthardware";
-	my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments);
-	return if !$output;
-	
-	# The following line should be contained in the output:
-	#	 memorySize = 17178869760,
-	
-	my ($memory_size_line) = grep(/^\s*memorySize\s*=/i, @$output);
-	if (!$memory_size_line) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine VM host $vmhost_hostname total memory capacity, output does not contain a 'memorySize =' line:\n" . join("\n", @$output));
-		return;
-	}
-	elsif ($memory_size_line =~ /(\d+)/) {
-		my $memory_mb = int($1 / 1024 / 1024);
-		notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_hostname total memory capacity: $memory_mb MB");
-		return $memory_mb;
-	}
-	else {

[... 5603 lines stripped ...]