Author: arkurth
Date: Tue Jul 20 16:59:39 2010
New Revision: 965909

URL: http://svn.apache.org/viewvc?rev=965909&view=rev
Log:
VCL-298
Made several changes to Linux.pm to allow the various Linux OS commands to work 
under ESXi via SSH. There are several commands which aren't available under 
ESXi such as du. The commands which are supported usually allow only basic 
arguments and switches.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm

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=965909&r1=965908&r2=965909&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Tue Jul 20 
16:59:39 2010
@@ -1420,32 +1420,37 @@ sub file_exists {
        # Escape all spaces in the path
        my $escaped_path = escape_file_path($path);
        
-       # Copy the path and replace any *'s with .* to be used with grep
-       # This string will be used to check the output
-       my $grep_path = $escaped_path;
-       $grep_path =~ s/\*/\.\*/g;
-       
        my $computer_short_name = $self->data->get_computer_short_name();
        
        # Check if the file or directory exists
        # Do not enclose the path in quotes or else wildcards won't work
-       my $command = "ls -1d $escaped_path";
+       my $command = "stat $escaped_path";
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to 
determine if file or directory exists on $computer_short_name:\npath: 
'$path'\ncommand: '$command'");
                return;
        }
-       elsif (my @matching_file_paths = grep(/^$grep_path/i, @$output)) {
-               notify($ERRORS{'DEBUG'}, 0, "file or directory exists on 
$computer_short_name: '$path', matching paths:\n" . join("\n", 
@matching_file_paths));
-               return 1;
+       elsif (grep(/no such file/i, @$output)) {
+               notify($ERRORS{'DEBUG'}, 0, "file or directory does not exist 
on $computer_short_name: '$path'");
+               return 0;
        }
-       elsif (grep(/ls: /i, @$output) && !grep(/no such file/i, @$output)) {
+       elsif (grep(/stat: /i, @$output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to determine if file or 
directory exists on $computer_short_name:\npath: '$path'\ncommand: 
'$command'\nexit status: $exit_status, output:\n" . join("\n", @$output));
                return;
        }
+       
+       # Count the lines beginning with "Size:" and ending with "file", 
"directory", or "link" to determine how many files and/or directories were found
+       my $files_found = grep(/^\s*Size:.*file$/i, @$output);
+       my $directories_found = grep(/^\s*Size:.*directory$/i, @$output);
+       my $links_found = grep(/^\s*Size:.*link$/i, @$output);
+       
+       if ($files_found || $directories_found || $links_found) {
+               notify($ERRORS{'DEBUG'}, 0, "'$path' exists on 
$computer_short_name, files: $files_found, directories: $directories_found, 
links: $links_found");
+               return 1;
+       }
        else {
-               notify($ERRORS{'DEBUG'}, 0, "file or directory does NOT exist 
on $computer_short_name: '$path'");
-               return 0;
+               notify($ERRORS{'WARNING'}, 0, "unexpected output returned while 
attempting to determine if file or directory exists on $computer_short_name: 
'$path'\ncommand: '$command'\nexit status: $exit_status, output:\n" . 
join("\n", @$output));
+               return;
        }
 }
 
@@ -1488,24 +1493,30 @@ sub delete_file {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to delete 
file or directory on $computer_short_name:\npath: '$path'\ncommand: 
'$command'");
                return;
        }
-       elsif (!grep(/rm: /i, @$output) && (my @file_paths_deleted = 
grep(/^removed/i, @$output))) {
-               @file_paths_deleted = map { $_ =~ /removed \W(.*)\W$/} 
@file_paths_deleted;
-               notify($ERRORS{'OK'}, 0, "deleted '$path' on 
$computer_short_name, files or directories deleted: " . 
scalar(@file_paths_deleted) . "\n" . join("\n", @file_paths_deleted));
-       }
        elsif (grep(/(cannot access|no such file)/i, @$output)) {
                notify($ERRORS{'OK'}, 0, "file or directory not deleted because 
it does not exist on $computer_short_name: $path");
        }
-       else {
+       elsif (grep(/rm: /i, @$output)) {
                notify($ERRORS{'WARNING'}, 0, "error occurred attempting to 
delete file or directory on $computer_short_name: '$path':\ncommand: 
'$command'\nexit status: $exit_status\noutput:\n" . join("\n", @$output));
        }
+       else {
+               notify($ERRORS{'OK'}, 0, "deleted '$path' on 
$computer_short_name");
+       }
        
        # Make sure the path does not exist
-       my $host_file_exists = $self->file_exists($path);
-       if (!defined($host_file_exists)) {
+       my $file_exists = $self->file_exists($path);
+       if (!defined($file_exists)) {
                notify($ERRORS{'WARNING'}, 0, "failed to confirm file doesn't 
exist on $computer_short_name: '$path'");
                return;
        }
-       return !$host_file_exists;
+       elsif ($file_exists) {
+               notify($ERRORS{'WARNING'}, 0, "file was not deleted, it still 
exists on $computer_short_name: '$path'");
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "confirmed file does not exist on 
$computer_short_name: '$path'");
+               return 1;
+       }
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1515,9 +1526,7 @@ sub delete_file {
  Parameters  : $directory_path, $mode (optional)
  Returns     : boolean
  Description : Creates a directory on the Linux computer as indicated by the
-               $directory_path argument. A 2nd argument specifying the file 
mode
-               (as in chmod) can be specified. The default file mode is 755
-               (drwxr-xr-x).
+               $directory_path argument.
 
 =cut
 
@@ -1538,28 +1547,25 @@ sub create_directory {
        # Remove any quotes from the beginning and end of the path
        $directory_path = normalize_file_path($directory_path);
        
-       # Get the mode argument or set the default value
-       my $mode = shift || 755;
-       
        my $computer_short_name = $self->data->get_computer_short_name();
        
        # Attempt to create the directory
-       my $command = "mkdir -p -v --mode=$mode \"$directory_path\" 2>&1 && ls 
-1d \"$directory_path\"";
+       my $command = "mkdir -p \"$directory_path\" 2>&1 && ls -1d 
\"$directory_path\"";
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to create 
directory on $computer_short_name:\npath: '$directory_path'\ncommand: 
'$command'");
                return;
        }
        elsif (grep(/created directory/i, @$output)) {
-               notify($ERRORS{'OK'}, 0, "created directory on 
$computer_short_name: '$directory_path', mode: $mode");
+               notify($ERRORS{'OK'}, 0, "created directory on 
$computer_short_name: '$directory_path'");
                return 1;
        }
-       elsif (grep(/mkdir: /i, @$output)) {
+       elsif (grep(/(mkdir|ls):/i, @$output)) {
                notify($ERRORS{'WARNING'}, 0, "error occurred attempting to 
create directory on $computer_short_name: '$directory_path':\ncommand: 
'$command'\nexit status: $exit_status\noutput:\n" . join("\n", @$output));
                return;
        }
        elsif (grep(/^$directory_path/, @$output)) {
-               notify($ERRORS{'OK'}, 0, "directory already exists on 
$computer_short_name: '$directory_path'");
+               notify($ERRORS{'OK'}, 0, "directory either created or already 
exists on $computer_short_name: '$directory_path'");
                return 1;
        }
        else {
@@ -1604,7 +1610,7 @@ sub move_file {
        my $computer_short_name = $self->data->get_computer_short_name();
        
        # Execute the command to move the file
-       my $command = "mv -fv $escaped_source_path $escaped_destination_path";
+       my $command = "mv -f $escaped_source_path $escaped_destination_path";
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to move 
file on $computer_short_name:\nsource path: '$source_path'\ndestination path: 
'$destination_path'\ncommand: '$command'");
@@ -1614,16 +1620,10 @@ sub move_file {
                notify($ERRORS{'WARNING'}, 0, "failed to move file on 
$computer_short_name:\nsource path: '$source_path'\ndestination path: 
'$destination_path'\ncommand: '$command'\noutput:\n" . join("\n", @$output));
                return;
        }
-       elsif (grep(/->/i, @$output)) {
+       else {
                notify($ERRORS{'OK'}, 0, "moved file on 
$computer_short_name:\n'$source_path' --> '$destination_path'");
                return 1;
        }
-       else {
-               notify($ERRORS{'WARNING'}, 0, "unexpected output returned from 
command to move file on $computer_short_name:\nsource path: 
'$source_path'\ndestination path: '$destination_path'\ncommand: 
'$command'\noutput:\n" . join("\n", @$output));
-               return;
-       }
-       
-       return 1;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1676,9 +1676,11 @@ sub get_file_contents {
 =head2 get_available_space
 
  Parameters  : none
- Returns     : integer
+ Returns     : If successful: integer
+               If failed: undefined
  Description : Returns the bytes available in the path specified by the
-               argument.
+               argument. 0 is returned if no space is available. Undefined is
+               returned if an error occurred.
 
 =cut
 
@@ -1698,38 +1700,44 @@ sub get_available_space {
        
        my $computer_short_name = $self->data->get_computer_short_name();
        
-       # Run df specifying the path as an argument if specified
-       my $command = "df \"$path\"";
+       # Run stat -f specifying the path as an argument
+       # Don't use df because you can't specify a path under ESX and parsing 
would be difficult
+       my $command = "stat -f \"$path\"";
        my ($exit_status, $output) = $self->execute($command);
-       return if !defined($output);
-       
-       if (grep(/^df: /i, @$output)) {
-               notify($ERRORS{'WARNING'}, 0, "error occurred running df 
command on $computer_short_name:\n" . join("\n", @$output));
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to run command to 
determine available space on $computer_short_name:\ncommand: 
$command\noutput:\n" . join("\n", @$output));
                return;
        }
-       
-       my @path_lines = grep(!/^Filesystem/i, @$output);
-       if (scalar(@path_lines) == 0) {
-               notify($ERRORS{'WARNING'}, 0, "unable to find filesystem data 
line in df output:\n" . join("\n", @$output));
+       elsif (grep(/^stat: /i, @$output)) {
+               notify($ERRORS{'WARNING'}, 0, "error occurred running command 
to determine available space on $computer_short_name\ncommand: 
$command\noutput:\n" . join("\n", @$output));
                return;
        }
-       elsif (scalar(@path_lines) > 1) {
-               notify($ERRORS{'WARNING'}, 0, "found multiple filesystem data 
lines in df output:\n" . join("\n", @$output));
+       
+       # Create an output string from the array of lines for easier regex 
parsing
+       my $output_string = join("\n", @$output);
+       
+       # Extract the block size value
+       # Search case sensitive for 'Block size:' because the line may also 
contain "Fundamental block size:"
+       my ($block_size) = $output_string =~ /Block size: (\d+)/;
+       if (!$block_size) {
+               notify($ERRORS{'WARNING'}, 0, "unable to locate 'Block size:' 
value in stat output:\ncommand: $command\noutput:\n" . join("\n", @$output));
                return;
        }
        
-       my ($filesystem, $blocks_total, $blocks_used, $blocks_available, 
$percent_used, $mounted_on) = split(/\s+/, $path_lines[0]);
-       if (!$mounted_on) {
-               notify($ERRORS{'WARNING'}, 0, "failed to parse df output 
line:\n$path_lines[0]\noutput:\n" . join("\n", @$output));
+       # Extract the blocks free value
+       my ($blocks_free) = $output_string =~ /Blocks:[^\n]*Free: (\d+)/;
+       if (!$blocks_free) {
+               notify($ERRORS{'WARNING'}, 0, "unable to locate blocks free 
value in stat output:\ncommand: $command\noutput:\n" . join("\n", @$output));
                return;
        }
        
-       my $bytes_available = ($blocks_available * 1024);
-       my $mb_available = format_number(($bytes_available / 1024 / 1024), 2);
-       my $gb_available = format_number(($bytes_available / 1024 / 1024 / 
1024), 1);
+       # Calculate the bytes free
+       my $bytes_free = ($block_size * $blocks_free);
+       my $mb_free = format_number(($bytes_free / 1024 / 1024), 2);
+       my $gb_free = format_number(($bytes_free / 1024 / 1024 / 1024), 1);
        
-       notify($ERRORS{'DEBUG'}, 0, "bytes available in '$path' on 
$computer_short_name: " . format_number($bytes_available) . " bytes 
($mb_available MB, $gb_available GB)");
-       return $bytes_available;
+       notify($ERRORS{'DEBUG'}, 0, "bytes free in '$path' on 
$computer_short_name: " . format_number($bytes_free) . " bytes ($mb_free MB, 
$gb_free GB)");
+       return $bytes_free;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -1885,7 +1893,7 @@ sub copy_file {
        my $computer_node_name = $self->data->get_computer_node_name();
        
        # Execute the command to copy the file
-       my $command = "cp -fvr $escaped_source_path $escaped_destination_path";
+       my $command = "cp -fr $escaped_source_path $escaped_destination_path";
        notify($ERRORS{'DEBUG'}, 0, "attempting to copy file on 
$computer_node_name: '$source_file_path' -> '$destination_file_path'");
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
@@ -1896,7 +1904,7 @@ sub copy_file {
                notify($ERRORS{'WARNING'}, 0, "failed to copy file on 
$computer_node_name:\nsource path: '$source_file_path'\ndestination path: 
'$destination_file_path'\ncommand: '$command'\noutput:\n" . join("\n", 
@$output));
                return;
        }
-       elsif (grep(/->/i, @$output)) {
+       elsif (!...@$output || grep(/->/i, @$output)) {
                notify($ERRORS{'OK'}, 0, "copied file on $computer_node_name: 
'$source_file_path' --> '$destination_file_path'");
                return 1;
        }
@@ -1914,9 +1922,9 @@ sub copy_file {
 
  Parameters  : $file_path
  Returns     : integer
- Description : Determines the size of the file or directory specified by the
-               file path argument in bytes. The file path argument may be a
-               directory path or contain wildcards.
+ Description : Determines the size of the file specified by the file path
+               argument in bytes. The file path argument may contain wildcards.
+                                       If the path argument is a directory, 0 
will be returned.
 
 =cut
 
@@ -1943,38 +1951,36 @@ sub get_file_size {
        # Get the computer name
        my $computer_node_name = $self->data->get_computer_node_name() || 
return;
        
-       # Run du specifying the path as an argument
-       my $command = "du -bc $escaped_file_path";
+       # Run stat rather than du because du is not available on VMware ESX
+       my $command = 'stat -c "%F:%s:%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");
                return;
        }
-       elsif (grep(/^du: /i, @$output)) {
+       elsif (grep(/^stat:/i, @$output)) {
                notify($ERRORS{'WARNING'}, 0, "error occurred attempting to 
determine file size on $computer_node_name: $file_path\ncommand: 
$command\noutput:\n" . join("\n", @$output));
                return;
        }
        
-       # Find the line containing 'total'
-       my ($total_line) = grep(/total/, @$output);
-       if (!$total_line) {
-               notify($ERRORS{'WARNING'}, 0, "unable to find total line in du 
output on $computer_node_name: $file_path, output:\n" . join("\n", @$output));
-               return;
-       }
-       
-       # Extract the blocks used number from the total line
-       my ($bytes_used) = $total_line =~ /(\d+)/g;
-       if (!defined($bytes_used) || length($bytes_used) == 0) {
-               notify($ERRORS{'WARNING'}, 0, "unable to determine bytes used 
from the total line in du output on $computer_node_name: $file_path\ncommand: 
$command\ntotal line: $total_line\noutput:\n" . join("\n", @$output));
-               return;
+       # Loop through the stat output lines
+       my $total_bytes = 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)) {
+                       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;
+               }
        }
        
-       my $kb_used = ($bytes_used / 1024);
-       my $mb_used = ($bytes_used / 1024 / 1024);
-       my $gb_used = ($bytes_used / 1024 / 1024 / 1024);
-       
-       notify($ERRORS{'DEBUG'}, 0, "size of $file_path: " . 
format_number($bytes_used) . " bytes (" . format_number($kb_used, 2) . " KB, " 
. format_number($mb_used, 2) . " MB, " . format_number($gb_used, 2) . " GB)");
-       return $bytes_used;
+       notify($ERRORS{'DEBUG'}, 0, "size of $file_path on $computer_node_name: 
" . format_number($total_bytes) . " bytes");
+       return $total_bytes;
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -2007,11 +2013,16 @@ sub find_files {
        $base_directory_path = normalize_file_path($base_directory_path);
        $file_pattern = normalize_file_path($file_pattern);
        
+       # The base directory path must have a trailing slash or find won't work
+       $base_directory_path .= '/';
+       
        # Get the computer short and hostname
        my $computer_node_name = $self->data->get_computer_node_name() || 
return;
        
        # Run the find command
        my $command = "find \"$base_directory_path\" -type f -iname 
\"$file_pattern\"";
+       notify($ERRORS{'DEBUG'}, 0, "attempting to find files on 
$computer_node_name, base directory path: '$base_directory_path', pattern: 
$file_pattern, command: $command");
+       
        my ($exit_status, $output) = $self->execute($command);
        if (!defined($output)) {
                notify($ERRORS{'WARNING'}, 0, "failed to run command to find 
files on $computer_node_name, base directory path: '$base_directory_path', 
pattern: $file_pattern, command:\n$command");
@@ -2023,7 +2034,9 @@ sub find_files {
        }
        
        # Return the file list
-       return @$output;
+       my @file_paths = @$output;
+       notify($ERRORS{'DEBUG'}, 0, "matching file count: " . 
scalar(@file_paths));
+       return @file_paths;
 }
        
 #/////////////////////////////////////////////////////////////////////////////


Reply via email to