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/03/05 20:10:04 UTC

svn commit: r1664459 - in /vcl/trunk/managementnode/lib/VCL: Module/OS.pm Module/OS/Linux/firewall/iptables.pm reclaim.pm utils.pm

Author: arkurth
Date: Thu Mar  5 19:10:04 2015
New Revision: 1664459

URL: http://svn.apache.org/r1664459
Log:
VCL-174
Renamed utils.pm::get_connect_method_info to get_reservation_connect_method_info and changed argument from $imagerevision_id to $reservation_id. Updated all calls to this subroutine.

Added iptables.pm::sanitize_reservation. Changed call in reclaim.pm from delete_chain to sanitize_reservation to make things more generic and flexible for future modules.

Removed required $chain_name argument from iptables.pm::add_nat_port_forward. Added get_reservation_chain_name subroutine so that the chain name used for individual reservations is only defined in 1 location.

Added iptables.pm::save_configuration subroutine. This gets called from sanitize_reservation and configure_nat_reservation.

Other
Updated utils.pm::get_vmhost_info to accept either a VM host computer name or ID.

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/OS.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm
    vcl/trunk/managementnode/lib/VCL/reclaim.pm
    vcl/trunk/managementnode/lib/VCL/utils.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=1664459&r1=1664458&r2=1664459&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS.pm Thu Mar  5 19:10:04 2015
@@ -2977,7 +2977,7 @@ sub process_connect_methods {
 						return;
 					}
 					
-					if ($self->nathost_os->firewall->add_nat_port_forward($protocol, $nat_public_port, $computer_ip_address, $port, "$PROCESSNAME-$reservation_id")) {
+					if ($self->nathost_os->firewall->add_nat_port_forward($protocol, $nat_public_port, $computer_ip_address, $port)) {
 						notify($ERRORS{'OK'}, 0, "NAT port forwarding configured on $nathost_hostname for '$name' connect method: $nathost_public_ip_address:$nat_public_port --> $computer_ip_address:$port ($protocol)");
 					}
 					else {

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm?rev=1664459&r1=1664458&r2=1664459&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm Thu Mar  5 19:10:04 2015
@@ -24,7 +24,7 @@ VCL::Module::OS::Linux::firewall::iptabl
 
 =head1 DESCRIPTION
 
- This module provides VCL support for iptables-based firewalls.
+ This module provides support for configuring iptables-based firewalls.
 
 =cut
 
@@ -64,7 +64,8 @@ use VCL::utils;
 
  Parameters  : none
  Returns     : boolean
- Description : 
+ Description : Returns true if the iptables command exists on the computer.
+               Returns false if the command does not exist.
 
 =cut
 
@@ -94,9 +95,58 @@ sub initialize {
 
 =head2 insert_rule
 
- Parameters  : none
+ Parameters  : hash reference
  Returns     : boolean
- Description : 
+ Description : Inserts an iptables rule. The argument must be a properly
+               constructed hash reference. Supported top-level hash keys are:
+               * {table} => '<string>' (optional)
+                    Specifies the name of the table the rule will be added to.
+                    If ommitted, the rule will be added to the filter table by
+                    default.
+               * {chain} => '<string>' (mandatory)
+                    Specifies the name of the chain the rule will be added to.
+               * {parameters} => {<hash reference>} (optional)
+                    Allows any of the options under the iptables man page
+                    "PARAMETERS" section to be specified. Full parameter names
+                    should be used such as "protocol" instead of "-p".
+                    Parameters can be negated by adding an exclaimation point
+                    before the parameter name.
+               * {match_extensions} => {<hash reference>} (optional)
+                    Allows any of the options under the iptables man page
+                    "MATCH EXTENSIONS" section to be specified. Each key should
+                    be a match extension module name such as "state". The value
+                    should be a hash reference whose key names should be the
+                    names of the supported options for that match extension
+                    module.
+               * {target_extensions} => {<hash reference>} (optional)
+                    Allows any of the options under the iptables man page
+                    "TARGET EXTENSIONS" section to be specified. Each key should
+                    be a target extension module name such as "DNAT". The value
+                    should be a hash reference whose key names should be the
+                    names of the supported options for that target extension
+                    module.
+               Example:
+               {
+                  'table' => 'nat',
+                  'chain' => 'PREROUTING',
+                  'parameters' => {
+                     'protocol' => 'tcp',
+                     'in-interface' => 'eth1',
+                  },
+                  'match_extensions' => {
+                     'comment' => {
+                        'comment' => "forward: eth1:50443 --> 10.1.2.3.4:443 (tcp)",
+                     },
+                     $protocol => {
+                        'destination-port' => 50443,
+                     },
+                  },
+                  'target_extensions' => {
+                     'DNAT' => {
+                        'to-destination' => "10.1.2.3.4:443",
+                     },
+                  },
+               }
 
 =cut
 
@@ -196,7 +246,7 @@ sub insert_rule {
 
  Parameters  : hash reference
                -or-
-					$table_name, $chain_name, $rule_specification
+               $table_name, $chain_name, $rule_specification
  Returns     : boolean
  Description : Deletes a rule.
 
@@ -413,6 +463,35 @@ sub delete_chain {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 sanitize_reservation
+
+ Parameters  : $reservation_id (optional)
+ Returns     : boolean
+ Description : Deletes the chains created for the reservation. Saves the
+               iptables configuration.
+
+=cut
+
+sub sanitize_reservation {
+	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 0;
+	}
+	
+	my $reservation_id = shift || $self->data->get_reservation_id();
+	my $reservation_chain_name = $self->get_reservation_chain_name($reservation_id);
+	
+	if (!$self->delete_chain('nat', $reservation_chain_name)) {
+		return;
+	}
+	
+	$self->save_configuration();
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 delete_chain_references
 
  Parameters  : $table_name, $referenced_chain_name
@@ -517,7 +596,49 @@ sub flush_chain {
 
  Parameters  : $table_name, $chain_name (optional)
  Returns     : boolean
- Description : 
+ Description : Retrieves the configuration of an iptables table and constructs a
+               hash reference. Example:
+               {
+                 "OUTPUT" => {
+                   "policy" => "ACCEPT"
+                 },
+                 "PREROUTING" => {
+                   "policy" => "ACCEPT",
+                   "rules" => [
+                     {
+                       "parameters" => {
+                         "jump" => {
+                           "target" => "vcld-3116"
+                         }
+                       },
+                       "rule_specification" => "-j vcld-3116"
+                     }
+                   ]
+                 },
+                 "vcld-3116" => {
+                   "rules" => [
+                     {
+                       "match_extensions" => {
+                         "comment" => {
+                           "comment" => "forward: eth1:18892 --> 192.168.110.201:53 (tcp)"
+                         },
+                         "tcp" => {
+                           "dport" => 18892
+                         }
+                       },
+                       "parameters" => {
+                         "in-interface" => "eth1",
+                         "jump" => {
+                           "target" => "DNAT",
+                           "to-destination" => "192.168.110.201:53"
+                         },
+                         "protocol" => "tcp"
+                       },
+                       "rule_specification" => "-i eth1 -p tcp -m comment --comment \"forward: eth1:18892 --> 192.168.110.201:53 (tcp)\" -m tcp --dport 18892 -j DNAT --to-destination 192.168.110.201:53"
+                     }
+                   ]
+                 }
+               }
 
 =cut
 
@@ -534,6 +655,8 @@ sub get_table_info {
 		return;
 	}
 	
+	$ENV{iptables_get_table_info_count}{$table_name}++;
+	
 	my $computer_name = $self->data->get_computer_hostname();
 	
 	my $command = "/sbin/iptables --list-rules";
@@ -599,10 +722,10 @@ sub get_table_info {
 		}
 		elsif ($iptables_command =~ /^(-A|--append chain)/) {
 			# -A, --append chain rule-specification
-			notify($ERRORS{'DEBUG'}, 0, "parsing iptables append rule command:\n" .
-				"iptables command: $line\n" .
-				"iptables rule specification: $rule_specification_string"
-			);
+			#notify($ERRORS{'DEBUG'}, 0, "parsing iptables append rule command:\n" .
+			#	"iptables command: $line\n" .
+			#	"iptables rule specification: $rule_specification_string"
+			#);
 			
 			my $rule = {};
 			$rule->{rule_specification} = $rule_specification_string;
@@ -662,7 +785,7 @@ sub get_table_info {
 					# Check if this is the beginning of a target extension option
 					if ($target_extension_option_section =~ /^[-]+(\w[\w-]+)/) {
 						$target_extension_option_name = $1;
-						notify($ERRORS{'DEBUG'}, 0, "located $target_parameter target extension option: $target_extension_option_name");
+						#notify($ERRORS{'DEBUG'}, 0, "located $target_parameter target extension option: $target_extension_option_name");
 						$rule->{parameters}{$target_parameter}{$target_extension_option_name} = undef;
 					}
 					elsif (!$target_extension_option_name) {
@@ -685,13 +808,13 @@ sub get_table_info {
 				
 				my $rule_specification_string_before = $rule_specification_string;
 				$rule_specification_string =~ s/$target_parameter_regex//g;
-				notify($ERRORS{'DEBUG'}, 0, "parsed iptables target parameter:\n" .
-					"target parameter: $target_parameter_match\n" .
-					"target: $target\n" .
-					"target specification removal regex: $target_parameter_regex\n" .
-					"rule specification before: $rule_specification_string_before\n" .
-					"rule specification after:  $rule_specification_string"
-				);
+				#notify($ERRORS{'DEBUG'}, 0, "parsed iptables target parameter:\n" .
+				#	"target parameter: $target_parameter_match\n" .
+				#	"target: $target\n" .
+				#	"target specification removal regex: $target_parameter_regex\n" .
+				#	"rule specification before: $rule_specification_string_before\n" .
+				#	"rule specification after:  $rule_specification_string"
+				#);
 			}  # TARGET_PARAMETER
 			
 			
@@ -723,7 +846,7 @@ sub get_table_info {
 					# If section begins with a letter it should be the match extension module name
 					if ($match_extension_section =~ /^[a-z]/i) {
 						$match_extension_module_name = $match_extension_section;
-						notify($ERRORS{'DEBUG'}, 0, "located match extension module name: $match_extension_module_name");
+						#notify($ERRORS{'DEBUG'}, 0, "located match extension module name: $match_extension_module_name");
 						next MATCH_EXTENSION_SECTION;
 					}
 					else {
@@ -742,7 +865,7 @@ sub get_table_info {
 						$match_extension_option = "!$match_extension_option";
 						$match_extension_option_inverted = 0;
 					}
-					notify($ERRORS{'DEBUG'}, 0, "match extension module name: $match_extension_module_name, located match extension option: $match_extension_option");
+					#notify($ERRORS{'DEBUG'}, 0, "match extension module name: $match_extension_module_name, located match extension option: $match_extension_option");
 					next MATCH_EXTENSION_SECTION;
 				}
 				elsif ($match_extension_section =~ /^!/) {
@@ -795,7 +918,7 @@ sub get_table_info {
 
  Parameters  : $public_ip_address, $internal_ip_address
  Returns     : boolean
- Description : 
+ Description : Configures the iptables firewall to pass NAT traffic.
 
 =cut
 
@@ -840,8 +963,9 @@ sub configure_nat {
 	
 	# Check if NAT has previously been configured
 	for my $rule (@{$nat_table_info->{POSTROUTING}{rules}}) {
-		if ($rule =~ /MASQUERADE/) {
-			notify($ERRORS{'DEBUG'}, 0, "POSTROUTING chain in nat table contains a MASQUERADE rule, assuming NAT has already been configured: $rule");
+		my $rule_specification = $rule->{rule_specification};
+		if ($rule_specification =~ /MASQUERADE/) {
+			notify($ERRORS{'DEBUG'}, 0, "POSTROUTING chain in nat table contains a MASQUERADE rule, assuming NAT has already been configured: $rule_specification");
 			return 1;
 		}
 	}
@@ -1022,7 +1146,7 @@ sub configure_nat_reservation {
 		return;
 	}
 	
-	my $chain_name = "$PROCESSNAME-$reservation_id";
+	my $chain_name = $self->get_reservation_chain_name();
 	
 	# Check if chain for reservation has already been created
 	if (defined($nat_table_info->{$chain_name})) {
@@ -1035,8 +1159,9 @@ sub configure_nat_reservation {
 	
 	# Check if rule to jump to reservation's chain already exists in the PREROUTING table
 	for my $rule (@{$nat_table_info->{PREROUTING}{rules}}) {
-		if ($rule =~ /-j $chain_name(\s|$)/) {
-			notify($ERRORS{'DEBUG'}, 0, "PREROUTING chain in nat table on $computer_name already contains a rule to jump to '$chain_name' chain: $rule");
+		my $rule_specification = $rule->{rule_specification};
+		if ($rule_specification =~ /-j $chain_name(\s|$)/) {
+			notify($ERRORS{'DEBUG'}, 0, "PREROUTING chain in nat table on $computer_name already contains a rule to jump to '$chain_name' chain: $rule_specification");
 			return 1;;
 		}
 	}
@@ -1053,6 +1178,7 @@ sub configure_nat_reservation {
 		return;
 	}
 	
+	$self->save_configuration();
 	return 1;
 }
 
@@ -1062,7 +1188,7 @@ sub configure_nat_reservation {
 
  Parameters  : $protocol, $source_port, $destination_ip_address, $destination_port, $chain_name (optional)
  Returns     : boolean
- Description : 
+ Description : Forwards a port via DNAT.
 
 =cut
 
@@ -1092,12 +1218,48 @@ sub add_nat_port_forward {
 		notify($ERRORS{'WARNING'}, 0, "destination port argument was not provided");
 		return;
 	}
-	$chain_name = 'PREROUTING' unless defined $chain_name;
+	$chain_name = $self->get_reservation_chain_name() unless defined $chain_name;
 	
 	$protocol = lc($protocol);
 	
 	my $public_interface_name = $self->os->get_public_interface_name();
-	my $public_ip_address = $self->os->get_public_ip_address();
+	
+	my $nat_table_info = $self->get_table_info('nat');
+	if (!$nat_table_info) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add NAT port forward on $computer_name, nat table information could not be retrieved");
+		return;
+	}
+	
+	# Check if rule has previously been added
+	for my $rule (@{$nat_table_info->{$chain_name}{rules}}) {
+		my $rule_target = $rule->{parameters}{jump}{target} || '<not set>';
+		if ($rule_target ne 'DNAT') {
+			#notify($ERRORS{'DEBUG'}, 0, "ignoring rule, target is not DNAT: $rule_target");
+			next;
+		}
+		
+		my $rule_protocol = $rule->{parameters}{protocol} || '<not set>';
+		if (lc($rule_protocol) ne $protocol) {
+			#notify($ERRORS{'DEBUG'}, 0, "ignoring rule, protocol '$rule_protocol' does not match protocol argument: '$protocol'");
+			next;
+		}
+		
+		my $rule_source_port = $rule->{match_extensions}{$protocol}{dport} || '<not set>';
+		if ($rule_source_port ne $source_port) {
+			#notify($ERRORS{'DEBUG'}, 0, "ignoring rule, source port $rule_source_port does not match argument: $source_port");
+			next;
+		}
+		
+		my $rule_destination = $rule->{parameters}{jump}{'to-destination'} || '<not set>';
+		if ($rule_destination ne "$destination_ip_address:$destination_port") {
+			#notify($ERRORS{'DEBUG'}, 0, "ignoring rule, destination $rule_destination does not match argument: $destination_ip_address:$destination_port");
+			next;
+		}
+		
+		my $rule_specification = $rule->{'rule_specification'};
+		notify($ERRORS{'DEBUG'}, 0, "NAT port forwared rule already exists, chain: $chain_name, protocol: $protocol, source port: $source_port, destination: $destination_ip_address:$destination_port\nrule specification:\n$rule_specification");
+		return 1;
+	}
 	
 	if ($self->insert_rule({
 		'table' => 'nat',
@@ -1105,11 +1267,10 @@ sub add_nat_port_forward {
 		'parameters' => {
 			'protocol' => $protocol,
 			'in-interface' => $public_interface_name,
-			#'destination' => $public_ip_address,
 		},
 		'match_extensions' => {
 			'comment' => {
-				'comment' => "forward: $public_ip_address:$source_port --> $destination_ip_address:$destination_port ($protocol)",
+				'comment' => "forward: $public_interface_name:$source_port --> $destination_ip_address:$destination_port ($protocol)",
 			},
 			$protocol => {
 				'destination-port' => $source_port,
@@ -1131,6 +1292,129 @@ sub add_nat_port_forward {
 }
 
 #/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_reservation_chain_name
+
+ Parameters  : $reservation_id (optional)
+ Returns     : string
+ Description : Returns the name of the iptables chain containing rules for a
+               single VCL reservation.
+
+=cut
+
+sub get_reservation_chain_name {
+	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 0;
+	}
+	
+	my $reservation_id = shift || $self->data->get_reservation_id();
+	return "$PROCESSNAME-$reservation_id";
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 save_configuration
+
+ Parameters  : $file_path (optional)
+ Returns     : boolean
+ Description : Saves the current iptables configuration by running
+               iptables-save. If no file path argument is provided, the output
+               is saved to /etc/sysconfig/iptables.
+
+=cut
+
+sub save_configuration {
+	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 0;
+	}
+	
+	my $file_path = shift || '/etc/sysconfig/iptables';
+	
+	my $computer_id = $self->data->get_computer_id();
+	my $computer_name = $self->data->get_computer_hostname();
+	
+	# Get the output of iptables-save
+	# IMPORTANT: don't simply redirect the output to the file
+	# If iptables is stopped or else the previously saved configuration will be overwritten
+	my $command = '/sbin/iptables-save';
+	my ($exit_status, $output) = $self->os->execute($command, 0);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to save iptables configuration on $computer_name");
+		return;
+	}
+	elsif ($exit_status ne 0) {
+		notify($ERRORS{'WARNING'}, 0, "failed to save iptables configuration on $computer_name, exit status: $exit_status, command:\n$command\noutput:\n" . join("\n", @$output));
+		return 0;
+	}
+	
+	my $file_exists = $self->os->file_exists($file_path);
+	
+	# Make sure output contains at least 1 line beginning with "-A"
+	# If the iptables service is stopped the output will be blank
+	# If the iptables service is stopped but "iptables -L" is executed the output may contain something like:
+	# #Generated by iptables-save v1.4.7 on Thu Mar  5 13:36:51 2015
+	# *filter
+	# :INPUT ACCEPT [40:4736]
+	# :FORWARD ACCEPT [0:0]
+	# :OUTPUT ACCEPT [8:1200]
+	# COMMIT
+	# #Completed on Thu Mar  5 13:36:51 2015
+	if (!grep(/\w/, @$output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to save iptables configuration on $computer_name, iptables service may not be running, no output was returned from $command");
+		return 0;
+	}
+	elsif (!grep(/^-A/, @$output) && ($file_exists || $file_path eq '/etc/sysconfig/iptables')) {
+		notify($ERRORS{'WARNING'}, 0, "iptables configuration not saved to $file_path on $computer_name for safety, iptables service may not be running, output of $command does not contain any lines beginning with '-A':\n" . join("\n", @$output));
+		return 0;
+	}
+	
+	# Attempt to get a semaphore if the file already exists
+	my $semaphore;
+	if ($file_exists) {
+		$semaphore = $self->get_semaphore("iptables-save_configuration-$computer_id", (30 * 1));
+		if (!$semaphore) {
+			notify($ERRORS{'WARNING'}, 0, "failed to save iptables configuration on $computer_name, $file_path already exists and semaphore could not be obtained to avoid multiple processes writing to the file at the same time");
+			return;
+		}
+	}
+	
+	return $self->os->create_text_file($file_path, join("\n", @$output));
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 DESTROY
+
+ Parameters  : none
+ Returns     : true
+ Description : 
+
+=cut
+
+sub DESTROY {
+	my $self = shift || return;
+	
+	my $address = sprintf('%x', $self);
+	my $table_count_string;
+	if ($ENV{iptables_get_table_info_count}) {
+		for my $table_name (keys $ENV{iptables_get_table_info_count}) {
+			my $table_count = $ENV{iptables_get_table_info_count}{$table_name};
+			$table_count_string .= "$table_name: $table_count\n";
+		}
+		notify($ERRORS{'DEBUG'}, 0, "get_table_info calls:\n$table_count_string");
+	}
+	
+	# Check for an overridden destructor
+	$self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
 
 1;
 __END__

Modified: vcl/trunk/managementnode/lib/VCL/reclaim.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/reclaim.pm?rev=1664459&r1=1664458&r2=1664459&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/reclaim.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/reclaim.pm Thu Mar  5 19:10:04 2015
@@ -131,12 +131,18 @@ sub process {
 	if ($self->nathost_os(0)) {
 		my $nathost_hostname = $self->data->get_nathost_hostname();
 		if ($self->nathost_os->firewall()) {
-			if (!$self->nathost_os->firewall->delete_chain('nat', $reservation_id)) {
-				notify($ERRORS{'CRITICAL'}, 0, "failed to delete '$reservation_id' chain from the nat table on NAT host $nathost_hostname");
+			if ($self->nathost_os->firewall->can('sanitize_reservation')) {
+				if (!$self->nathost_os->firewall->sanitize_reservation()) {
+					notify($ERRORS{'CRITICAL'}, 0, "failed to sanitize firewall for reservation on NAT host $nathost_hostname");
+				}
 			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to sanitize firewall for reservation on NAT host $nathost_hostname, " . ref($self->nathost_os->firewall) . " does not implement a 'sanitize_reservation' subroutine");
+			}
+			
 		}
 		else {
-			notify($ERRORS{'CRITICAL'}, 0, "failed to delete '$reservation_id' chain from the nat table on NAT host $nathost_hostname, NAT host OS object is not available");
+			notify($ERRORS{'WARNING'}, 0, "unable to sanitize firewall for reservation on NAT host $nathost_hostname, NAT host OS firewall object is not available");
 		}
 	}
 	

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1664459&r1=1664458&r2=1664459&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Thu Mar  5 19:10:04 2015
@@ -134,7 +134,6 @@ our @EXPORT = qw(
 	get_computer_nathost_info
 	get_computer_private_ip_address_info
 	get_computers_controlled_by_mn
-	get_connect_method_info
 	get_connectlog_info
 	get_connectlog_remote_ip_address_info
 	get_copy_speed_info_string
@@ -178,6 +177,7 @@ our @EXPORT = qw(
 	get_reservation_accounts
 	get_reservation_computerloadlog_entries
 	get_reservation_computerloadlog_time
+	get_reservation_connect_method_info
 	get_reservation_management_node_hostname
 	get_reservation_vcld_process_name_regex
 	get_request_loadstate_names
@@ -3053,7 +3053,7 @@ EOF
 		}
 		
 		# Add the connect method info to the hash
-		my $connect_method_info = get_connect_method_info($imagerevision_id, 0);
+		my $connect_method_info = get_reservation_connect_method_info($reservation_id, 0);
 		$request_info->{reservation}{$reservation_id}{connect_methods} = $connect_method_info;
 		
 		# Add the managementnode info to the hash
@@ -3314,9 +3314,9 @@ sub set_managementnode_state {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_requests
+=head2 get_management_node_requests
 
- Parameters  : management node id
+ Parameters  : $management_node_id
  Returns     : hash
  Description : gets request information for a particular management node
 
@@ -3835,7 +3835,7 @@ sub get_default_imagemeta_info {
 
 =head2  get_vmhost_info
 
- Parameters  : $vmhost_id, $no_cache (optional)
+ Parameters  : $vmhost_identifier, $no_cache (optional)
  Returns     : Hash reference
  Description : Retrieves info from the database for the vmhost, vmprofile, and
                repository and datastore imagetypes.
@@ -3844,15 +3844,15 @@ sub get_default_imagemeta_info {
 
 
 sub get_vmhost_info {
-	my ($vmhost_id, $no_cache) = @_;
+	my ($vmhost_identifier, $no_cache) = @_;
 	
 	# Check the passed parameter
-	if (!defined($vmhost_id)) {
-		notify($ERRORS{'WARNING'}, 0, "vmhost ID argument was not specified");
+	if (!defined($vmhost_identifier)) {
+		notify($ERRORS{'WARNING'}, 0, "VM host identifier argument was not specified");
 		return;
 	}
 	
-	return $ENV{vmhost_info}{$vmhost_id} if (!$no_cache && $ENV{vmhost_info}{$vmhost_id});
+	return $ENV{vmhost_info}{$vmhost_identifier} if (!$no_cache && $ENV{vmhost_info}{$vmhost_identifier});
 	
 	# Get a hash ref containing the database column names
 	my $database_table_columns = get_database_table_columns();
@@ -3885,15 +3885,24 @@ FROM
 vmhost,
 vmprofile,
 imagetype repositoryimagetype,
-imagetype datastoreimagetype
+imagetype datastoreimagetype,
+computer
 
 WHERE
-vmhost.id = '$vmhost_id'
-AND vmprofile.id = vmhost.vmprofileid
+vmprofile.id = vmhost.vmprofileid
 AND vmprofile.repositoryimagetypeid = repositoryimagetype.id
 AND vmprofile.datastoreimagetypeid = datastoreimagetype.id
+AND vmhost.computerid = computer.id
+AND 
 EOF
-
+	
+	if ($vmhost_identifier =~ /^\d+$/) {
+		$select_statement .= "vmhost.id = '$vmhost_identifier'";
+	}
+	else {
+		$select_statement .= "computer.hostname REGEXP '$vmhost_identifier(\\\\.|\$)'";
+	}
+	
 	# Call the database select subroutine
 	my @selected_rows = database_select($select_statement);
 
@@ -3985,9 +3994,15 @@ EOF
 	$vmhost_info->{vmprofile}{vmpath} = $vmhost_info->{vmprofile}{datastorepath} if !$vmhost_info->{vmprofile}{vmpath};
 	$vmhost_info->{vmprofile}{virtualdiskpath} = $vmhost_info->{vmprofile}{vmpath} if !$vmhost_info->{vmprofile}{virtualdiskpath};
 
-	notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_id info, computer: $vmhost_info->{computer}{hostname}");
-	$ENV{vmhost_info}{$vmhost_id} = $vmhost_info;
-	return $ENV{vmhost_info}{$vmhost_id};
+	notify($ERRORS{'DEBUG'}, 0, "retrieved VM host $vmhost_identifier info, computer: $vmhost_info->{computer}{hostname}");
+	$ENV{vmhost_info}{$vmhost_identifier} = $vmhost_info;
+	
+	my $vmhost_id = $vmhost_info->{id};
+	if ($vmhost_identifier ne $vmhost_id) {
+		$ENV{vmhost_info}{$vmhost_id} = $vmhost_info;
+	}
+	
+	return $ENV{vmhost_info}{$vmhost_identifier};
 }
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -7141,7 +7156,7 @@ EOF
 		}
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "retrieved info for computer: $computer_identifier");
+	notify($ERRORS{'DEBUG'}, 0, "retrieved info for computer: $computer_hostname ($computer_id)");
 	$ENV{computer_info}{$computer_identifier} = $computer_info;
 	$ENV{computer_info}{$computer_identifier}{RETRIEVAL_TIME} = time;
 	return $ENV{computer_info}{$computer_identifier};
@@ -7378,7 +7393,7 @@ sub get_natport_ranges {
 		push @natport_ranges, [$start_port, $end_port];
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "parsed natport_ranges variable:\n" . format_data(\@natport_ranges));
+	notify($ERRORS{'DEBUG'}, 0, "parsed natport_ranges variable: " . join(', ', @natport_ranges));
 	$ENV{natport_ranges} = \@natport_ranges;
 	return @natport_ranges;
 }
@@ -7421,7 +7436,7 @@ sub populate_reservation_natport {
 	notify($ERRORS{'DEBUG'}, 0, "computer $computer_id is mapped to NAT host $nathost_hostname ($nathost_hostname)");
 	
 	# Retrieve the connect method info - do not use cached info
-	my $connect_method_info = get_connect_method_info($imagerevision_id, 1);
+	my $connect_method_info = get_reservation_connect_method_info($reservation_id, 1);
 	
 	# Retrieve the ports already assigned to the nathost
 	my @assigned_ports = get_nathost_assigned_public_ports($nathost_id);
@@ -7497,7 +7512,7 @@ sub populate_reservation_natport {
 	
 	# Get the connect method info again to verify all ports are assigned a NAT public port
 	my $info_string = "";
-	$connect_method_info = get_connect_method_info($imagerevision_id, 1);
+	$connect_method_info = get_reservation_connect_method_info($reservation_id, 1);
 	for my $connect_method_id (sort keys %$connect_method_info) {
 		my $connect_method = $connect_method_info->{$connect_method_id};
 		my $connect_method_name = $connect_method->{name};
@@ -10695,12 +10710,11 @@ sub kill_child_processes {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 get_connect_method_info
+=head2 get_reservation_connect_method_info
 
  Parameters  : $imagerevision_id, $no_cache (optional)
  Returns     : hash reference
- Description : Returns the connect methods for the image revision specified as
-               the argument. Example:
+ Description : Returns the connect methods for the reservation. Example:
                {
                 4 => {
                   "RETRIEVAL_TIME" => "1417709281",
@@ -10748,30 +10762,28 @@ sub kill_child_processes {
 
 =cut
 
-sub get_connect_method_info {
-	my ($imagerevision_id, $no_cache) = @_;
-	if (!defined($imagerevision_id)) {
-		notify($ERRORS{'WARNING'}, 0, "imagerevision ID argument was not supplied");
+sub get_reservation_connect_method_info {
+	my ($reservation_id, $no_cache) = @_;
+	if (!defined($reservation_id)) {
+		notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not supplied");
 		return;
 	}
 	
-	# Check if cached image info exists
-	if (!$no_cache && defined($ENV{connect_method_info}{$imagerevision_id})) {
-		my $connect_method_id = (keys(%{$ENV{connect_method_info}{$imagerevision_id}}))[0];
+	# Check if cached info exists
+	if (!$no_cache && defined($ENV{connect_method_info}{$reservation_id})) {
+		my $connect_method_id = (keys(%{$ENV{connect_method_info}{$reservation_id}}))[0];
 		if ($connect_method_id) {
 			# Check the time the info was last retrieved
-			my $data_age_seconds = (time - $ENV{connect_method_info}{$imagerevision_id}{$connect_method_id}{RETRIEVAL_TIME});
+			my $data_age_seconds = (time - $ENV{connect_method_info}{$reservation_id}{$connect_method_id}{RETRIEVAL_TIME});
 			if ($data_age_seconds < 600) {
-				return $ENV{connect_method_info}{$imagerevision_id};
+				return $ENV{connect_method_info}{$reservation_id};
 			}
 			else {
-				notify($ERRORS{'DEBUG'}, 0, "retrieving current connect method info for imagerevision $imagerevision_id from database, cached data is stale: $data_age_seconds seconds old");
+				notify($ERRORS{'DEBUG'}, 0, "retrieving current connect method info for reservation $reservation_id from database, cached data is stale: $data_age_seconds seconds old");
 			}
 		}
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "attempting to retrieve connect method info for image revision $imagerevision_id");
-	
 	# Get a hash ref containing the database column names
 	my $database_table_columns = get_database_table_columns();
 	
@@ -10800,26 +10812,25 @@ sub get_connect_method_info {
 	$select_statement .= <<EOF;
 FROM
 connectmethod,
-
-connectmethodport
-LEFT JOIN natport ON (natport.connectmethodportid = connectmethodport.id),
-
 connectmethodmap,
 
-imagerevision
-LEFT JOIN image ON (image.id = imagerevision.imageid)
+reservation
+LEFT JOIN image ON (image.id = reservation.imageid)
 LEFT JOIN OS ON (OS.id = image.OSid)
-LEFT JOIN OStype ON (OStype.name = OS.type)
+LEFT JOIN OStype ON (OStype.name = OS.type),
+
+connectmethodport
+LEFT JOIN natport ON (natport.connectmethodportid = connectmethodport.id AND natport.reservationid = $reservation_id)
 
 WHERE
-connectmethodport.connectmethodid = connectmethod.id
+reservation.id = $reservation_id
+AND connectmethodport.connectmethodid = connectmethod.id
 AND connectmethodmap.connectmethodid = connectmethod.id
-AND imagerevision.id = $imagerevision_id
 AND connectmethodmap.autoprovisioned IS NULL
 AND (
 	connectmethodmap.OStypeid = OStype.id
 	OR connectmethodmap.OSid = OS.id 
-	OR connectmethodmap.imagerevisionid = imagerevision.id
+	OR connectmethodmap.imagerevisionid = reservation.imagerevisionid
 )
 
 ORDER BY
@@ -10869,9 +10880,9 @@ EOF
 		$connect_method_info->{$connectmethod_id}{RETRIEVAL_TIME} = $timestamp;
 	}
 
-	#notify($ERRORS{'DEBUG'}, 0, "retrieved connect method info:\n" . format_data($connect_method_info));
-	$ENV{connect_method_info}{$imagerevision_id} = $connect_method_info;
-	return $ENV{connect_method_info}{$imagerevision_id};
+	notify($ERRORS{'DEBUG'}, 0, "retrieved connect method info for reservation $reservation_id:\n" . format_data($connect_method_info));
+	$ENV{connect_method_info}{$reservation_id} = $connect_method_info;
+	return $ENV{connect_method_info}{$reservation_id};
 }
 
 #/////////////////////////////////////////////////////////////////////////////