You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by fa...@apache.org on 2011/02/03 15:52:41 UTC

svn commit: r1066821 - /incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm

Author: fapeeler
Date: Thu Feb  3 14:52:41 2011
New Revision: 1066821

URL: http://svn.apache.org/viewvc?rev=1066821&view=rev
Log:
VCL-417

Adding David Hutchins virtual box module

Including small change on line 356 to include full path to hdds for vm.


Added:
    incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm

Added: incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm?rev=1066821&view=auto
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm (added)
+++ incubator/vcl/trunk/managementnode/lib/VCL/vbox.pm Thu Feb  3 14:52:41 2011
@@ -0,0 +1,1429 @@
+#!/usr/bin/perl -w
+###############################################################################
+# $Id: $ 
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+=head1 NAME
+
+VCL::Provisioning::vbox - VCL module to support SUN Virtual Box Provisioning
+
+=head1 SYNOPSIS
+
+ Needs to be written
+
+=head1 DESCRIPTION
+
+ This module provides VCL support for SUN Virtual Box.
+
+=cut
+
+##############################################################################
+package VCL::Module::Provisioning::vbox;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../../..";
+
+# Configure inheritance
+use base qw(VCL::Module::Provisioning);
+
+# Specify the version of this module
+our $VERSION = '1.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+use English qw( -no_match_vars );
+
+use VCL::utils;
+use Fcntl qw(:DEFAULT :flock);
+
+##############################################################################
+
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 initialize
+
+ Parameters  :
+ Returns     :
+ Description :
+
+=cut
+
+sub initialize {
+	notify($ERRORS{'DEBUG'}, 0, "module initialized");
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 provision
+
+ Parameters  : hash
+ Returns     : 1(success) or 0(failure)
+ Description : loads node with provided image
+
+=cut
+
+sub load {
+	my $self = shift;
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+
+	my $request_data = shift;
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	# Store some hash variables into local variables
+	my $request_id     = $self->data->get_request_id;
+	my $reservation_id = $self->data->get_reservation_id;
+	my $persistent     = $self->data->get_request_forimaging;
+	
+	my $management_node_keys     = $self->data->get_management_node_keys();
+
+	my $image_os_type  = $self->data->get_image_os_type;
+
+	my $vmclient_computerid = $self->data->get_computer_id;
+	my $computer_shortname  = $self->data->get_computer_short_name;
+	my $computer_nodename   = $computer_shortname;
+	my $computer_hostname   = $self->data->get_computer_hostname;
+
+	my $vmprofile_vmdisk  = $self->data->get_vmhost_profile_vmdisk;
+	my $datastorepath     = $self->data->get_vmhost_profile_datastore_path;
+	my $virtualswitch0    = $self->data->get_vmhost_profile_virtualswitch0;
+	my $virtualswitch1    = $self->data->get_vmhost_profile_virtualswitch1;
+
+	my $requestedimagename = $self->data->get_image_name;
+	my $shortname          = $computer_shortname;
+
+	my $vmhost_imagename          = $self->data->get_vmhost_image_name;
+	my $vmhost_hostname           = $self->data->get_vmhost_hostname;
+	my $vmclient_eth0MAC          = $self->data->get_computer_eth0_mac_address;
+	my $vmclient_eth1MAC          = $self->data->get_computer_eth1_mac_address;
+	my $vmclient_imageminram      = $self->data->get_image_minram;
+	my $vmhost_RAM                = $self->data->get_vmhost_ram;
+	my $vmclient_drivetype        = $self->data->get_computer_drive_type;
+	my $vmclient_privateIPaddress = $self->data->get_computer_ip_address;
+	my $vmclient_publicIPaddress  = $self->data->get_computer_private_ip_address;
+	my $vmclient_OSname           = $self->data->get_image_os_name;
+	
+	my $image_repository_path     = $self->_get_image_repository_path();
+	
+	# Assemble a consistent prefix for notify messages
+	my $notify_prefix = "req=$request_id, res=$reservation_id:";
+	my $vm_name;
+	my @sshcmd;
+	insertloadlog($reservation_id, $vmclient_computerid, "startload", "$computer_shortname $requestedimagename");
+	my $starttime = convert_to_epoch_seconds;
+
+	my ($hostnode);
+	$hostnode = $vmhost_hostname;
+	if (!(defined($management_node_keys))) {
+		notify($ERRORS{'CRITICAL'}, 0, "identity variable not defined, setting to blade identity file vmhost variable to $vmhost_imagename");
+	}
+
+	notify($ERRORS{'OK'}, 0, "identity file set $management_node_keys  vmhost imagename $vmhost_imagename bladekey ");
+	#setup flags
+        my $baseisregistered = 0;
+	my $baseexists   = 0;
+	my $dirstructure = 0;
+
+	#for convienence
+	my ($myimagename, $myvmx, $myvmdir, $mybasedirname, $requestedimagenamebase);
+
+	# preform cleanup
+	if ($self->control_VM("remove")) {
+                notify($ERRORS{'OK'}, 0, "removed node $shortname from vmhost $vmhost_hostname");
+        }
+
+        ### FIX-ME: I have no freakin clue how to approach this (imaging mode) at the moment
+        ###         For VBox, this would require changing the disk mode from immuatable to normal
+        ###         which itself would be easy, the challenge for me is handeling the hypervisors that have this image registered
+        ###         where any VMs that are using it will have associated snapshots that will have to be delt with before the image
+        ###         could be un-registered and re-registered. so for now, @#$% it... (david.hutchins)
+	if ($persistent) {
+         $vm_name = "$requestedimagename\_IMAGING\_$shortname"; 
+	} ## end if ($persistent)
+	else {
+         $vm_name = "$requestedimagename\_$shortname";
+	}
+	
+	$myimagename   = $requestedimagename;
+
+	notify($ERRORS{'DEBUG'}, 0, "persistent= NOT IMPLEMENTED");
+	notify($ERRORS{'DEBUG'}, 0, "myimagename= $myimagename");
+
+	#does the requested base vbox image files already existed on the vmhost
+	notify($ERRORS{'OK'}, 0, "checking for base image $requestedimagename on $hostnode ");
+	insertloadlog($reservation_id, $vmclient_computerid, "vmround1", "checking host for requested image files");
+
+	#check for lock file - another process might be copying the same image files to the same host server
+	my $tmplockfile = "/tmp/$hostnode" . "$requestedimagename" . "lock";
+	notify($ERRORS{'OK'}, 0, "trying to create exclusive lock on $tmplockfile while checking if image files exist on host");
+	if (sysopen(TMPLOCK, $tmplockfile, O_RDONLY | O_CREAT)) {
+		if (flock(TMPLOCK, LOCK_EX)) {
+			notify($ERRORS{'OK'}, 0, "owning exclusive lock on $tmplockfile");
+			notify($ERRORS{'OK'}, 0, "listing datestore $datastorepath ");
+
+			# Check to see if the baseimage is registered with VirtualBox on this host. 
+			undef @sshcmd;
+			#@sshcmd = run_ssh_command($hostnode, $management_node_keys, "ls -1 $datastorepath", "root");
+			@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list hdds", "root");
+			notify($ERRORS{'OK'}, 0, "Hdds in VirtualBox database on vm host:\n@{ $sshcmd[1] }");
+			foreach my $l (@{$sshcmd[1]}) {
+				if ($l =~ /(\s*?)$datastorepath\/$myimagename/) {
+                                        # The base is registered, so we will assume it is also present (This may not be the best approach, but for now it will do).
+					notify($ERRORS{'OK'}, 0, "base image exists");
+					$baseisregistered = 1;
+                                        $baseexists = 1;
+				}
+			} ## end foreach my $l (@{$sshcmd[1]})
+
+                        # If the base is not registered, we will check to see if it exists
+                        if (!($baseisregistered)) {
+				undef @sshcmd;
+				@sshcmd = run_ssh_command($hostnode, $management_node_keys, "ls -1 $datastorepath", "root");
+				foreach my $l (@{$sshcmd[1]}) {
+                                	if ($l =~ /(\s*?)$myimagename/) {
+                                        	# The base exists so we just need to register it with VirtualBox.
+                                        	notify($ERRORS{'OK'}, 0, "base image exists, registering it with VirtualBox");
+                                        	$baseexists = 1;
+                                	}
+                        	}
+			}
+
+
+			if (!($baseexists)) {
+				#check available disk space -- clean up if needed
+				#copy vm files from local repository to vmhost
+				#this could take a few minutes
+				#get size of  vmdl files
+
+				insertloadlog($reservation_id, $vmclient_computerid, "info", "image files do not exist on host server, preparing to copy");
+				my $myvmdkfilesize = 0;
+				if (open(SIZE, "du -k $image_repository_path/$requestedimagename 2>&1 |")) {
+					my @du = <SIZE>;
+					close(SIZE);
+					foreach my $d (@du) {
+						if ($d =~ /No such file or directory/) {
+							insertloadlog($reservation_id, $vmclient_computerid, "failed", "could not collect size of local image files");
+							notify($ERRORS{'CRITICAL'}, 0, "problem checking local vm file size on $image_repository_path/$requestedimagename");
+							close(TMPLOCK);
+							unlink($tmplockfile);
+							return 0;
+						}
+						if ($d =~ /^([0-9]*)/) {
+							$myvmdkfilesize += $1;
+						}
+					} ## end foreach my $d (@du)
+				} ## end if (open(SIZE, "du -k $image_repository_path/$requestedimagename 2>&1 |"...
+
+				notify($ERRORS{'DEBUG'}, 0, "file size $myvmdkfilesize of $requestedimagename");
+				if ($vmprofile_vmdisk eq "localdisk") {
+					notify($ERRORS{'OK'}, 0, "copying base image files $requestedimagename to $hostnode");
+					if (run_scp_command("$image_repository_path/$requestedimagename", "$hostnode:\"$datastorepath/\"", $management_node_keys)) {
+						#recheck host server for files - the  scp output is not being captured
+						undef @sshcmd;
+						@sshcmd = run_ssh_command($hostnode, $management_node_keys, "ls -1 $datastorepath", "root");
+						foreach my $l (@{$sshcmd[1]}) {
+							if ($l =~ /denied|No such/) {
+								notify($ERRORS{'CRITICAL'}, 0, "node $hostnode output @{ $sshcmd[1] }");
+								insertloadlog($reservation_id, $vmclient_computerid, "failed", "could not log into vmhost $hostnode @{ $sshcmd[1] }");
+								close(TMPLOCK);
+								unlink($tmplockfile);
+								return 0;
+							}
+							if ($l =~ /(\s*?)$requestedimagename$/) {
+								notify($ERRORS{'OK'}, 0, "base image exists");
+								$baseexists = 1;
+								insertloadlog($reservation_id, $vmclient_computerid, "transfervm", "copying base image files");
+							}
+						} ## end foreach my $l (@{$sshcmd[1]})
+
+					} ## end if (run_scp_command("$image_repository_path/$requestedimagename"...
+					else {
+						notify($ERRORS{'CRITICAL'}, 0, "problems scp vm files to $hostnode $!");
+						close(TMPLOCK);
+						unlink($tmplockfile);
+						return 0;
+					}
+				} ## end if ($vmprofile_vmdisk eq "localdisk")
+				notify($ERRORS{'OK'}, 0, "confirm image exist process complete removing lock on $tmplockfile");
+				close(TMPLOCK);
+				unlink($tmplockfile);
+
+			}    # start if base not exists
+                        # If the base exists but was not registered we just need to register it
+			elsif((!($baseisregistered)) && ($baseexists)) {
+				undef @sshcmd;
+                                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q openmedium disk $datastorepath/$myimagename --type immutable", "root");
+	                             foreach my $l (@{$sshcmd[1]}) {
+					if ($l =~ /(\s*?)ERROR:/) {
+                                                # Registeration failed, manual intervention is probably required, send warning and die.
+                                                notify($ERRORS{'CRITICAL'}, 0, "Registeration of image failed, output is: \n@{ $sshcmd[1] }");
+                                                close(TMPLOCK);
+                                                unlink($tmplockfile);
+                                                return 0;
+                                        } 
+					else {
+                                                # Registeration success.
+                                                notify($ERRORS{'OK'}, 0, "Registeration of image was successful");
+                                                $baseisregistered = 1;
+					}
+                                        
+                                }
+			} else {
+				#base exists
+				notify($ERRORS{'OK'}, 0, "confirm image exist process complete removing lock on $tmplockfile");
+				close(TMPLOCK);
+				unlink($tmplockfile);
+			}
+		}    #flock
+	}    #sysopen
+	     #ok good base vm files exist on hostnode
+	     #if guest dirstructure exists check state of vm, else create sturcture and new vmx file
+	#check for dependent settings ethX
+	if (!(defined($vmclient_eth0MAC))) {
+		#complain
+		notify($ERRORS{'CRITICAL'}, 0, "eth0MAC is not defined for $computer_shortname can not continue");
+		insertloadlog($reservation_id, $vmclient_computerid, "failed", "eth0MAC address is not defined");
+		return 0;
+
+	}
+
+	#check for memory settings
+	my $dynamicmemvalue = "128";
+	if (defined($vmclient_imageminram)) {
+		#preform some sanity check
+		if (($dynamicmemvalue < $vmclient_imageminram) && ($vmclient_imageminram < $vmhost_RAM)) {
+			$dynamicmemvalue = $vmclient_imageminram;
+			notify($ERRORS{'OK'}, 0, "setting memory to $dynamicmemvalue");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "image memory value $vmclient_imageminram out of the expected range in host machine $vmhost_RAM setting to 128");
+		}
+	} ## end if (defined($vmclient_imageminram))
+	
+        VBOXCREATE:
+
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q createvm --name $vm_name --register", "root");
+        $vmclient_eth0MAC =~ tr/://d;
+        $vmclient_eth1MAC =~ tr/://d;
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q modifyvm $vm_name --memory $dynamicmemvalue", "root");
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q modifyvm $vm_name --nic1 bridged --bridgeadapter1 $virtualswitch0 --macaddress1 $vmclient_eth0MAC", "root");
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q modifyvm $vm_name --nic2 bridged --bridgeadapter2 $virtualswitch1 --macaddress2 $vmclient_eth1MAC", "root");
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q storagectl $vm_name --name $shortname\_stor --add ide", "root");
+        if ($persistent) {
+		notify($ERRORS{'OK'}, 0, "Cloning image, this could take a while.");
+		undef @sshcmd;
+	        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q clonehd $image_repository_path/$requestedimagename $image_repository_path/$requestedimagename\_IMAGING\_$shortname.vdi ", "root");
+        	undef @sshcmd;
+                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q storageattach $vm_name --storagectl $shortname\_stor --port 0 --device 0 --type hdd --medium $image_repository_path/$requestedimagename\_IMAGING\_$shortname.vdi", "root"); 
+        } ## end if ($persistent)
+        else {
+        	undef @sshcmd;
+        	@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q storageattach $vm_name --storagectl $shortname\_stor --port 0 --device 0 --type hdd --medium $image_repository_path/$requestedimagename/$requestedimagename.vdi", "root");
+        }
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q modifyvm $vm_name --pae on", "root");
+
+	#turn on vm
+	#set loop control
+	my $vbox_starts = 0;
+
+	VBOXSTART:
+
+	$vbox_starts++;
+	notify($ERRORS{'OK'}, 0, "starting vm $vm_name - pass $vbox_starts");
+	if ($vbox_starts > 2) {
+		notify($ERRORS{'CRITICAL'}, 0, "VirtualBox starts exceeded limit vbox_starts= $vbox_starts hostnode= $hostnode vm= $computer_shortname");
+		insertloadlog($reservation_id, $vmclient_computerid, "failed", "could not load machine on $hostnode exceeded attempts");
+		return 0;
+	}
+
+	undef @sshcmd;
+	@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q startvm $vm_name --type headless", "root");
+	for my $l (@{$sshcmd[1]}) {
+		next if ($l =~ /Warning:/);
+		#if successful -- this cmd does not appear to return any ouput so anything could be a failure
+		if ($l =~ /successfully started/) {
+			notify($ERRORS{'OK'}, 0, "started $vm_name on $hostnode");
+		}
+		else {
+			notify($ERRORS{'OK'}, 0, "Unknown output when trying to start $vm_name on $hostnode \n@{ $sshcmd[1] }");
+		}
+	} ## end for my $l (@{$sshcmd[1]})
+	insertloadlog($reservation_id, $vmclient_computerid, "startvm", "started vm on $hostnode");
+
+	my $sshd_attempts = 0;
+
+	VBOXROUND2:
+	
+	insertloadlog($reservation_id, $vmclient_computerid, "vmround2", "waiting for ssh to become active");
+	
+	if ($self->os->can("post_load")) {
+		notify($ERRORS{'DEBUG'}, 0, "calling " . ref($self->os) . "->post_load()");
+		if ($self->os->post_load()) {
+			notify($ERRORS{'DEBUG'}, 0, "successfully ran OS post_load subroutine");
+		}
+		else {
+			my $vm_state = $self->power_status() || 'unknown';
+			notify($ERRORS{'WARNING'}, 0, "failed to run OS post_load subroutine, VM state: $vm_state");
+			return;
+		}
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, ref($self->os) . "::post_load() has not been implemented");
+	}
+	
+	insertloadlog($reservation_id, $vmclient_computerid, "info", "starting post configurations on node");
+	
+	#clear ssh public keys from /root/.ssh/known_hosts
+	my $known_hosts = "/root/.ssh/known_hosts";
+	my $ssh_keyscan = "/usr/bin/ssh-keyscan";
+	my $port        = "22";
+	my @file;
+	if (open(FILE, $known_hosts)) {
+		@file = <FILE>;
+		close FILE;
+        
+		foreach my $line (@file) {
+			if ($line =~ s/$computer_shortname.*\n//) {
+				notify($ERRORS{'OK'}, 0, "removing $computer_shortname ssh public key from $known_hosts");
+			}
+			if ($line =~ s/$vmclient_privateIPaddress}.*\n//) {
+				notify($ERRORS{'OK'}, 0, "removing $vmclient_privateIPaddress ssh public key from $known_hosts");
+			}
+		}
+        
+		if (open(FILE, ">$known_hosts")) {
+			print FILE @file;
+			close FILE;
+		}
+		#sync new keys
+		if (open(KEYSCAN, "$ssh_keyscan -t rsa -p $port $computer_shortname >> $known_hosts 2>&1 |")) {
+			my @ret = <KEYSCAN>;
+			close(KEYSCAN);
+			foreach my $r (@ret) {
+				notify($ERRORS{'OK'}, 0, "$r");
+			}
+		}
+	} ## end if (open(FILE, $known_hosts))
+	else {
+		notify($ERRORS{'OK'}, 0, "could not open $known_hosts for editing the $computer_shortname public ssh key");
+	}
+
+	insertloadlog($reservation_id, $vmclient_computerid, "vboxready", "preformed post config on node");
+	return 1;
+
+} ## end sub load
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 capture
+
+ Parameters  : $request_data_hash_reference
+ Returns     : 1 if sucessful, 0 if failed
+ Description : Creates a new vbox image.
+
+=cut
+
+sub capture { ## This is going to need to be implemented before the module is complete, but at the moment the focus is on complete VM provisioning.
+	my $self = shift;
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+	my $request_id     = $self->data->get_request_id;
+        my $reservation_id = $self->data->get_reservation_id;
+        my $management_node_keys     = $self->data->get_management_node_keys();
+
+        my $image_id       = $self->data->get_image_id;
+        my $image_os_name  = $self->data->get_image_os_name;
+        my $image_identity = $self->data->get_image_identity;
+        my $image_os_type  = $self->data->get_image_os_type;
+        my $image_name     = $self->data->get_image_name();
+
+        my $computer_id        = $self->data->get_computer_id;
+        my $computer_shortname = $self->data->get_computer_short_name;
+        my $computer_nodename  = $computer_shortname;
+        my $computer_hostname  = $self->data->get_computer_hostname;
+        my $computer_type      = $self->data->get_computer_type;
+
+        my $vmtype_name             = $self->data->get_vmhost_type_name;
+        my $vmhost_vmpath           = $self->data->get_vmhost_profile_vmpath;
+        my $vmprofile_vmdisk        = $self->data->get_vmhost_profile_vmdisk;
+        my $vmprofile_datastorepath = $self->data->get_vmhost_profile_datastore_path;
+        my $vmhost_hostname         = $self->data->get_vmhost_hostname;
+        my $host_type               = $self->data->get_vmhost_type;
+        my $vmhost_imagename        = $self->data->get_vmhost_image_name;
+
+        my $image_repository_path   = $self->_get_image_repository_path();
+	my $hostnodename = $vmhost_hostname;
+        # Assemble a consistent prefix for notify messages
+        my $notify_prefix = "req=$request_id, res=$reservation_id:";
+        my $image_filename;
+
+
+        # Print some preliminary information
+        notify($ERRORS{'OK'}, 0, "$notify_prefix new name: $image_name");
+        notify($ERRORS{'OK'}, 0, "$notify_prefix computer_name: $computer_shortname");
+        notify($ERRORS{'OK'}, 0, "$notify_prefix vmhost_hostname: $vmhost_hostname");
+        notify($ERRORS{'OK'}, 0, "$notify_prefix vmtype_name: $vmtype_name");
+
+        # Modify currentimage.txt
+        if (write_currentimage_txt($self->data)) {
+                notify($ERRORS{'OK'}, 0, "$notify_prefix currentimage.txt updated on $computer_shortname");
+        }
+        else {
+                notify($ERRORS{'WARNING'}, 0, "$notify_prefix unable to update currentimage.txt on $computer_shortname");
+                return 0;
+        }
+        my @sshcmd;
+
+        # Check if pre_capture() subroutine has been implemented by the OS module
+        if ($self->os->can("pre_capture")) {
+                # Call OS pre_capture() - it should perform all OS steps necessary to capture an image
+                # pre_capture() should shut down the computer when it is done
+                notify($ERRORS{'OK'}, 0, "calling OS module's pre_capture() subroutine");
+
+                if (!$self->os->pre_capture({end_state => 'off'})) {
+                        notify($ERRORS{'WARNING'}, 0, "OS module pre_capture() failed");
+                        return 0;
+                }
+
+                # Get the power status, make sure computer is off
+                my $power_status = $self->power_status();
+                notify($ERRORS{'DEBUG'}, 0, "retrieved power status: $power_status");
+                if ($power_status eq 'off') {
+                        notify($ERRORS{'OK'}, 0, "verified $computer_nodename power is off");
+                }
+                elsif ($power_status eq 'on') {
+                        notify($ERRORS{'WARNING'}, 0, "$computer_nodename power is still on, turning computer off");
+
+                        # Attempt to power off computer
+                        if ($self->power_off()) {
+                                notify($ERRORS{'OK'}, 0, "$computer_nodename was powered off");
+                        }
+                        else {
+                                notify($ERRORS{'WARNING'}, 0, "failed to power off $computer_nodename");
+                                return 0;
+                        }
+                }
+                else {
+                        notify($ERRORS{'WARNING'}, 0, "failed to determine power status of $computer_nodename");
+                        return 0;
+                }
+        }
+	
+        if ($vmprofile_vmdisk eq "localdisk") {
+                # copy vdi files
+                # confirm they were copied
+                notify($ERRORS{'OK'}, 0, "Removing VM");
+		if ($self->control_VM("remove")) {
+        	        notify($ERRORS{'OK'}, 0, "removed node $computer_shortname from vmhost $hostnodename");
+	        }
+
+                undef @sshcmd;
+        	@sshcmd = run_ssh_command($hostnodename, $management_node_keys, "ls $vmhost_vmpath/*_IMAGING_$computer_shortname.vdi", "root");
+	        for my $l (@{$sshcmd[1]}) {
+                	if ($l =~ /\/(.*_IMAGING_$computer_shortname\.vdi)/) {
+				$image_filename = $1;
+                        	notify($ERRORS{'OK'}, 0, "Image filename is: $image_filename");
+			}
+        	} ## end for my $l (@{$sshcmd[1]})
+
+                notify($ERRORS{'OK'}, 0, "attemping to copy vdi file to $image_repository_path");
+                if (run_scp_command("$hostnodename:\"$vmhost_vmpath/$image_filename\"", "$image_repository_path/$image_name", $management_node_keys)) {
+
+                # set file premissions on images to 644
+                # to allow for other management nodes to fetch image if neccessary
+                # useful in a large distributed framework
+                if (open(CHMOD, "/bin/chmod -R 644 $image_repository_path/$image_name 2>&1 |")) {
+                        close(CHMOD);
+                        notify($ERRORS{'DEBUG'}, 0, "$notify_prefix recursive update file permssions 644 on $image_repository_path/$image_name");
+                }
+		undef @sshcmd;
+                @sshcmd = run_ssh_command($hostnodename, $management_node_keys, "VBoxManage closemedium disk $vmhost_vmpath/$image_filename --delete", "root");
+                return 1;
+                } ## end if (run_scp_command("$hostnodename:\"$vmhost_vmpath/$vmx_directory/*.vmdk\""...
+                else {
+                        notify($ERRORS{'CRITICAL'}, 0, "failed to copy .vdi file to image repository");
+                        return 0;
+                }
+        } ## end if ($vmprofile_vmdisk eq "localdisk")
+
+
+} ## end sub capture
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 remove_snapshots
+
+ Parameters  : n/a
+ Returns     : 1 if sucessful, 0 if failed
+ Description : removes any unused snapshot hdds from specified host.
+
+=cut
+
+sub remove_snapshots { 
+	my $self = shift;
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+        my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+        my $hostnode = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+        my $management_node_keys = $self->data->get_management_node_keys();
+        my @sshcmd;
+        my @sshcmd2;
+        my $is_snapshot = 0;
+        my $delete_flag = 0;
+        my $current_uuid;
+	notify($ERRORS{'OK'}, 0, "Removing unused snapshots");
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list hdds | sed s/^\$/----/g", "root");
+	foreach my $l (@{$sshcmd[1]}) {
+        	if ($l =~ m/^UUID/) { # UUID line is the start of a section
+        	        $l =~ m/(........-....-....-....-............)/;
+			$current_uuid = $1;
+	        	notify($ERRORS{'OK'}, 0, "Checking hdd with UUID $1");
+                        $is_snapshot = 0; # reset this flag
+                        $delete_flag = 0; # reset this flag
+                }
+		if ($l =~ m/^Parent/) {
+			if ($l =~ m/Parent UUID: base/) { # This is a base image, not a snapshot
+				notify($ERRORS{'OK'}, 0, "UUID $current_uuid is not a snapshot");
+                        	$is_snapshot = 0; # Mark as a snapshot.
+                        	$delete_flag = 0; # Default is to remove this snapshot, unless it is found to be in use.
+			} else { # This is a snapshot
+				$l =~ m/(........-....-....-....-............)/;
+				notify($ERRORS{'OK'}, 0, "UUID $current_uuid is a snapshot of $1");
+                        	$is_snapshot = 1; # Mark as a snapshot.
+                        	$delete_flag = 1; # Default is to remove this snapshot, unless it is found to be in use.
+			}
+		}
+		if ($l =~ m/^Usage/) { # This image is still in use
+                        notify($ERRORS{'OK'}, 0, "UUID $current_uuid is in use, will not be removed");
+                        $delete_flag = 0; #Will not delete as this is still in use 
+                }
+                if ($l eq '----') { # end of one section, time to remove the image if it is an unused snapshot.
+			if ($is_snapshot && $delete_flag) {
+                        	notify($ERRORS{'OK'}, 0, "UUID $current_uuid is not in use, will be removed");
+        			@sshcmd2 = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q closemedium disk $current_uuid --delete", "root");
+			} 
+		}
+	}
+} ## end sub remove_snapshots 
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 controlVM
+
+ Parameters  : control command hash
+ Returns     : 0 or 1
+ Description : controls VM, stop,remove, etc
+
+=cut
+
+### This section will be next.
+
+sub control_VM {
+	my $self = shift;
+        my $ret = 0;
+
+	# Check if subroutine was called as a class method
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'DEBUG'}, 0, "subroutine was called as a function, it must be called as a class method");
+	}
+
+	my $control = shift;
+	#my (%vm) = shift;
+	#notify($ERRORS{'CRITICAL'}, 0, "debugging", %vm);
+
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	if (!(defined($control))) {
+		notify($ERRORS{'WARNING'}, 0, "control is not defined");
+		return 0;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "control $control is defined ");
+	}
+
+	# Store hash var into local var
+
+	my $shortname  = $self->data->get_computer_short_name;
+	my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+	my $hostnode    = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+	my $management_node_keys     = $self->data->get_management_node_keys();
+        my @sshcmd;
+
+	if ($control =~ /off|remove/) {
+        	undef @sshcmd;
+        	@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+        	foreach my $l (@{$sshcmd[1]}) {
+                	if ($l =~ m/\_$shortname\"/) {
+                        	$l =~ m/{(.*)}/;         
+                        	notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                        	notify($ERRORS{'OK'}, 0, "UUID  $1 - POWER OFF");
+                        	undef @sshcmd;
+                        	@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q controlvm $1 poweroff", "root");
+                                if ($control eq 'remove') {
+                        		notify($ERRORS{'OK'}, 0, "UUID  $1 - REMOVE");
+                        		undef @sshcmd;
+                        		@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q storagectl $1 --name $shortname\_stor --remove", "root");
+                        		undef @sshcmd;
+                        		@sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q unregistervm $1 --delete", "root");
+					$self->remove_snapshots();
+                                }
+                                $ret = 1;
+                	}
+        	}
+		
+	}
+        if ($control eq 'pause') {
+		undef @sshcmd;
+                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+                foreach my $l (@{$sshcmd[1]}) {
+                        if ($l =~ m/\_$shortname\"/) {
+                                $l =~ m/{(.*)}/;
+                                notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                                notify($ERRORS{'OK'}, 0, "UUID  $1 - PAUSE");
+                                undef @sshcmd;
+                                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q controlvm $1 pause", "root");
+			}
+		}
+	}
+        if ($control eq 'resume') {
+		undef @sshcmd;
+                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+                foreach my $l (@{$sshcmd[1]}) {
+                        if ($l =~ m/\_$shortname\"/) {
+                                $l =~ m/{(.*)}/;
+                                notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                                notify($ERRORS{'OK'}, 0, "UUID  $1 - RESUME");
+                                undef @sshcmd;
+                                @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q controlvm $1 resume", "root");
+			}
+		}
+	}
+
+	my $baseexists   = 0;
+	my $dirstructure = 0;
+	my $vmison       = 0;
+	return $ret;
+} ## end sub control_VM
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2  get_image_size
+
+ Parameters  : imagename
+ Returns     : 0 failure or size of image
+ Description : in size of Kilobytes
+
+=cut
+
+sub get_image_size {
+	my $self = shift;
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+
+	# Either use a passed parameter as the image name or use the one stored in this object's DataStructure
+	my $image_name = shift;
+	my $image_repository_path = $self->_get_image_repository_path();
+	$image_name = $self->data->get_image_name() if !$image_name;
+	if (!$image_name) {
+		notify($ERRORS{'CRITICAL'}, 0, "image name could not be determined");
+		return 0;
+	}
+	notify($ERRORS{'DEBUG'}, 0, "getting size of image: $image_name");
+	
+
+	my $IMAGEREPOSITORY = "$image_repository_path/$image_name";
+
+	#list files in image directory, account for main .gz file and any .gz.00X files
+	if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |")) {
+		my @filelist = <FILELIST>;
+		close(FILELIST);
+		my $size = 0;
+		foreach my $f (@filelist) {
+			if ($f =~ /$image_name.*vmdk/) {
+				my ($presize, $blah) = split(" ", $f);
+				$size += $presize;
+			}
+		}
+		if ($size == 0) {
+			#strange imagename not found
+			return 0;
+		}
+		return int($size / 1024);
+	} ## end if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |"...
+
+	return 0;
+} ## end sub get_image_size
+
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 node_status
+
+ Parameters  : $nodename, $log
+ Returns     : array of related status checks
+ Description : checks on ping,sshd, currentimage, OS
+
+=cut
+
+# This is where VBoxManage will need to be called, and the output parsed into useable data, currently always returning RELOAD to force the code into creating a new VM.
+
+sub node_status {
+        my $self = shift;
+
+        my $vmpath             = 0;
+        my $datastorepath      = 0;
+        my $requestedimagename = 0;
+        my $vmhost_type        = 0;
+        my $log                = 0;
+        my $vmhost_hostname    = 0;
+        my $vmhost_imagename   = 0;
+        my $vmclient_shortname = 0;
+        my $image_os_type      = 0;
+        my $request_forimaging = 0;
+        my $computer_node_name = 0;
+        my $identity_keys      = 0;
+
+	# Check if subroutine was called as a class method
+        if (ref($self) !~ /vbox/i) {
+                if (ref($self) eq 'HASH') {
+                        $log = $self->{logfile};
+                        #notify($ERRORS{'DEBUG'}, $log, "self is a hash reference");
+
+                        $computer_node_name = $self->{computer}->{hostname};
+                        $identity_keys      = $self->{managementnode}->{keys};
+                        $requestedimagename = $self->{imagerevision}->{imagename};
+                        $image_os_type      = $self->{image}->{OS}->{type};
+                        $vmhost_type        = $self->{vmhost}->{vmprofile}->{vmtype}->{name};
+                        $vmhost_imagename   = $self->{vmhost}->{imagename};
+                        $vmpath             = $self->{vmhost}->{vmprofile}->{vmpath};
+                        $datastorepath      = $self->{vmhost}->{vmprofile}->{datastorepath};
+                        $vmhost_hostname    = $self->{vmhost}->{hostname};
+
+                } ## end if (ref($self) eq 'HASH')
+                # Check if node_status returned an array ref
+                elsif (ref($self) eq 'ARRAY') {
+                        notify($ERRORS{'DEBUG'}, $log, "self is a array reference");
+                }
+
+                $vmclient_shortname = $1 if ($computer_node_name =~ /([-_a-zA-Z0-9]*)(\.?)/);
+
+        } ## end if (ref($self) !~ /vbox/i)
+        else {
+                # called as an object
+                # Collect local variables from DataStructure
+
+                $vmpath             = $self->data->get_vmhost_profile_vmpath;
+                $datastorepath      = $self->data->get_vmhost_profile_datastore_path;
+                $requestedimagename = $self->data->get_image_name;
+                $vmhost_type        = $self->data->get_vmhost_type;
+                $vmhost_hostname    = $self->data->get_vmhost_hostname;
+                $vmhost_imagename   = $self->data->get_vmhost_image_name;
+                $vmclient_shortname = $self->data->get_computer_short_name;
+                $image_os_type      = $self->data->get_image_os_type;
+                $request_forimaging = $self->data->get_request_forimaging();
+                $identity_keys      = $self->data->get_management_node_keys;
+        } ## end else [ if (ref($self) !~ /vbox/i)
+
+        notify($ERRORS{'DEBUG'}, $log, "identity_keys= $identity_keys");
+        notify($ERRORS{'DEBUG'}, $log, "requestedimagename= $requestedimagename");
+        notify($ERRORS{'DEBUG'}, $log, "image_os_type= $image_os_type");
+        notify($ERRORS{'DEBUG'}, $log, "request_forimaging= $request_forimaging");
+        notify($ERRORS{'DEBUG'}, $log, "vmpath= $vmpath");
+        notify($ERRORS{'DEBUG'}, $log, "datastorepath= $datastorepath");
+
+        # Create a hash to store status components
+        my %status;
+
+        # Initialize all hash keys here to make sure they're defined
+        $status{status}       = 0;
+        $status{currentimage} = 0;
+        $status{ping}         = 0;
+        $status{ssh}          = 0;
+        $status{vmstate}      = 0;    #on or off
+        $status{image_match}  = 0;
+
+        if (!$identity_keys) {
+                notify($ERRORS{'CRITICAL'}, $log, "could not set ssh identity variable for image $vmhost_imagename type= $vmhost_type host= $vmhost_hostname");
+        }
+
+        # Check if node is pingable
+        notify($ERRORS{'DEBUG'}, $log, "checking if $vmclient_shortname is pingable");
+        if (_pingnode($vmclient_shortname)) {
+                $status{ping} = 1;
+                notify($ERRORS{'OK'}, $log, "$vmclient_shortname is pingable ($status{ping})");
+        }
+        else {
+                notify($ERRORS{'OK'}, $log, "$vmclient_shortname is not pingable ($status{ping})");
+                $status{ping}         = 0;
+        }
+
+        my $mybasedirname = $requestedimagename;
+        my $myimagename   = $requestedimagename;
+
+        # #vm running
+        my @sshcmd = run_ssh_command($vmhost_hostname, $identity_keys, "VBoxManage -q showvminfo $requestedimagename\_$vmclient_shortname --machinereadable | grep VMState=", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+                notify($ERRORS{'OK'}, $log, "$l");
+                $status{vmstate} = "on"    if ($l =~ /running/);
+                $status{vmstate} = "off"   if ($l =~ /poweroff/);
+                $status{vmstate} = "stuck" if ($l =~ /paused/);
+                ##if ($l =~ /No such virtual machine/) {
+                ##        #ok wait something is using that hostname
+                ##        #reset $status{image_match} controlVM will detect and remove it
+                ##        $status{image_match} = 0;
+                ##}
+        } ## end foreach my $l (@{$sshcmd[1]})
+        notify($ERRORS{'OK'}, $log, "$vmclient_shortname vmstate reports $status{vmstate}");
+
+        #can I ssh into it
+        my $sshd = _sshd_status($vmclient_shortname, $requestedimagename, $image_os_type);
+
+        #is it running the requested image
+        if ($sshd eq "on") {
+
+                $status{ssh} = 1;
+
+                $status{currentimage} = _getcurrentimage($vmclient_shortname);
+
+                if ($status{currentimage}) {
+                        chomp($status{currentimage});
+                        if ($status{currentimage} =~ /$requestedimagename/) {
+                                $status{image_match} = 1;
+                                notify($ERRORS{'OK'}, $log, "$vmclient_shortname is loaded with requestedimagename $requestedimagename");
+                        }
+                        else {
+                                notify($ERRORS{'OK'}, $log, "$vmclient_shortname reports current image is currentimage= $status{currentimage} requestedimagename= $requestedimagename");
+                        }
+                } ## end if ($status{currentimage})
+        } ## end if ($sshd eq "on")
+
+
+        # Determine the overall machine status based on the individual status results
+        if ($status{ssh} && $status{image_match}) {
+                $status{status} = 'READY';
+        }
+        else {
+                $status{status} = 'RELOAD';
+        }
+
+        if ($request_forimaging) {
+                $status{status} = 'RELOAD';
+                notify($ERRORS{'OK'}, $log, "forimaging flag enabled RELOAD machine");
+        }
+
+        notify($ERRORS{'OK'}, $log, "returning node status hash reference (\$node_status->{status}=$status{status})");
+        return \%status;
+
+} ## end sub node_status
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 does_image_exist
+
+ Parameters  : imagename
+ Returns     : 0 or 1
+ Description : scans  our image local image library for requested image
+					returns 1 if found or 0 if not
+					attempts to scp image files from peer management nodes
+
+=cut
+
+sub does_image_exist {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+
+	# Get the image name, first try passed argument, then data
+	my $image_name = shift;
+	$image_name = $self->data->get_image_name() if !$image_name;
+	if (!$image_name) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine image name");
+		return;
+	}
+
+	# Get the image repository path
+	my $image_repository_path = $self->_get_image_repository_path();
+	if (!$image_repository_path) {
+		notify($ERRORS{'WARNING'}, 0, "image repository path could not be determined");
+		return;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "image repository path: $image_repository_path");
+	}
+	
+	# Run du to get the size of the image files if the image exists
+	my $du_command = "du -c $image_repository_path/*$image_name* 2>&1 | grep total 2>&1";
+	my ($du_exit_status, $du_output) = run_command($du_command);
+        notify($ERRORS{'OK'}, 0, "$du_command");
+	
+	# If the partner doesn't have the image, a "no such file" error should be displayed
+	my $image_files_exist;
+	if (defined(@$du_output) && grep(/no such file/i, @$du_output)) {
+		notify($ERRORS{'OK'}, 0, "$image_name does NOT exist");
+		$image_files_exist = 0;
+	}
+	elsif (defined(@$du_output) && !grep(/\d+\s+total/i, @$du_output)) {
+		notify($ERRORS{'WARNING'}, 0, "du output does not contain a total line:\n" . join("\n", @$du_output));
+		return;
+	}
+	elsif (!defined($du_exit_status)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to determine if image $image_name exists");
+		return;
+	}
+	
+	# Return 1 if the image size > 0
+	my ($image_size) = (@$du_output[0] =~ /(\d+)\s+total/);
+	if ($image_size && $image_size > 0) {
+		my $image_size_mb = int($image_size / 1024);
+		notify($ERRORS{'DEBUG'}, 0, "$image_name exists in $image_repository_path, size: $image_size_mb MB");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'DEBUG'}, 0, "image does NOT exist: $image_name");
+		return 0;
+	}
+
+} ## end sub does_image_exist
+	
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 retrieve_image
+
+ Parameters  :
+ Returns     :
+ Description : Attempts to retrieve an image from an image library partner
+
+=cut
+
+sub retrieve_image {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+
+	# Make sure image library functions are enabled
+	my $image_lib_enable = $self->data->get_management_node_image_lib_enable();
+	if (!$image_lib_enable) {
+		notify($ERRORS{'OK'}, 0, "image library functions are disabled");
+		return;
+	}
+
+	# If an argument was specified, use it as the image name
+	# If not, get the image name from the reservation data
+	my $image_name = shift || $self->data->get_image_name();
+	if (!$image_name) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine image name from argument or reservation data");
+		return;
+	}
+	
+	# Get the last digit of the reservation ID and sleep that number of seconds
+	# This is done in case 2 reservations for the same image were started at the same time
+	# Both may attempt to retrieve an image and execute the SCP command at nearly the same time
+	# does_image_exist() may not catch this and allow 2 SCP retrieval processes to start
+	# It's likely that the reservation IDs are consecutive and the the last digits will be different
+	my ($pre_retrieval_sleep) = $self->data->get_reservation_id() =~ /(\d)$/;
+	notify($ERRORS{'DEBUG'}, 0, "sleeping for $pre_retrieval_sleep seconds to prevent multiple SCP image retrieval processes");
+	sleep $pre_retrieval_sleep;
+	
+	# Make sure image does not already exist on this management node
+	if ($self->does_image_exist($image_name)) {
+		notify($ERRORS{'OK'}, 0, "$image_name already exists on this management node");
+		return 1;
+	}
+
+	# Get the image library partner string
+	my $image_lib_partners = $self->data->get_management_node_image_lib_partners();
+	if (!$image_lib_partners) {
+		notify($ERRORS{'WARNING'}, 0, "image library partners could not be determined");
+		return;
+	}
+	
+	# Split up the partner list
+	my @partner_list = split(/,/, $image_lib_partners);
+	if ((scalar @partner_list) == 0) {
+		notify($ERRORS{'WARNING'}, 0, "image lib partners variable is not listed correctly or does not contain any information: $image_lib_partners");
+		return;
+	}
+	
+	# Get the local image repository path
+	my $image_repository_path_local = $self->_get_image_repository_path();
+	if (!$image_repository_path_local) {
+		notify($ERRORS{'WARNING'}, 0, "image repository path could not be determined");
+		return;
+	}
+	
+	# Loop through the partners
+	# Find partners which have the image
+	# Check size for each partner
+	# Retrieve image from partner with largest image
+	# It's possible that another partner (management node) is currently copying the image from another managment node
+	# This should prevent copying a partial image
+	my $largest_partner;
+	my $largest_partner_hostname;
+	my $largest_partner_image_lib_user;
+	my $largest_partner_image_lib_key;
+	my $largest_partner_ssh_port;
+	my $largest_partner_path;
+	my $largest_partner_size = 0;
+	
+	notify($ERRORS{'OK'}, 0, "attempting to find another management node that contains $image_name");
+	foreach my $partner (@partner_list) {
+		# Get the connection information for the partner management node
+		my $partner_hostname = $self->data->get_management_node_hostname($partner) || '';
+		my $partner_image_lib_user = $self->data->get_management_node_image_lib_user($partner) || '';
+		my $partner_image_lib_key = $self->data->get_management_node_image_lib_key($partner) || '';
+		my $partner_ssh_port = $self->data->get_management_node_ssh_port($partner) || '';
+		my $image_repository_path_remote = $self->_get_image_repository_path($partner);
+		
+		notify($ERRORS{'OK'}, 0, "checking if $partner_hostname has image $image_name");
+		notify($ERRORS{'DEBUG'}, 0, "remote image repository path on $partner: $image_repository_path_remote");
+		
+		# Run du to get the size of the image files on the partner if the image exists
+		my ($du_exit_status, $du_output) = run_ssh_command($partner, $partner_image_lib_key, "du -c $image_repository_path_remote/*$image_name* | grep total", $partner_image_lib_user, $partner_ssh_port, 1);
+		
+		# If the partner doesn't have the image, a "no such file" error should be displayed
+		if (defined(@$du_output) && grep(/no such file/i, @$du_output)) {
+			notify($ERRORS{'OK'}, 0, "$image_name does NOT exist on $partner_hostname");
+			next;
+		}
+		elsif (defined(@$du_output) && !grep(/\d+\s+total/i, @$du_output)) {
+			notify($ERRORS{'WARNING'}, 0, "du output does not contain a total line:\n" . join("\n", @$du_output));
+			next;
+		}
+		elsif (!defined($du_exit_status)) {
+			notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to determine if image $image_name exists on $partner_hostname");
+			next;
+		}
+		
+		# Extract the image size in bytes from the du total output line
+		my ($partner_image_size) = (@$du_output[0] =~ /(\d+)\s+total/);
+		notify($ERRORS{'OK'}, 0, "$image_name exists on $partner_hostname, size: $partner_image_size bytes");
+		
+		# Check if the image size is larger than any previously found, if so, save the partner info
+		if ($partner_image_size > $largest_partner_size) {
+			$largest_partner = $partner;
+			$largest_partner_hostname = $partner_hostname;
+			$largest_partner_size = $partner_image_size;
+			$largest_partner_image_lib_user = $partner_image_lib_user;
+			$largest_partner_image_lib_key = $partner_image_lib_key;
+			$largest_partner_ssh_port = $partner_ssh_port;
+			$largest_partner_path = $image_repository_path_remote;
+		}
+	}
+	
+	# Check if any partner was found
+	if (!$largest_partner) {
+		notify($ERRORS{'WARNING'}, 0, "unable to find $image_name on other management nodes");
+		return;
+	}
+	
+	# Attempt copy
+	notify($ERRORS{'OK'}, 0, "attempting to retrieve $image_name from $largest_partner_hostname");
+	if (run_scp_command("$largest_partner_image_lib_user\@$largest_partner:$largest_partner_path/$image_name*", $image_repository_path_local, $largest_partner_image_lib_key, $largest_partner_ssh_port)) {
+		notify($ERRORS{'OK'}, 0, "image $image_name was copied from $largest_partner_hostname");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to copy image $image_name from $largest_partner_hostname");
+		return 0;
+	}
+	
+	# Make sure image was copied
+	if (!$self->does_image_exist($image_name)) {
+		notify($ERRORS{'WARNING'}, 0, "$image_name was not copied to this management node");
+		return 0;
+	}
+
+	return 1;
+} ## end sub retrieve_image
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _get_image_repository_path
+
+ Parameters  : none, must be called as an object method
+ Returns     :
+ Description :
+
+=cut
+
+sub _get_image_repository_path {
+	my $self = shift;
+
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+
+	my $return_path = "/install";
+	return $return_path;
+} ## end sub _get_image_repository_path
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 put_node_in_maintenance
+
+ Parameters  : none, must be called as an object method
+ Returns     :  1,0
+ Description : preforms any actions on node before putting in maintenance state
+
+=cut
+
+sub post_maintenance_action {
+	my $self = shift;
+
+	if (ref($self) !~ /vbox/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+
+	#steps putting vm into maintenance
+	# check state of vm
+	# turn off if needed
+	# unregister
+	# remove vm machine directory from vmx path
+	# set vmhostid to null in computer table - handled in new.pm
+
+	my $computer_short_name   = $self->data->get_computer_short_name;
+	my $computer_id = $self->data->get_computer_id();
+	my $vmhost_hostname = $self->data->get_vmhost_hostname;
+
+	if ($self->control_VM("remove")) {
+		notify($ERRORS{'OK'}, 0, "removed node $computer_short_name from vmhost $vmhost_hostname");
+	}
+
+	if (switch_vmhost_id($computer_id, 'NULL')) {
+                notify($ERRORS{'OK'}, 0, "set vmhostid to NULL for for VM $computer_short_name");
+        }
+        else {
+                notify($ERRORS{'WARNING'}, 0, "failed to set the vmhostid to NULL for VM $computer_short_name");
+                return;
+        }
+
+	return 1;
+
+} ## end sub post_maintenance_action
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 power_on
+
+ Parameters  : 
+ Returns     : 
+ Description : 
+
+=cut
+
+sub power_on {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+	
+	## Get necessary data
+        my $shortname  = $self->data->get_computer_short_name;
+        my $vmhost_hostname    = $self->data->get_vmhost_hostname();
+        my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+        my $hostnode = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+        my $management_node_keys = $self->data->get_management_node_keys();
+        my @sshcmd;
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+                if ($l =~ m/\_$shortname\"/) {
+                        $l =~ m/{(.*)}/;
+                        notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                        notify($ERRORS{'OK'}, 0, "UUID  $1 - POWERON");
+                        undef @sshcmd;
+                        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q  startvm $1 --type headless", "root");
+                }
+        }
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 power_off
+
+ Parameters  : 
+ Returns     : 
+ Description : 
+
+=cut
+
+sub power_off {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+	
+	## Get necessary data
+        my $shortname  = $self->data->get_computer_short_name;
+	my $vmhost_hostname    = $self->data->get_vmhost_hostname();
+        my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+        my $hostnode = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+        my $management_node_keys = $self->data->get_management_node_keys();
+        my @sshcmd;
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+       		if ($l =~ m/\_$shortname\"/) {
+                	$l =~ m/{(.*)}/;
+                        notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                        notify($ERRORS{'OK'}, 0, "UUID  $1 - POWEROFF");
+                        undef @sshcmd;
+                        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q controlvm $1 poweroff", "root");
+                }
+        }
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 power_reset
+
+ Parameters  : 
+ Returns     : 
+ Description : 
+
+=cut
+
+sub power_reset {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+	
+	## Get necessary data
+	my $shortname  = $self->data->get_computer_short_name;
+        my $vmhost_hostname    = $self->data->get_vmhost_hostname();
+        my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+        my $hostnode = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+        my $management_node_keys = $self->data->get_management_node_keys();
+        my @sshcmd;
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+                if ($l =~ m/\_$shortname\"/) {
+                        $l =~ m/{(.*)}/;
+                        notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                        notify($ERRORS{'OK'}, 0, "UUID  $1 - RESET");
+                        undef @sshcmd;
+                        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q controlvm $1 reset", "root");
+                }
+        }
+        
+
+        return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 power_status
+
+ Parameters  : 
+ Returns     : If successful: string containing "on", "off", "suspended", or "stuck"
+               If failed: undefined
+ Description : 
+ 
+
+=cut
+
+sub power_status {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
+		return;	
+	}
+	## Get necessary data
+        my $shortname  = $self->data->get_computer_short_name;
+        my $vmhost_hostname    = $self->data->get_vmhost_hostname();
+        my $vmhost_fullhostname = $self->data->get_vmhost_hostname;
+        my $hostnode = $1 if ($vmhost_fullhostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
+        my $management_node_keys = $self->data->get_management_node_keys();
+        my @sshcmd;
+        my $vm_uuid;
+        my $vm_status = "UNKNOWN";
+        undef @sshcmd;
+        @sshcmd = run_ssh_command($hostnode, $management_node_keys, "VBoxManage -q list vms", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+                if ($l =~ m/\_$shortname\"/) {
+                        $l =~ m/{(.*)}/;
+                        notify($ERRORS{'OK'}, 0, "VM $shortname has UUID  $1");
+                        $vm_uuid = $1;
+                }
+        }
+
+	undef @sshcmd;
+	@sshcmd = run_ssh_command($vmhost_hostname, $management_node_keys, "VBoxManage -q showvminfo $vm_uuid --machinereadable | grep VMState=", "root");
+        foreach my $l (@{$sshcmd[1]}) {
+                $vm_status = "on"    if ($l =~ /running/);
+                $vm_status = "off"   if ($l =~ /poweroff/);
+                $vm_status = "stuck" if ($l =~ /paused/);
+        } ## end foreach my $l (@{$sshcmd[1]})
+        notify($ERRORS{'OK'}, 0, "$shortname vmstate reports $vm_status");
+	
+        return $vm_status;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 SEE ALSO
+
+L<http://cwiki.apache.org/VCL/>
+
+=cut