Author: arkurth
Date: Fri Aug  6 19:38:53 2010
New Revision: 983104

URL: http://svn.apache.org/viewvc?rev=983104&view=rev
Log:
VCL-289
Created Provisioning.pm::retrieve_image subroutine based on the code from the 
existing xCAT and VMware modules.  Added Semaphore.pm which contains code to 
create an exclusively locked file and Module.pm::get_semaphore for easy 
access/creation.  The retrieve_image subroutine creates a Semaphore object 
before retrieving an image from another management node.  This ensures that 
only 1 retrieval for a given image happens at a time.  Added 
get_image_repository_path and get_image_repository_search_paths subroutines to 
VMware.pm allowing it to use the new retrieve_image subroutine.  Also removed 
get_lockfile and release_lockfile from VMware.pm. They were put there during 
development.

VCL-100
Updated Linux.pm::get_file_size to return the bytes actually used rather than 
the apparent size of a file.  This allows an accurate size to be returned when 
checking the size of thin vmdk files whose different size values may differ 
widely.

VCL-298
Updated VMware.pm:
Modified is_vm_persistent to return true if the reservation end time is more 
than 24 hours in the future.
Updated in get_image_size so that it works correctly if an image name is passed 
as an argument. This is done by image.pm.
Fixed bug in get_vm_disk_adapter_type.  It was returning IDE if using ESX in 
some situations which doesn't work.

Other
Made minor change to OS.pm::is_ssh_responding so that it doesn't rely on the 
exit status of the SSH command.
In utils.pm::run_ssh_command, added '2>&1' so it is applied to both the remote 
command being run and the local SSH command.  This should allow STDOUT and 
STDERR output to be captured and synchronized.

Added:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm   (with 
props)
Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning.pm
    
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
    incubator/vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module.pm Fri Aug  6 19:38:53 
2010
@@ -86,6 +86,7 @@ use English '-no_match_vars';
 
 use VCL::utils qw($SETUP_MODE $VERBOSE %ERRORS &notify &getnewdbh format_data);
 use VCL::DataStructure;
+use VCL::Module::Semaphore;
 
 ##############################################################################
 
@@ -130,10 +131,10 @@ sub new {
        my $args  = shift;
 
        notify($ERRORS{'DEBUG'}, 0, "constructor called, class=$class");
-
+       
        # Create a variable to store the newly created class object
        my $class_object;
-
+       
        # Make sure the data structure was passed as an argument called 
'data_structure'
        if (!defined $args->{data_structure}) {
                notify($ERRORS{'CRITICAL'}, 0, "required 'data_structure' 
argument was not passed");
@@ -145,7 +146,7 @@ sub new {
                notify($ERRORS{'CRITICAL'}, 0, "'data_structure' argument 
passed is not a reference to a VCL::DataStructure object");
                return;
        }
-
+       
        # Add the DataStructure reference to the class object
        $class_object->{data} = $args->{data_structure};
 
@@ -334,7 +335,7 @@ sub get_package_hierarchy {
 
 sub code_loop_timeout {
        my $self = shift;
-       if (ref($self) !~ /VCL::Module/i) {
+       unless (ref($self) && $self->isa('VCL::Module')) {
                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
                return;
        }
@@ -422,6 +423,82 @@ sub code_loop_timeout {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_semaphore
+
+ Parameters  : $file_path, $total_wait_seconds (optional), 
$attempt_delay_seconds (optional)
+ Returns     : VCL::Module::Semaphore object
+ Description : This subroutine is used to ensure that only 1 process performs a
+               particular task at a time. An example would be the retrieval of
+               an image from another management node. If multiple reservations
+               are being processed for the same image, each reservation may
+               attempt to retrieve it via SCP at the same time. This subroutine
+               can be used to only allow 1 process to retrieve the image. The
+               others will wait until the semaphore is released by the
+               retrieving process.
+               
+               Attempts to open and obtain an exclusive lock on the file
+               specified by the file path argument. If unable to obtain an
+               exclusive lock, it will wait up to the value specified by the
+               total wait seconds argument (default: 30 seconds). The number of
+               seconds to wait in between retries can be specified (default: 15
+               seconds).
+               
+               A semaphore object is returned. The exclusive lock will be
+               retained as long as the semaphore object remains defined. Once
+               undefined, the exclusive lock is released and the file is
+               deleted.
+               
+               Examples:
+               
+               Semaphore is released when it is undefined:
+               my $semaphore = $self->get_semaphore('/tmp/test.lock');
+               ... <exclusive lock is in place>
+               undef $semaphore;
+               ... <exclusive lock released>
+               
+               Semaphore is released when it goes out of scope:
+               if (blah) {
+                  my $semaphore = $self->get_semaphore('/tmp/test.lock');
+                  ... <exclusive lock is in place>
+               }
+               ... <exclusive lock released>
+
+=cut
+
+sub get_semaphore {
+       my $self = shift;
+       unless (ref($self) && $self->isa('VCL::Module')) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the file path argument
+       my ($file_path, $total_wait_seconds, $attempt_delay_seconds) = @_;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
supplied");
+               return;
+       }
+       
+       # Attempt to create a new semaphore object
+       my $semaphore = VCL::Module::Semaphore->new({'data_structure' => 
$self->data});
+       if (!$semaphore) {
+               notify($ERRORS{'WARNING'}, 0, "failed to create semaphore 
object");
+               return;
+       }
+       
+       # Attempt to open and exclusively lock the file
+       if ($semaphore->get_lockfile($file_path, $total_wait_seconds, 
$attempt_delay_seconds)) {
+               # Return the semaphore object
+               return $semaphore;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "failed to open and optain 
exclusive lock on file: $file_path");
+               return;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS.pm Fri Aug  6 19:38:53 
2010
@@ -426,7 +426,7 @@ sub is_ssh_responding {
        });
        
        # The exit status will be 0 if the command succeeded
-       if (defined($exit_status) && $exit_status == 0) {
+       if (defined($output) && grep(/testing/, @$output)) {
                notify($ERRORS{'DEBUG'}, 0, "$computer_node_name is responding 
to SSH, port 22: $port_22_status, port 24: $port_24_status");
                return 1;
        }

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Fri Aug  6 
19:38:53 2010
@@ -1859,7 +1859,7 @@ sub get_file_size {
        my $computer_node_name = $self->data->get_computer_node_name() || 
return;
        
        # Run stat rather than du because du is not available on VMware ESX
-       my $command = 'stat -c "%F:%s:%n" ' . $escaped_file_path;
+       my $command = 'stat -c "%F:%s:%b:%B:%n" ' . $escaped_file_path;
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to 
determine file size on $computer_node_name: $file_path\ncommand: $command");
@@ -1871,23 +1871,25 @@ sub get_file_size {
        }
        
        # Loop through the stat output lines
-       my $total_bytes = 0;
+       my $total_bytes_used = 0;
+       my $total_bytes_allocated = 0;
        for my $line (@$output) {
                # Take the stat output line apart
-               my ($type, $file_bytes, $path) = split(/:/, $line);
-               if (!defined($type) || !defined($file_bytes) || 
!defined($path)) {
+               my ($type, $file_bytes, $file_blocks, $block_size, $path) = 
split(/:/, $line);
+               if (!defined($type) || !defined($file_bytes) || 
!defined($file_blocks) || !defined($block_size) || !defined($path)) {
                        notify($ERRORS{'WARNING'}, 0, "unexpected output 
returned from stat, line: $line\ncommand: $command\noutput:\n" . join("\n", 
@$output));
                        return;
                }
                
                # Add the size to the total if the type is file
                if ($type =~ /file/) {
-                       $total_bytes += $file_bytes;
+                       $total_bytes_used += ($file_blocks * $block_size);
+                       $total_bytes_allocated += $file_bytes;
                }
        }
        
-       notify($ERRORS{'DEBUG'}, 0, "size of $file_path on $computer_node_name: 
" . format_number($total_bytes) . " bytes");
-       return $total_bytes;
+       notify($ERRORS{'DEBUG'}, 0, "size of $file_path on $computer_node_name: 
" . format_number($total_bytes_used) . " bytes, (" . 
format_number($total_bytes_allocated) . " bytes allocated)");
+       return $total_bytes_used;
 }
 
 #/////////////////////////////////////////////////////////////////////////////

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning.pm Fri Aug  
6 19:38:53 2010
@@ -140,6 +140,182 @@ sub vmhost_os {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 retrieve_image
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Retrieves an image from another management node.
+
+=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 retrieval skipped, image 
library functions are disabled for this management node");
+               return;
+       }
+
+       # Get the image name from the reservation data
+       my $image_name = $self->data->get_image_name();
+       if (!$image_name) {
+               notify($ERRORS{'WARNING'}, 0, "failed to determine image name 
from 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;
+       
+       # Get a semaphore so only 1 process is able to retrieve the image at a 
time
+       # Do this before checking if the image exists in case another process 
is retrieving the image
+       my $semaphore = $self->get_semaphore("/tmp/retrieve_$image_name.lock", 
(60 * 15)) || return;
+       
+       # 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, "unable to determine the local 
image repository path");
+               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 %partner_info;
+       my $largest_partner_image_size = 0;
+       my @partners_with_image;
+       
+       foreach my $partner (@partner_list) {
+               # Get the connection information for the partner management node
+               $partner_info{$partner}{hostname} = 
$self->data->get_management_node_hostname($partner);
+               $partner_info{$partner}{user} = 
$self->data->get_management_node_image_lib_user($partner) || 'root';
+               $partner_info{$partner}{identity_key} = 
$self->data->get_management_node_image_lib_key($partner) || '';
+               $partner_info{$partner}{port} = 
$self->data->get_management_node_ssh_port($partner) || '22';
+               
+               # Call the provisioning module's 
get_image_repository_search_paths() subroutine
+               # This returns an array of strings to pass to du
+               $partner_info{$partner}{search_paths} = 
[$self->get_image_repository_search_paths($partner)];
+               if (!$partner_info{$partner}{search_paths}) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to retrieve image 
repository search paths for partner: $partner");
+                       next;
+               }
+               
+               # Run du to get the size of the image files on the partner if 
the image exists in any of the search paths
+               my $du_command = "du -b " . join(" ", 
@{$partner_info{$partner}{search_paths}});
+               my ($du_exit_status, $du_output) = run_ssh_command($partner, 
$partner_info{$partner}{identity_key}, $du_command, 
$partner_info{$partner}{user}, $partner_info{$partner}{port}, 0);
+               if (!defined($du_output)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to run SSH 
command to determine if image $image_name exists on 
$partner_info{$partner}{hostname}");
+                       next;
+               }
+               
+               # Loop through the du output lines, parse lines beginning with 
a number followed by a '/'
+               for my $line (@$du_output) {
+                       my ($file_size, $file_path) = $line =~ 
/^(\d+)\s+(\/.+)/;
+                       next if (!defined($file_size) || !defined($file_path));
+                       $partner_info{$partner}{file_paths}{$file_path} = 
$file_size;
+                       $partner_info{$partner}{image_size} += $file_size;
+               }
+               
+               # Display the image size if any files were found
+               if ($partner_info{$partner}{image_size}) {
+                       notify($ERRORS{'OK'}, 0, "$image_name exists on 
$partner_info{$partner}{hostname}, size: " . 
format_number($partner_info{$partner}{image_size}) . " bytes");
+               }
+               else {
+                       notify($ERRORS{'OK'}, 0, "$image_name does NOT exist on 
$partner_info{$partner}{hostname}");
+                       next;
+               }
+
+               # Check if the image size is larger than any previously found 
on other partners
+               if ($partner_info{$partner}{image_size} > 
$largest_partner_image_size) {
+                       @partners_with_image = ();
+               }
+               
+               # Check if the image size is larger than any previously found 
on other partners
+               if ($partner_info{$partner}{image_size} >= 
$largest_partner_image_size) {
+                       push @partners_with_image, $partner;
+                       $largest_partner_image_size = 
$partner_info{$partner}{image_size};
+               }
+       }
+       
+       # Check if any partner was found
+       if (!...@partners_with_image) {
+               notify($ERRORS{'WARNING'}, 0, "unable to find $image_name on 
other management nodes");
+               return;
+       }
+       
+       notify($ERRORS{'OK'}, 0, "found $image_name on partner management 
nodes:\n" . join("\n", map { $partner_info{$_}{hostname} } (sort 
@partners_with_image)));
+       
+       # Choose a random partner so that the same management node isn't used 
for most transfers
+       my $random_index = int(rand(scalar(@partners_with_image)));
+       my $retrieval_partner = $partners_with_image[$random_index];
+       notify($ERRORS{'OK'}, 0, "selected random retrieval partner: 
$partner_info{$retrieval_partner}{hostname}");
+       
+       # Create the directory in the image repository
+       my $mkdir_command = "mkdir -pv $image_repository_path_local";
+       my ($mkdir_exit_status, $mkdir_output) = run_command($mkdir_command);
+       if (!defined($mkdir_output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to run command to create 
image repository directory: $mkdir_command");
+               return;
+       }
+       
+       # Copy each file path to the image repository directory
+       notify($ERRORS{'OK'}, 0, "attempting to retrieve $image_name from 
$partner_info{$retrieval_partner}{hostname}");
+       for my $partner_file_path (sort keys 
%{$partner_info{$retrieval_partner}{file_paths}}) {
+               my ($file_name) = $partner_file_path =~ /([^\/]+)$/;
+               if 
(run_scp_command("$partner_info{$retrieval_partner}{use...@$retrieval_partner:$partner_file_path",
 "$image_repository_path_local/$file_name", 
$partner_info{$retrieval_partner}{key}, 
$partner_info{$retrieval_partner}{port})) {
+               notify($ERRORS{'OK'}, 0, "image $image_name was copied from 
$partner_info{$retrieval_partner}{hostname}");
+               }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "failed to copy image 
$image_name from $partner_info{$retrieval_partner}{hostname}");
+                       return;
+               }
+       }
+       
+       # Make sure image was retrieved
+       if (!$self->does_image_exist($image_name)) {
+               notify($ERRORS{'WARNING'}, 0, "does_image_exist subroutine 
returned false for $image_name after it should have been retrieved");
+               return;
+       }
+       
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

Modified: 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm 
(original)
+++ 
incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm 
Fri Aug  6 19:38:53 2010
@@ -276,6 +276,9 @@ sub initialize {
        # Store the VM host API object in this object
        $self->{api} = $vmware_api;
        
+       # Make sure the VMware product name can be retrieved
+       $self->get_vmhost_product_name() || return;
+       
        # Make sure the vmx and vmdk base directories can be accessed
        my $vmx_base_directory_path = $self->get_vmx_base_directory_path() || 
return;
        if (!$vmhost_os->file_exists($vmx_base_directory_path)) {
@@ -461,9 +464,6 @@ sub capture {
                sleep 5;
        }
        
-       ## Get a lockfile so that only 1 process is operating on VM host files 
at any one time
-       #my $lockfile = $self->get_lockfile("/tmp/$vmhost_hostname.lock", (60 * 
10)) || return;
-       
        # Rename the vmdk files on the VM host and change the vmdk directory 
name to the image name
        # This ensures that the vmdk and vmx files now reside in different 
directories
        #   so that the vmdk files can't be deleted when the vmx directory is 
deleted later on
@@ -1997,13 +1997,77 @@ sub get_vmdk_file_path {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_image_repository_path
+
+ Parameters  : $management_node_identifier (optional)
+ Returns     : 
+ Description :
+
+=cut
+
+sub get_image_repository_path {
+       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;
+       }
+       
+       return $self->get_repository_vmdk_directory_path();
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_image_repository_search_paths
+
+ Parameters  : 
+ Returns     : 
+ Description : 
+
+=cut
+
+sub get_image_repository_search_paths {
+       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 $management_node_identifier = shift || 
$self->data->get_management_node_hostname();
+       
+       my $image_name = $self->data->get_image_name();
+       
+       my @repository_search_paths;
+       
+       if (my $vmhost_profile_repository_path = 
$self->data->get_vmhost_profile_repository_path()) {
+               push @repository_search_paths, 
"$vmhost_profile_repository_path/$image_name/$image_name*.vmdk";
+       }
+       
+       if (my $management_node_install_path = 
$self->data->get_management_node_install_path($management_node_identifier)) {
+               push @repository_search_paths, 
"$management_node_install_path/vmware_images/$image_name/$image_name*.vmdk";
+               push @repository_search_paths, 
"$management_node_install_path/$image_name/$image_name*.vmdk";
+       }
+       
+       push @repository_search_paths, 
"/install/vmware_images/$image_name/$image_name*.vmdk";
+       
+       my %seen;
+       @repository_search_paths = grep { !$seen{$_}++ } 
@repository_search_paths; 
+       #notify($ERRORS{'DEBUG'}, 0, "repository search paths on 
$management_node_identifier:\n" . join("\n", @repository_search_paths));
+       return @repository_search_paths;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 get_repository_vmdk_base_directory_path
 
  Parameters  : none
  Returns     : string
  Description : Returns the image repository directory path on the management
-               node under which the vmdk directories for all of the images
-               reside.  The preferred database value to use is 
vmprofile.repositorypath. If this is not available, managementnode.installpath 
is retrieved and "/vmware_images" is appended. If this is not available, 
"/install/vmware
+                                       node under which the vmdk directories 
for all of the images
+                                       reside. The preferred database value to 
use is
+                                       vmprofile.repositorypath. If this is 
not available,
+                                       managementnode.installpath is retrieved 
and "/vmware_images" is
+                                       appended. If this is not available, 
"/install/vmware_images" is
+                                       returned.
                                        Example:
                repository vmdk file path: 
/install/vmware_images/vmwarewinxp-base234-v12/vmwarewinxp-base234-v12.vmdk
                repository vmdk base directory path: /install/vmware_images
@@ -2018,9 +2082,6 @@ sub get_repository_vmdk_base_directory_p
                return;
        }
        
-       # Return the path stored in this object if it has already been 
determined
-       return $self->{repository_base_directory_path} if (defined 
$self->{repository_base_directory_path});
-       
        my $repository_vmdk_base_directory_path;
        
        # Attempt the retrieve vmhost.repositorypath
@@ -2037,9 +2098,7 @@ sub get_repository_vmdk_base_directory_p
                notify($ERRORS{'WARNING'}, 0, "unable to retrieve repository 
path from VM profile or management node install path, returning 
'/install/vmware_images'");
        }
        
-       # Set a value in this object so this doesn't have to be retrieved more 
than once
-       $self->{repository_base_directory_path} = 
$repository_vmdk_base_directory_path;
-       return $self->{repository_base_directory_path};
+       return $repository_vmdk_base_directory_path;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2098,7 +2157,8 @@ sub get_repository_vmdk_file_path {
  Parameters  : none
  Returns     : boolean
  Description : Determines if a VM should be persistent or not based on whether
-               or not the reservation is an imaging reservation.
+               or not the reservation is an imaging reservation or if the end
+               time is more than 24 hours in the future.
 
 =cut
 
@@ -2113,9 +2173,17 @@ sub is_vm_persistent {
        if ($request_forimaging) {
                return 1;
        }
-       else {
-               return 0;
+       
+       # Return true if the request end time is more than 24 hours in the 
future
+       my $end_epoch = 
convert_to_epoch_seconds($self->data->get_request_end_time());
+       my $now_epoch = time();
+       my $end_hours = (($end_epoch - $now_epoch) / 60 / 60);
+       if ($end_hours >= 24) {
+               notify($ERRORS{'DEBUG'}, 0, "request end time is " . 
format_number($end_hours, 1) . " hours in the future, returning true");
+               return 1;
        }
+       
+       return 0;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2158,7 +2226,7 @@ sub is_vm_registered {
 
 =head2 get_image_size
 
- Parameters  : $vmdk_file_path (optional)
+ Parameters  : $image_name (optional)
  Returns     : integer
  Description : Returns the size of the image in bytes. If the vmdk file path
                argument is not supplied and the VM disk type in the VM profile
@@ -2176,73 +2244,67 @@ sub get_image_size {
        }
        
        my $vmhost_hostname = $self->data->get_vmhost_hostname() || return;
-       my $vmprofile_vmdisk = $self->data->get_vmhost_profile_vmdisk() || 
return;
-       my $image_name = $self->data->get_image_name() || return;
        
-       # Attempt to get the vmdk file path argument
-       # If not supplied, use the default vmdk file path for this reservation
-       my $vmdk_file_path = shift;
-       
-       # Try to retrieve the image size from the repository if an argument was 
not supplied and localdisk is being used
-       if (!$vmdk_file_path && $vmprofile_vmdisk eq "localdisk") {
-               my $repository_vmdk_directory_path = 
$self->get_repository_vmdk_directory_path() || return;
-               notify($ERRORS{'DEBUG'}, 0, "vm disk type is $vmprofile_vmdisk, 
checking size of vmdk directory in image repository: 
$repository_vmdk_directory_path");
+       # Attempt to get the image name argument
+       my $image_name = shift;
+       if (!$image_name) {
+               $image_name = $self->data->get_image_name() || return;
+       }
+       
+       my $image_size_bytes;
+       
+       # Try to retrieve the image size from the repository if localdisk is 
being used
+       if (my $repository_vmdk_base_directory_path = 
$self->get_repository_vmdk_base_directory_path()) {
+               
+               my $search_path = 
"$repository_vmdk_base_directory_path/$image_name/$image_name*.vmdk";
+               
+               notify($ERRORS{'DEBUG'}, 0, "checking size of image in image 
repository: $search_path");
                
                # Run du specifying image repository directory as an argument
-               my ($exit_status, $output) = run_command("du -bc 
\"$repository_vmdk_directory_path\"", 1);
+               my ($exit_status, $output) = run_command("du -bc $search_path", 
1);
                if (!defined($output)) {
-                       notify($ERRORS{'WARNING'}, 0, "failed to run command to 
determine size of vmdk directory in image repository: 
$repository_vmdk_directory_path");
+                       notify($ERRORS{'WARNING'}, 0, "failed to run command to 
determine size of image in image repository: $search_path");
+               }
+               elsif (grep(/no such file/i, @$output)) {
+                       notify($ERRORS{'DEBUG'}, 0, "image does not exist in 
image repository");
                }
                elsif (grep(/du: /i, @$output)) {
-                       notify($ERRORS{'WARNING'}, 0, "error occurred 
attempting to determine size of vmdk directory in image repository: 
$repository_vmdk_directory_path, output:\n" . join("\n", @$output));
+                       notify($ERRORS{'WARNING'}, 0, "error occurred 
attempting to determine size of image in image repository: $search_path, 
output:\n" . join("\n", @$output));
                }
-               else {
-                       my ($total_line) = grep(/total/, @$output);
-                       if (!$total_line) {
-                               notify($ERRORS{'WARNING'}, 0, "unable to locate 
'total' line in du output while attempting to determine size of vmdk directory 
in image repository: $repository_vmdk_directory_path, output:\n" . join("\n", 
@$output));
+               elsif (my ($total_line) = grep(/total/, @$output)) {
+                       ($image_size_bytes) = $total_line =~ /(\d+)/;
+                       if (defined($image_size_bytes)) {
+                               notify($ERRORS{'DEBUG'}, 0, "retrieved size of 
image in image repository: $image_size_bytes");
                        }
                        else {
-                               my ($bytes_used) = $total_line =~ /(\d+)/;
-                               if ($bytes_used =~ /^\d+$/) {
-                                       my $mb_used = 
format_number(($bytes_used / 1024 / 1024), 1);
-                                       my $gb_used = 
format_number(($bytes_used / 1024 / 1024 / 1024), 2);
-                                       notify($ERRORS{'DEBUG'}, 0, "size of 
$image_name image in image repository: " . format_number($bytes_used) . " bytes 
($mb_used MB, $gb_used GB)");
-                                       return $bytes_used;
-                               }
-                               else {
-                                       notify($ERRORS{'WARNING'}, 0, "failed 
to parse du output to determine size of vmdk directory in image repository: 
$repository_vmdk_directory_path, output:\n" . join("\n", @$output));
-                                       return;
-                               }
+                               notify($ERRORS{'WARNING'}, 0, "failed to parse 
du output to determine size of vmdk directory in image repository: 
$search_path, output:\n" . join("\n", @$output));
                        }
                }
+               else {
+                       notify($ERRORS{'WARNING'}, 0, "unable to locate 'total' 
line in du output while attempting to determine size of vmdk directory in image 
repository: $search_path, output:\n" . join("\n", @$output));
+               }
        }
        
-       # Get the vmdk file path if not specified as an argument
-       if (!$vmdk_file_path) {
-               $vmdk_file_path = $self->get_vmdk_file_path() || return;
-       }
-       
-       # Extract the directory path and file prefix from the vmdk file path
-       my ($vmdk_directory_path, $vmdk_file_prefix) = $vmdk_file_path =~ 
/^(.+)\/([^\/]+)\.vmdk$/;
-       if (!$vmdk_directory_path || !$vmdk_file_prefix) {
-               notify($ERRORS{'WARNING'}, 0, "unable to determine vmdk 
directory path and vmdk file prefix from vmdk file path: $vmdk_file_path");
-               return;
+       # Unable to determine the image size from the image repository, attempt 
to retrieve size from VM host
+       if (!defined($image_size_bytes)) {
+               # Assemble a search path
+               my $vmdk_base_directory_path = 
$self->get_vmdk_base_directory_path() || return;
+               my $search_path = 
"$vmdk_base_directory_path/$image_name/$image_name*.vmdk";
+               
+               # Get the size of the files on the VM host
+               $image_size_bytes = 
$self->vmhost_os->get_file_size($search_path);
        }
        
-       # Assemble a search path
-       my $vmdk_search_path = "$vmdk_directory_path/$vmdk_file_prefix*.vmdk";
        
-       # Get the size of the files on the VM host
-       my $vmdk_size = $self->vmhost_os->get_file_size($vmdk_search_path);
-       if (!defined($vmdk_size)) {
-               notify($ERRORS{'WARNING'}, 0, "unable to determine the size of 
vmdk file on VM host $vmhost_hostname:
-                        vmdk file path: $vmdk_file_path
-                        search path: $vmdk_search_path");
+       if (!defined($image_size_bytes)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to determine the size of 
image in image repository or on VM host");
                return;
        }
        
-       notify($ERRORS{'DEBUG'}, 0, "size of $image_name image on VM host 
$vmhost_hostname: " . format_number($vmdk_size) . " bytes");
-       return $vmdk_size;
+       my $mb_used = format_number(($image_size_bytes / 1024 / 1024));
+       my $gb_used = format_number(($image_size_bytes / 1024 / 1024 / 1024), 
2);
+       notify($ERRORS{'DEBUG'}, 0, "size of $image_name image: " . 
format_number($image_size_bytes) . " bytes ($mb_used MB, $gb_used GB)");
+       return $image_size_bytes;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2414,15 +2476,15 @@ sub get_vm_disk_adapter_type {
        my $vm_host_product_name = $self->get_vmhost_product_name() || return;
        
        my $vmdk_controller_type;
-       if ($self->api->can("get_virtual_disk_controller_type")) {
-               $vmdk_controller_type = 
$self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path());
+       
+       if ($self->api->can("get_virtual_disk_controller_type") && 
($vmdk_controller_type = 
$self->api->get_virtual_disk_controller_type($self->get_vmdk_file_path()))) {
                notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter type 
from api object: $vmdk_controller_type");
        }
        elsif ($vmdk_controller_type = 
$self->get_vmdk_parameter_value('adapterType')) {
                notify($ERRORS{'DEBUG'}, 0, "retrieved VM disk adapter type 
from vmdk file: $vmdk_controller_type");
        }
-       elsif (!$vmdk_controller_type || ($vm_host_product_name =~ /esx/i && 
$vmdk_controller_type =~ /ide/i)) {
-               
+       
+       if (!$vmdk_controller_type || ($vm_host_product_name =~ /esx/i && 
$vmdk_controller_type =~ /ide/i)) {
                my $vm_os_configuration = $self->get_vm_os_configuration();
                if (!$vm_os_configuration) {
                        notify($ERRORS{'WARNING'}, 0, "unable to determine VM 
disk adapter type because unable to retrieve default VM OS configuration");
@@ -2622,113 +2684,6 @@ sub get_vm_ram {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_lockfile
-
- Parameters  : $file_path, $total_wait_seconds (optional), 
$attempt_delay_seconds (optional)
- Returns     : filehandle
- Description : Attempts to open and obtain an exclusive lock on the file
-               specified by the file path argument. If unable to obtain an
-               exclusive lock, it will wait up to the value specified by the
-               total wait seconds argument (default: 30 seconds). The number of
-               seconds to wait in between retries can be specified (default: 15
-               seconds).
-
-=cut
-
-sub get_lockfile {
-       my $self = shift;
-       if (ref($self) !~ /Module/i) {
-               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
-               return;
-       }
-       
-       # Get the file path argument
-       my ($file_path, $total_wait_seconds, $attempt_delay_seconds) = @_;
-       if (!$file_path) {
-               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
supplied");
-               return;
-       }
-       
-       # Set the wait defaults if not supplied as arguments
-       $total_wait_seconds = 30 if !$total_wait_seconds;
-       $attempt_delay_seconds = 5 if !$attempt_delay_seconds;
-       
-       # Attempt to open the file
-       notify($ERRORS{'DEBUG'}, 0, "attempting to open file to be exclusively 
locked: $file_path");
-       my $file_handle = new IO::File($file_path, O_RDONLY | O_CREAT);
-       if (!$file_handle) {
-               notify($ERRORS{'WARNING'}, 0, "failed to open file to be 
exclusively locked: $file_path, reason: $!");
-               return;
-       }
-       my $fileno = $file_handle->fileno;
-       notify($ERRORS{'DEBUG'}, 0, "opened file to be exclusively locked: 
$file_path");
-       
-       # Store the fileno and path in %ENV so we can retrieve the path later on
-       $ENV{fileno}{$fileno} = $file_path;
-       
-       # Attempt to lock the file
-       my $wait_message = "attempting to obtain lock on file: $file_path";
-       if ($self->code_loop_timeout(sub{flock($file_handle, LOCK_EX|LOCK_NB)}, 
[], $wait_message, $total_wait_seconds, $attempt_delay_seconds)) {
-               notify($ERRORS{'DEBUG'}, 0, "obtained an exclusive lock on 
file: $file_path");
-       }
-       else {
-               notify($ERRORS{'DEBUG'}, 0, "failed to obtain lock on file: 
$file_path");
-               return;
-       }
-       
-       # Store the file handle as a variable and return it
-       return $file_handle;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
-=head2 release_lockfile
-
- Parameters  : $file_handle
- Returns     : boolean
- Description : Closes the lockfile handle specified by the argument.
-
-=cut
-
-sub release_lockfile {
-       my $self = shift;
-       if (ref($self) !~ /Module/i) {
-               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
-               return;
-       }
-       
-       # Get the file handle argument
-       my ($file_handle) = @_;
-       if (!$file_handle) {
-               notify($ERRORS{'WARNING'}, 0, "file handle argument was not 
supplied");
-               return;
-       }
-       
-       # Make sure the file handle is opened
-       my $fileno = $file_handle->fileno;
-       if (!$fileno) {
-               notify($ERRORS{'WARNING'}, 0, "file handle is not opened");
-               return;
-       }
-       
-       # Get the file path previously stored in %ENV
-       my $file_path = $ENV{fileno}{$fileno} || 'unknown';
-       
-       # Close the file
-       if (close($file_handle)) {
-               notify($ERRORS{'DEBUG'}, 0, "closed file handle: $file_path");
-       }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "failed to close file handle: 
$file_path, reason: $!");
-               return;
-       }
-       
-       delete $ENV{fileno}{$fileno};
-       return 1;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 get_vmx_file_paths
 
  Parameters  : none

Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm?rev=983104&view=auto
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm (added)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Semaphore.pm Fri Aug  6 
19:38:53 2010
@@ -0,0 +1,281 @@
+#!/usr/bin/perl -w
+###############################################################################
+# $Id$
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+=head1 NAME
+
+VCL::Module::Semaphore - VCL module to control semaphores
+
+=head1 SYNOPSIS
+
+ my $semaphore = VCL::Module::Semaphore->new({data_structure => $self->data});
+ $semaphore->get_lockfile($file_path, $total_wait_seconds, 
$attempt_delay_seconds);
+
+=head1 DESCRIPTION
+
+ A semaphore is used to ensure that only 1 process performs a particular task 
at
+ a time. An example would be the retrieval of an image from another management
+ node. If multiple reservations are being processed for the same image, each
+ reservation may attempt to retrieve it via SCP at the same time. A
+ VCL::Module::Semaphore can be used to only allow 1 process to retrieve the
+ image. The others will wait until the semaphore is released by the retrieving
+ process.
+
+=cut
+
+##############################################################################
+package VCL::Module::Semaphore;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/../..";
+
+# Configure inheritance
+use base qw(VCL::Module);
+
+# Specify the version of this module
+our $VERSION = '2.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+use English qw( -no_match_vars );
+use IO::File;
+use Fcntl qw(:DEFAULT :flock);
+
+use VCL::utils;
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_lockfile
+
+ Parameters  : $file_path, $total_wait_seconds (optional), 
$attempt_delay_seconds (optional)
+ Returns     : filehandle
+ Description : Attempts to open and obtain an exclusive lock on the file
+               specified by the file path argument. If unable to obtain an
+               exclusive lock, it will wait up to the value specified by the
+               total wait seconds argument (default: 30 seconds). The number of
+               seconds to wait in between retries can be specified (default: 15
+               seconds).
+
+=cut
+
+sub get_lockfile {
+       my $self = shift;
+       unless (ref($self) && $self->isa('VCL::Module')) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the file path argument
+       my ($file_path, $total_wait_seconds, $attempt_delay_seconds) = @_;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
supplied");
+               return;
+       }
+       
+       # Set the wait defaults if not supplied as arguments
+       $total_wait_seconds = 30 if !$total_wait_seconds;
+       $attempt_delay_seconds = 5 if !$attempt_delay_seconds;
+       
+       # Attempt to lock the file
+       my $wait_message = "attempting to open lockfile";
+       if ($self->code_loop_timeout(\&open_lockfile, [$self, $file_path], 
$wait_message, $total_wait_seconds, $attempt_delay_seconds)) {
+               return $file_path;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "failed to open lockfile: 
$file_path");
+               return;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 open_lockfile
+
+ Parameters  : $file_path
+ Returns     : If successful: IO::File file handle object
+               If failed: false
+ Description : Opens and obtains an exclusive lock on the file specified by the
+               argument.
+
+=cut
+
+sub open_lockfile {
+       my $self = shift;
+       unless (ref($self) && $self->isa('VCL::Module')) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the file path argument
+       my ($file_path) = @_;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
supplied");
+               return;
+       }
+       
+       # Attempt to open and lock the file
+       if (my $file_handle = new IO::File($file_path, O_WRONLY|O_CREAT)) {
+               if (flock($file_handle, LOCK_EX | LOCK_NB)) {
+                       notify($ERRORS{'DEBUG'}, 0, "opened and obtained an 
exclusive lock on file: $file_path");
+                       
+                       # Truncate and print the process information to the file
+                       $file_handle->truncate(0);
+                       print $file_handle "$$ $0\n";
+                       
+                       $self->{file_handles}{$file_path} = $file_handle;
+                       return $file_handle;
+               }
+               else {
+                       notify($ERRORS{'DEBUG'}, 0, "unable to obtain exclusive 
lock on file: $file_path");
+                       $file_handle->close;
+               }
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to open file: $file_path, 
error:\n$!");
+               return;
+       }
+       
+       # Run lsof to determine which process is locking the file
+       my ($exit_status, $output) = run_command("lsof -Fp $file_path", 1);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to run losf command to 
determine which process is locking the file: $file_path");
+               return;
+       }
+       elsif (grep(/no such file/i, @$output)) {
+               notify($ERRORS{'WARNING'}, 0, "losf command reports that the 
file does not exist: $file_path");
+               return;
+       }
+       
+       # Parse the lsof output to determine the PID
+       my @locking_pids = map { /^p(\d+)/ } @$output;
+       if (@locking_pids && grep { $_ eq $PID } @locking_pids) {
+               # The current process already has an exclusive lock on the file
+               # This could happen if open_lockfile is called more than once 
for the same file in the same scope
+               notify($ERRORS{'WARNING'}, 0, "file is already locked by this 
process: @locking_pids");
+               return;
+       }
+       elsif (@locking_pids) {
+               notify($ERRORS{'DEBUG'}, 0, "file is locked by another process: 
@locking_pids");
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "unable to determine PIDs from lsof 
output\n:" . join("\n", @$output));
+       }
+       
+       return 0;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 release_lockfile
+
+ Parameters  : $file_path
+ Returns     : boolean
+ Description : Releases the exclusive lock and closes the lockfile handle
+               specified by the argument.
+
+=cut
+
+sub release_lockfile {
+       my $self = shift;
+       unless (ref($self) && $self->isa('VCL::Module')) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       # Get the file path argument
+       my $file_path = shift;
+       if (!$file_path) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
supplied");
+               return;
+       }
+       
+       my $file_handle = $self->{file_handles}{$file_path};
+       if (!$file_handle) {
+               notify($ERRORS{'WARNING'}, 0, "file handle is not saved in this 
object for file path: $file_path");
+               return;
+       }
+       
+       # Make sure the file handle is opened
+       my $fileno = $file_handle->fileno;
+       if (!$fileno) {
+               notify($ERRORS{'WARNING'}, 0, "file is not opened: $file_path");
+       }
+       
+       # Close the file
+       if (!close($file_handle)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to close file: 
$file_path, reason: $!");
+       }
+       
+       # Delete the file
+       if (unlink($file_path)) {
+               notify($ERRORS{'DEBUG'}, 0, "deleted file: $file_path");
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "failed to delete file: 
$file_path, reason: $!");
+       }
+       
+       delete $self->{file_handles}{$file_path};
+       return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 DESTROY
+
+ Parameters  : none
+ Returns     : nothing
+ Description : Destroys the semaphore object. The files opened and exclusively
+               locked by the semaphore object are closed and deleted.
+
+=cut
+
+sub DESTROY {
+       my $self = shift;
+       notify($ERRORS{'DEBUG'}, 0, "destructor called: $self");
+       
+       for my $file_path (keys %{$self->{file_handles}}) {
+               $self->release_lockfile($file_path);
+       }
+       
+       # Check for an overridden destructor
+       $self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
+} ## end sub DESTROY
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 SEE ALSO
+
+L<http://cwiki.apache.org/VCL/>
+
+=cut

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

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

Modified: incubator/vcl/trunk/managementnode/lib/VCL/utils.pm
URL: 
http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=983104&r1=983103&r2=983104&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/utils.pm Fri Aug  6 19:38:53 2010
@@ -5404,11 +5404,8 @@ sub run_ssh_command {
        # -p <port>, Port to connect to on the remote host.
        # -x, Disables X11 forwarding.
        # Dont use: -q, Quiet mode.  Causes all warning and diagnostic messages 
to be suppressed.
-       my $ssh_command = "$ssh_path $identity_paths -l $user -p $port -x $node 
'$command'";
-
-       # Redirect standard output and error output so all messages are captured
-       $ssh_command .= ' 2>&1';
-
+       my $ssh_command = "$ssh_path $identity_paths -l $user -p $port -x $node 
'$command 2>&1' 2>&1";
+       
        # Execute the command
        my $ssh_output;
        my $ssh_output_formatted;
@@ -5443,10 +5440,10 @@ sub run_ssh_command {
                else {
                        notify($ERRORS{'DEBUG'}, 0, "attempt 
$attempts/$max_attempts: executing SSH command on $node:\n$ssh_command") if 
$output_level;
                }
-
+               
                # Execute the command
                $ssh_output = `$ssh_command`;
-               
+
                # Bits 0-7 of $? are set to the signal the child process 
received that caused it to die
                my $signal_number = $? & 127;
                


Reply via email to