Author: arkurth
Date: Wed Feb 11 00:03:26 2015
New Revision: 1658846

URL: http://svn.apache.org/r1658846
Log:
VCL-815
Reworked OS.pm::update_cluster. Each reservation now only creates a 
cluster_info file for itself. The firewall processes was also improved to be 
much more efficient.

Fixed problem with Windows code which creates the cluster_info file. The line 
endings were not Windows-style because the sed command in 
OS.pm::set_text_file_line_endings was failing. Sed under Cygwin can't handle a 
Windows-style file path if the "-i" switch is used. Added 
get_cygwin_unix_file_path subroutine. This gets called and the result gets 
passed to set_text_file_line_endings.

Other
Cleaned up and renamed Windows.pm::get_cygwin_path --> 
get_cygwin_installation_directory_path. It was messy. There were notify 
messages obviously copied/pasted from another subroutine which made no sense. 
Its name had also become vague with the addition of get_cygwin_unix_file_path, 
both of which call cygpath.exe.

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

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=1658846&r1=1658845&r2=1658846&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS.pm Wed Feb 11 00:03:26 2015
@@ -930,7 +930,7 @@ sub is_ssh_responding {
                notify($ERRORS{'DEBUG'}, 0, "$computer_node_name is NOT 
responding to SSH, ports 22 or 24 are both closed");
                return 0;
        }
-       
+
        if ($max_attempts) {
                # Run a test SSH command
                #my ($exit_status, $output) = $self->execute({
@@ -2255,7 +2255,7 @@ sub set_text_file_line_endings {
                return 1;
        }
        else {
-               notify($ERRORS{'WARNING'}, 0, "failed to set $type-style line 
endings for file: $file_path, exit status: $exit_status, output:\n@{$output}");
+               notify($ERRORS{'WARNING'}, 0, "failed to set $type-style line 
endings for file: $file_path, exit status: $exit_status, 
command:\n$command\noutput:\n@{$output}");
                return;
        }
 }
@@ -3887,86 +3887,112 @@ sub firewall_compare_update {
 =cut
 
 sub update_cluster {
-
        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 $reservation_id      = $self->data->get_reservation_id();
+       
+       my $current_reservation_id = $self->data->get_reservation_id();
+       my @reservation_ids = $self->data->get_reservation_ids();
+       my @child_reservation_ids = $self->data->get_child_reservation_ids();
+       my $parent_reservation_id = $self->data->get_parent_reservation_id();
        my $computer_short_name = $self->data->get_computer_short_name();
-       my $image_OS_type       = $self->data->get_image_os_type();
-       my $is_cluster_parent   = $self->data->get_request_is_cluster_parent();
-       my $is_cluster_child            = 
$self->data->get_request_is_cluster_child();
-
-       my $cluster_info   = "/tmp/$computer_short_name.cluster_info";
-       my @cluster_string = "";
-
-       #Get all the request data
-       my $request_data      = $self->data->get_request_data();
-
-       my @reservation_ids = sort keys %{$request_data->{reservation}};
-
-       # parent reservation id lowest
-       my $parent_reservation_id = min @reservation_ids;
-       notify($ERRORS{'DEBUG'}, 0, "$computer_short_name is_cluster_parent = 
$is_cluster_parent ");
-       notify($ERRORS{'DEBUG'}, 0, "$computer_short_name is_cluster_child = 
$is_cluster_child ");
-       notify($ERRORS{'DEBUG'}, 0, "parent_reservation_id = 
$parent_reservation_id ");
-
-       foreach my $rid (keys %{$request_data->{reservation}}) {
-               if ($rid == $parent_reservation_id) {
-                       push(@cluster_string, "parent= 
$request_data->{reservation}{$rid}{computer}{IPaddress}" . "\n");
-                       notify($ERRORS{'DEBUG'}, 0, "writing parent=  
$request_data->{reservation}{$rid}{computer}{IPaddress}");
+       
+       my $cluster_info_file_path = $self->get_cluster_info_file_path();
+       my $cluster_info_string = '';
+       
+       my @public_ip_addresses;
+       
+       for my $cluster_reservation_id (@reservation_ids) {
+               # Get a DataStructure object for each reservation
+               my $reservation_data;
+               if ($cluster_reservation_id eq $current_reservation_id) {
+                       $reservation_data = $self->data();
                }
                else {
-                       push(@cluster_string, "child= 
$request_data->{reservation}{$rid}{computer}{IPaddress}" . "\n");
-                       notify($ERRORS{'DEBUG'}, 0, "writing child=  
$request_data->{reservation}{$rid}{computer}{IPaddress}");
+                       $reservation_data = 
$self->data->get_reservation_data($cluster_reservation_id);
+               }
+               if (!$reservation_data) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to update cluster 
request, data could not be retrieved for reservation $cluster_reservation_id");
+                       return;
                }
                
-               #Create iptables rule for each node in cluster on the node 
being processed
-               # Could slow things down for large clusters, but they can 
communicate with each other
-               if ($self->can('enable_firewall_port')) {
-                       if (!$self->enable_firewall_port("tcp", "any", 
$request_data->{reservation}{$rid}{computer}{IPaddress}, 0)) {
-                               notify($ERRORS{'DEBUG'}, 0, "adding 
$request_data->{reservation}{$rid}{computer}{IPaddress} to iptables");
-                       }
+               # Get the computer IP address
+               my $cluster_computer_public_ip_address = 
$reservation_data->get_computer_public_ip_address();
+               if (!$cluster_computer_public_ip_address) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to update cluster 
request, public IP address could not be retrieved for computer assigned to 
reservation $cluster_reservation_id");
+                       return;
+               }
+               
+               # Add the public IP address to the array for reservations not 
matching the reservation ID currently being processed
+               if ($cluster_reservation_id ne $current_reservation_id) {
+                       push @public_ip_addresses, 
$cluster_computer_public_ip_address;
                }
+               
+               # Add a line to cluster_info string for each reservation
+               if ($cluster_reservation_id eq $parent_reservation_id) {
+                       $cluster_info_string .= "parent= ";
+               }
+               else {
+                       $cluster_info_string .= "child= ";
+               }
+               $cluster_info_string .= "$cluster_computer_public_ip_address\n";
        }
-
-       if (open(CLUSTERFILE, ">$cluster_info")) {
-               print CLUSTERFILE @cluster_string;
-               close(CLUSTERFILE);
+       
+       # Remove trailing newline
+       $cluster_info_string =~ s/\n$//;
+       
+       # Create the cluster_info file on the computer
+       if ($self->create_text_file($cluster_info_file_path, 
$cluster_info_string)) {
+               notify($ERRORS{'DEBUG'}, 0, "created $cluster_info_file_path on 
$computer_short_name:\n$cluster_info_string");
+               $self->set_text_file_line_endings($cluster_info_file_path);
        }
        else {
-               notify($ERRORS{'OK'}, 0, "could not write to $cluster_info");
+               notify($ERRORS{'WARNING'}, 0, "failed to create 
$cluster_info_file_path on $computer_short_name");
+               return;
        }
-
-       my $identity;
-       #scp cluster file to each node
-       my $targetpath;
-       foreach my $resid (keys %{$request_data->{reservation}}) {
-               $identity = 
$request_data->{reservation}{$resid}{image}{IDENTITY};
-               my $node_name = 
$request_data->{reservation}{$resid}{computer}{SHORTNAME};
-               if ($image_OS_type =~ /linux/i) {
-                       $targetpath = "$node_name:/etc/cluster_info";
-               }
-               elsif ($image_OS_type =~ /windows/i) {
-                       $targetpath = "$node_name:C:\/cluster_info";
+       
+       # Open the firewall allowing other cluster reservations computers access
+       if ($self->can('enable_firewall_port')) {
+               my $firewall_scope = join(",", @public_ip_addresses);
+               notify($ERRORS{'DEBUG'}, 0, "attempting to open the firewall on 
$computer_short_name to allow access from other cluster reservation computers: 
$firewall_scope");
+               
+               if (!$self->enable_firewall_port("tcp", "any", $firewall_scope, 
0)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to open the 
firewall on $computer_short_name to allow access from other cluster reservation 
computers via TCP: $firewall_scope");
                }
-               else {
-                       $targetpath = "$node_name:/etc/cluster_info";
+               
+               if (!$self->enable_firewall_port("udp", "any", $firewall_scope, 
0)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to open the 
firewall on $computer_short_name to allow access from other cluster reservation 
computers via UDP: $firewall_scope");
                }
+       }
 
-               if (run_scp_command($cluster_info, $targetpath, $identity)) {
-                       notify($ERRORS{'OK'}, 0, " successfully copied 
cluster_info file to $node_name");
-               }
-       } ## end foreach my $resid (keys %{$request_data->{reservation...
+       return 1;
+} ## end sub update_cluster_info
 
-       unlink $cluster_info;
+#/////////////////////////////////////////////////////////////////////////////
 
-       return 1;
+=head2 get_cluster_info_file_path
 
-} ## end sub update_cluster_info
+ Parameters  : none
+ Returns     : string
+ Description : Returns the location where the cluster_info files resides on the
+               computer: /etc/cluster_info. OS modules such as Windows which 
use
+               a different location should override this subroutine.
+
+=cut
+
+sub get_cluster_info_file_path {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module::OS/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       return $self->{cluster_info_file_path} if 
$self->{cluster_info_file_path};
+       $self->{cluster_info_file_path} = '/etc/cluster_info';
+       notify($ERRORS{'DEBUG'}, 0, "determined cluster_info file path for " . 
ref($self) . " OS module: $self->{cluster_info_file_path}");
+       return $self->{cluster_info_file_path};
+}
 
 #///////////////////////////////////////////////////////////////////////////
 

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1658846&r1=1658845&r2=1658846&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Wed Feb 11 00:03:26 
2015
@@ -4027,7 +4027,7 @@ sub get_service_configuration {
        
        my $services_key = 
'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services';
        
-       my $cygwin_path = $self->get_cygwin_path();
+       my $cygwin_path = $self->get_cygwin_installation_directory_path();
 
        my $node_reg_file_path = $cygwin_path . 
"/tmp/services_$computer_node_name.reg";
        my $mn_reg_file_path = "/tmp/vcl/services_$computer_node_name.reg";
@@ -6731,7 +6731,11 @@ sub set_text_file_line_endings {
        }
        $line_ending = 'win' unless $line_ending;
        
-       return $self->SUPER::set_text_file_line_endings($file_path, 
$line_ending);
+       # Convert the Windows-style path to a Cygwin/Unix-style path or else 
the sed command in OS.pm::set_text_file_line_endings will fail with this error:
+       # sed: couldn't open temporary file C:/sedxxxxxx: No such file or 
directory
+       my $unix_file_path = $self->get_cygwin_unix_file_path($file_path) || 
$file_path;
+       
+       return $self->SUPER::set_text_file_line_endings($unix_file_path, 
$line_ending);
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -6952,7 +6956,7 @@ sub clean_hard_drive {
 
        my $computer_node_name   = $self->data->get_computer_node_name();
        my $system32_path        = $self->get_system32_path() || return;
-       my $cygwin_path          = $self->get_cygwin_path();
+       my $cygwin_path          = 
$self->get_cygwin_installation_directory_path();
        
        # Run dism.exe
        # The dism.exe file may not be present
@@ -12026,15 +12030,17 @@ sub notify_user_console {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_cygwin_path
+=head2 get_cygwin_installation_directory_path
 
- Parameters  : 
- Returns     : sets $self->{CYGWIN_PATH}
- Description : sets CYGWIN_PATH, x86 and x86_64 use different paths, need to 
detect which path to use. 
+ Parameters  : none
+ Returns     : string
+ Description : Retrieves the directory path where Cygwin is installed on the
+               computer. 32-bit and 64-bit versions of Cygwin may use different
+               paths. 
 
 =cut
 
-sub get_cygwin_path {
+sub get_cygwin_installation_directory_path {
        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");
@@ -12044,30 +12050,114 @@ sub get_cygwin_path {
        return $self->{CYGWIN_PATH} if $self->{CYGWIN_PATH};
 
        my $computer_node_name = $self->data->get_computer_node_name();
-       my $command = "cygpath -d /";
-
-       my ($exit_status, $output) = $self->execute($command, 1);
        
+       my $default_path = 'C:/cygwin';
+       
+       my $command = "cygpath.exe -m /";
+       my ($exit_status, $output) = $self->execute($command, 1);
        if (!defined($output)) {
-               notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to 
delete files under command: $command");
-               #return default path
-               $self->{CYGWIN_PATH} = "C:/cygwin";
+               notify($ERRORS{'WARNING'}, 0, "failed to execute command to 
determine Cygwin installation directory path on $computer_node_name, returning 
default path: $default_path");
+               $self->{CYGWIN_PATH} = $default_path;
                return $self->{CYGWIN_PATH};
        }
-       elsif (@$output) {
-               $self->{CYGWIN_PATH} = @$output[0];
-               #fix path
-               $self->{CYGWIN_PATH} =~ tr/\\/\//;
-               notify($ERRORS{'DEBUG'}, 0, "command: $command cygwin_path: 
$self->{CYGWIN_PATH}");
-               if ($self->file_exists($self->{CYGWIN_PATH})) {
-                       notify($ERRORS{'DEBUG'}, 0, " $self->{CYGWIN_PATH} 
exists");
-               }
+       elsif (grep(/^cygpath:/, @$output)) {
+               notify($ERRORS{'WARNING'}, 0, "error occurred determining 
Cygwin installation directory path on $computer_node_name, returning default 
path: $default_path, output:\n" . join("\n", @$output));
+               $self->{CYGWIN_PATH} = $default_path;
+               return $self->{CYGWIN_PATH};
+       }
+       
+       my ($directory_path) = grep(/^[a-z]/i, @$output);
+       if ($directory_path) {
+               notify($ERRORS{'DEBUG'}, 0, "determined Cygwin installation 
directory path on $computer_node_name: $directory_path");
+               $self->{CYGWIN_PATH} = $directory_path;
+               return $self->{CYGWIN_PATH};
+       }
+       else {
+               notify($ERRORS{'WARNING'}, 0, "error occurred determining 
Cygwin installation directory path on $computer_node_name, returning default 
path: $default_path, did not find a line beginning with a letter in the 
output:\n" . join("\n", @$output));
+               $self->{CYGWIN_PATH} = $default_path;
                return $self->{CYGWIN_PATH};
        }
 }
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_cygwin_unix_file_path
+
+ Parameters  : $file_path
+ Returns     : string
+ Description : Converts a Windows-style path to a Cygwin/Unix-style path.
+               Example: C:\Windows\file.txt --> /cygdrive/c/Windows/file.txt
+
+=cut
+
+sub get_cygwin_unix_file_path {
+       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;
+       }
+       
+       my $file_path_argument = shift;
+       if (!$file_path_argument) {
+               notify($ERRORS{'WARNING'}, 0, "file path argument was not 
specified");
+               return;
+       }
+       
+       if ($file_path_argument =~ /^\//) {
+               notify($ERRORS{'DEBUG'}, 0, "file path not converted because it 
begins with a forward slash: $file_path_argument");
+               return $file_path_argument;
+       }
+       
+       # Change backslashes to forward slashes
+       $file_path_argument =~ s/\\+/\//g;
+       
+       my $command = "cygpath.exe -u \"$file_path_argument\"";
+       my ($exit_status, $output) = $self->execute($command);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute command to 
determine Cygwin/Unix-style path, returning argument: $file_path_argument");
+               return $file_path_argument;
+       }
+       
+       my ($unix_file_path) = grep(/^\//, @$output);
+       if (!$unix_file_path || grep(/^cygpath:/, @$output)) {
+               notify($ERRORS{'WARNING'}, 0, "error occurred attempting to 
determine Cygwin/Unix-style path, returning argument: $file_path_argument, 
output:\n" . join("\n", @$output));
+               return $file_path_argument;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "determined Cygwin/Unix-style path: 
$file_path_argument --> $unix_file_path");
+               return $unix_file_path;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_cluster_info_file_path
+
+ Parameters  : none
+ Returns     : string
+ Description : Returns the location where the cluster_info files resides on the
+               Windows computer, normally C:/cluster_info.
+
+=cut
+
+sub get_cluster_info_file_path {
+       my $self = shift;
+       if (ref($self) !~ /windows/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       return $self->{cluster_info_file_path} if 
$self->{cluster_info_file_path};
+       
+       my $systemroot_value = 
$self->get_environment_variable_value('SYSTEMDRIVE') || 'C:';
+       $self->{cluster_info_file_path} = "$systemroot_value/cluster_info";
+       notify($ERRORS{'DEBUG'}, 0, "determined cluster_info file path for 
Windows: $self->{cluster_info_file_path}");
+       return $self->{cluster_info_file_path};
+}
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 disable_set_network_location_prompt
 
  Parameters  : none
@@ -12085,7 +12175,7 @@ sub disable_set_network_location_prompt
                return;
        }
        
-       my $registry_key =      
'HKLM\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff';
+       my $registry_key = 
'HKLM\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff';
        return $self->reg_add($registry_key);
 }
 


Reply via email to