You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2015/02/11 01:03:26 UTC

svn commit: r1658846 - in /vcl/trunk/managementnode/lib/VCL/Module: OS.pm OS/Windows.pm

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);
 }