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 2014/12/11 19:28:53 UTC

svn commit: r1644715 - in /vcl/trunk/managementnode/lib/VCL: ./ Module/ Module/OS/ Module/OS/Linux/firewall/ Module/OS/Linux/init/

Author: arkurth
Date: Thu Dec 11 18:28:52 2014
New Revision: 1644715

URL: http://svn.apache.org/r1644715
Log:
VCL-174
Updated OS.pm::process_connect_methods. It was not configuring the NAT forwarding correctly. Reworked NAT subroutines in iptables.pm.

Renamed nathost.natIP to publicIPaddress. Added nathost.internalIPaddress.

Added subroutines to Linux.pm and corresponding subroutines to init modules:
is_service_enabled
is_service_running
enable_service
disable_service

Modified:
    vcl/trunk/managementnode/lib/VCL/DataStructure.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/firewall/iptables.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/SysV.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/Upstart.pm
    vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm
    vcl/trunk/managementnode/lib/VCL/Module/State.pm
    vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: vcl/trunk/managementnode/lib/VCL/DataStructure.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/DataStructure.pm Thu Dec 11 18:28:52 2014
@@ -251,7 +251,8 @@ $SUBROUTINE_MAPPINGS{nathost_hostname} =
 $SUBROUTINE_MAPPINGS{nathost_date_deleted} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{datedeleted}';
 $SUBROUTINE_MAPPINGS{nathost_deleted} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{deleted}';
 $SUBROUTINE_MAPPINGS{nathost_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{id}';
-$SUBROUTINE_MAPPINGS{nathost_nat_ip} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{natIP}';
+$SUBROUTINE_MAPPINGS{nathost_public_ip_address} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{publicIPaddress}';
+$SUBROUTINE_MAPPINGS{nathost_internal_ip_address} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{internalIPaddress}';
 $SUBROUTINE_MAPPINGS{nathost_resource_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{resource}{id}';
 $SUBROUTINE_MAPPINGS{nathost_resource_subid} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{resource}{subid}';
 $SUBROUTINE_MAPPINGS{nathost_resourcetype_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{nathost}{resource}{resourcetype}{id}';

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS.pm Thu Dec 11 18:28:52 2014
@@ -2664,6 +2664,8 @@ sub process_connect_methods {
 	my $reservation_id = $self->data->get_reservation_id();
 	my $request_state = $self->data->get_request_state_name();
 	my $computer_node_name = $self->data->get_computer_node_name();
+	my $nathost_hostname = $self->data->get_nathost_hostname(0);
+	my $nathost_public_ip_address = $self->data->get_nathost_public_ip_address(0);
 	
 	# Retrieve the connect method info hash
 	my $connect_method_info = $self->data->get_connect_methods();
@@ -2672,25 +2674,6 @@ sub process_connect_methods {
 		return;
 	}
 	
-	# Check if NAT is used
-	my $nathost_hostname;
-	my $computer_private_ip_address;
-	if ($self->nathost_os(0)) {
-		$nathost_hostname = $self->data->get_nathost_hostname();
-		# Call configure_nat - this adds a chain for the reservation if one does not already exist
-		if (!$self->nathost_os->firewall->configure_nat()) {
-			notify($ERRORS{'WARNING'}, 0, "failed to configure NAT on $nathost_hostname");
-			return;
-		}
-		
-		# Retrieve the computer's private IP address
-		$computer_private_ip_address = $self->get_private_ip_address();
-		if (!$computer_private_ip_address) {
-			notify($ERRORS{'WARNING'}, 0, "failed to retrieve private IP address of computer $computer_node_name, unable to configure NAT port forwarding");
-			return;
-		}
-	}
-	
 	my $remote_ip = shift;
 	if (!$remote_ip) {
 		notify($ERRORS{'OK'}, 0, "reservation remote IP address is not defined, connect methods will be available from any IP address");
@@ -2710,6 +2693,38 @@ sub process_connect_methods {
 		$overwrite = 0;
 	}
 	
+	# Check if NAT is used
+	my $computer_ip_address;
+	if ($nathost_hostname) {
+		if (!$self->nathost_os(0)) {
+			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, $computer_node_name is assigned to NAT host $nathost_hostname but NAT host OS object is not available");
+			return;
+		}
+		elsif (!$self->nathost_os->firewall()) {
+			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, $computer_node_name is assigned to NAT host $nathost_hostname but NAT host OS's firewall object is not available");
+			return;
+		}
+		
+		# Get the IP address used to communicate between the NAT host and computer
+		$computer_ip_address = $self->get_public_ip_address();
+		if (!$computer_ip_address) {
+			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to retrieve public (internal NAT) IP address of computer $computer_node_name, unable to configure NAT port forwarding");
+			return;
+		}
+		
+		# Perform general NAT configuration
+		if (!$self->nathost_os->firewall->configure_nat()) {
+			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname");
+			return;
+		}
+		
+		# Perform reservation-specific NAT configuration
+		if (!$self->nathost_os->firewall->configure_nat_reservation()) {
+			notify($ERRORS{'WARNING'}, 0, "unable to process connect methods, failed to configure NAT on $nathost_hostname for this reservation");
+			return;
+		}
+	}
+	
 	CONNECT_METHOD: for my $connect_method_id (sort keys %{$connect_method_info} ) {
 		my $connect_method = $connect_method_info->{$connect_method_id};
 		
@@ -2788,24 +2803,22 @@ sub process_connect_methods {
 					}
 				}
 				
-				my $nat_public_port = $connect_method->{connectmethodport}{$connect_method_port_id}{natport}{publicport};
-				if ($nat_public_port) {
-					if (!$self->nathost_os(0)) {
-						notify($ERRORS{'WARNING'}, 0, "connect method info contains NAT port information but NAT OS object is not available to control $nathost_hostname");
+				# Configure NAT port forwarding if NAT is being used
+				if ($nathost_hostname) {
+					my $nat_public_port = $connect_method->{connectmethodport}{$connect_method_port_id}{natport}{publicport};
+					if (!defined($nat_public_port)) {
+						notify($ERRORS{'WARNING'}, 0, "$computer_node_name is assigned to NAT host $nathost_hostname but connect method info does not contain NAT port information:\n" . format_data($connect_method));
 						return;
 					}
-					if ($self->nathost_os->firewall->add_nat_port_forward($protocol, $nat_public_port, $computer_private_ip_address, $port, $reservation_id)) {
-						notify($ERRORS{'OK'}, 0, "configured forwarded NAT port on $nathost_hostname: $protocol/$nat_public_port --> $computer_private_ip_address:$port");
+					
+					if ($self->nathost_os->firewall->add_nat_port_forward($protocol, $nat_public_port, $computer_ip_address, $port, $reservation_id)) {
+						notify($ERRORS{'OK'}, 0, "NAT port forwarding configured on $nathost_hostname for '$name' connect method: $nat_public_port --> $computer_ip_address:$port ($protocol)");
 					}
 					else {
-						notify($ERRORS{'WARNING'}, 0, "failed to process '$name' connect method, unable to configure forwarded NAT port on $nathost_hostname: $protocol/$nat_public_port --> $computer_private_ip_address:$port");
+						notify($ERRORS{'WARNING'}, 0, "failed to configure NAT port forwarding on $nathost_hostname for '$name' connect method: $nathost_public_ip_address:$nat_public_port --> $computer_ip_address:$port ($protocol)");
 						return;
 					}
 				}
-				elsif ($self->nathost_os(0)) {
-					notify($ERRORS{'WARNING'}, 0, "NAT OS object is not available but connect method info does not contain NAT port information:\n" . format_data($connect_method_info));
-					return;
-				}
 			}
 		}
 	}

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux.pm Thu Dec 11 18:28:52 2014
@@ -269,7 +269,7 @@ sub firewall {
 		# Attempt to create the object
 		my $firewall_object;
 		eval {
-			$firewall_object = ($firewall_perl_package)->new({data_structure => $self->data, base_package => ref($self)})
+			$firewall_object = ($firewall_perl_package)->new({data_structure => $self->data, base_package => ref($self), os => $self->os})
 		};
 		
 		if ($EVAL_ERROR) {
@@ -3118,6 +3118,163 @@ sub service_exists {
 }
 
 #/////////////////////////////////////////////////////////////////////////////
+
+=head2 is_service_enabled
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Determines if a service is enabled on the computer.
+
+=cut
+
+sub is_service_enabled {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name was not passed as an argument");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my ($init_module_index) = $self->service_exists($service_name);
+	if (!defined($init_module_index)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is enabled, it does not exist on $computer_node_name");
+		return;
+	}
+	
+	my $init_module = ($self->get_init_modules())[$init_module_index];
+	if (!$init_module->can('service_enabled')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is enabled on $computer_node_name, " . ref($init_module) . " module does not implement a 'service_running' subroutine");
+		return;
+	}
+	return $init_module->service_enabled($service_name);
+}
+
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 is_service_running
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Determines if a service is running on the computer.
+
+=cut
+
+sub is_service_running {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name was not passed as an argument");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my ($init_module_index) = $self->service_exists($service_name);
+	if (!defined($init_module_index)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is running, it does not exist on $computer_node_name");
+		return;
+	}
+	
+	my $init_module = ($self->get_init_modules())[$init_module_index];
+	if (!$init_module->can('service_running')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is running on $computer_node_name, " . ref($init_module) . " module does not implement a 'service_running' subroutine");
+		return;
+	}
+	return $init_module->service_running($service_name);
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 enable_service
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Enables a service on the computer.
+
+=cut
+
+sub enable_service {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name was not passed as an argument");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my ($init_module_index) = $self->service_exists($service_name);
+	if (!defined($init_module_index)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to enable '$service_name' service, it does not exist on $computer_node_name");
+		return;
+	}
+	
+	my $init_module = ($self->get_init_modules())[$init_module_index];
+	if (!$init_module->can('_enable_service')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to enable '$service_name' service on $computer_node_name, " . ref($init_module) . " module does not implement an '_enable_service' subroutine");
+		return;
+	}
+	return $init_module->_enable_service($service_name);
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 disable_service
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : disables a service on the computer.
+
+=cut
+
+sub disable_service {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name was not passed as an argument");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my ($init_module_index) = $self->service_exists($service_name);
+	if (!defined($init_module_index)) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable '$service_name' service, it does not exist on $computer_node_name");
+		return;
+	}
+	
+	my $init_module = ($self->get_init_modules())[$init_module_index];
+	if (!$init_module->can('_disable_service')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable '$service_name' service on $computer_node_name, " . ref($init_module) . " module does not implement an '_disable_service' subroutine");
+		return;
+	}
+	return $init_module->_disable_service($service_name);
+}
+
+#/////////////////////////////////////////////////////////////////////////////
 
 =head2 start_service
 

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=1644715&r1=1644714&r2=1644715&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 Dec 11 18:28:52 2014
@@ -144,6 +144,11 @@ sub insert_rule {
 	# Add the parameters to the command
 	for my $parameter (sort keys %{$arguments->{parameters}}) {
 		my $value = $arguments->{parameters}{$parameter};
+		
+		if ($parameter =~ /^\!/) {
+			$command .= " !";
+			$parameter =~ s/^\!//;
+		}
 		$command .= " --$parameter $value";
 	}
 	
@@ -596,202 +601,238 @@ sub configure_nat {
 		return 0;
 	}
 	
-	my $reservation_id = $self->data->get_reservation_id();
 	my $computer_name = $self->data->get_computer_hostname();
 	
-	my $table_info = $self->get_table_info('nat');
-	if (!$table_info) {
+	my $public_ip_address = $self->os->data->get_nathost_public_ip_address();
+	my $internal_ip_address = $self->os->data->get_nathost_internal_ip_address(0);
+	if (!$internal_ip_address) {
+		notify($ERRORS{'DEBUG'}, 0, "unable to automatically configure NAT, nathost.internalIPaddress is not set");
+		return 1;
+	}
+	
+	# Enable IP port forwarding
+	if (!$self->enable_ip_forwarding()) {
+		notify($ERRORS{'WARNING'}, 0, "unable to configure NAT host $computer_name, failed to enable IP forwarding");
+		return;
+	}
+	
+	my $nat_table_info = $self->get_table_info('nat');
+	if (!$nat_table_info) {
 		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT on $computer_name, nat table info could not be retrieved");
 		return;
 	}
-	elsif (!defined($table_info->{PREROUTING})) {
-		notify($ERRORS{'WARNING'}, 0, "unable to configure NAT on $computer_name, nat table does not contain a PREROUTING chain:\n" . format_data($table_info));
+	elsif (!defined($nat_table_info->{PREROUTING})) {
+		notify($ERRORS{'WARNING'}, 0, "unable to configure NAT on $computer_name, nat table does not contain a PREROUTING chain:\n" . format_data($nat_table_info));
 		return;
 	}
-	elsif (!defined($table_info->{POSTROUTING})) {
-		notify($ERRORS{'WARNING'}, 0, "unable to configure NAT on $computer_name, nat table does not contain a POSTROUTING chain:\n" . format_data($table_info));
+	elsif (!defined($nat_table_info->{POSTROUTING})) {
+		notify($ERRORS{'WARNING'}, 0, "unable to configure NAT on $computer_name, nat table does not contain a POSTROUTING chain:\n" . format_data($nat_table_info));
 		return;
 	}
 	
 	# Check if NAT has previously been configured
-	my $nat_previously_configured = 0;
-	for my $rule_specification (@{$table_info->{POSTROUTING}{rules}}) {
+	for my $rule_specification (@{$nat_table_info->{POSTROUTING}{rules}}) {
 		if ($rule_specification =~ /MASQUERADE/) {
-			$nat_previously_configured = 1;
 			notify($ERRORS{'DEBUG'}, 0, "POSTROUTING chain in nat table contains a MASQUERADE rule, assuming NAT has already been configured: $rule_specification");
-			last;
+			return 1;
 		}
 	}
-	if (!$nat_previously_configured) {
-		my $private_interface_name = $self->get_private_interface_name();
-		my $private_ip_address = $self->get_private_ip_address();
-		my $public_interface_name = $self->get_public_interface_name();
-		my $public_ip_address = $self->get_public_ip_address();
+	
+	# Figure out the public and internal interface names
+	my $public_interface_name;
+	my $internal_interface_name;
+	my $network_configuration = $self->get_network_configuration();
+	for my $interface_name (keys %$network_configuration) {
+		my @ip_addresses = keys %{$network_configuration->{$interface_name}{ip_address}};
 		
-		my $natport_ranges_variable = get_variable('natport_ranges') || '49152-65535';
-		my $destination_ports = '';
-		for my $natport_range (split(/[,;]+/, $natport_ranges_variable)) {
-			my ($start_port, $end_port) = $natport_range =~ /(\d+)-(\d+)/g;
-			if (!defined($start_port)) {
-				notify($ERRORS{'WARNING'}, 0, "unable to parse NAT port range: '$natport_range'");
-				next;
-			}
-			$destination_ports .= "," if ($destination_ports);
-			$destination_ports .= "$start_port:$end_port";
+		# Check if the interface is assigned the nathost.publicIPaddress
+		if (grep { $_ eq $public_ip_address } @ip_addresses) {
+			$public_interface_name = $interface_name;
 		}
 		
-		
-		if (!$self->insert_rule({
-			'table' => 'nat',
-			'chain' => 'POSTROUTING',
-			'parameters' => {
-				'out-interface' => $private_interface_name,
-				'jump' => 'MASQUERADE',
+		# If nathost.internalIPaddress is set, check if interface is assigned matching IP address
+		if (grep { $_ eq $internal_ip_address } @ip_addresses) {
+			$internal_interface_name = $interface_name;
+		}
+	}
+	if (!$public_interface_name) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT host $computer_name, no interface is assigned the public IP address configured in the nathost table: $public_ip_address\n" . format_data($network_configuration));
+		return;
+	}
+	if (!$internal_interface_name) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT host $computer_name, no interface is assigned the internal IP address configured in the nathost table: $internal_ip_address\n" . format_data($network_configuration));
+		return;
+	}
+	
+	
+	my $natport_ranges_variable = get_variable('natport_ranges') || '49152-65535';
+	my $destination_ports = '';
+	for my $natport_range (split(/[,;]+/, $natport_ranges_variable)) {
+		my ($start_port, $end_port) = $natport_range =~ /(\d+)-(\d+)/g;
+		if (!defined($start_port)) {
+			notify($ERRORS{'WARNING'}, 0, "unable to parse NAT port range: '$natport_range'");
+			next;
+		}
+		$destination_ports .= "," if ($destination_ports);
+		$destination_ports .= "$start_port:$end_port";
+	}
+	
+	
+	if (!$self->insert_rule({
+		'table' => 'nat',
+		'chain' => 'POSTROUTING',
+		'parameters' => {
+			'out-interface' => $public_interface_name,
+			'jump' => 'MASQUERADE',
+		},
+		'match_extensions' => {
+			'comment' => {
+				'comment' => "change IP of outbound $public_interface_name packets to NAT host IP address $public_ip_address",
 			},
-			'match_extensions' => {
-				'comment' => {
-					'comment' => "change IP of outbound private $private_interface_name packets to NAT host private IP address $private_interface_name",
-				},
+		},
+	})) {
+		return;
+	}
+	
+	if (!$self->insert_rule({
+		'chain' => 'INPUT',
+		'parameters' => {
+			'in-interface' => $public_interface_name,
+			'destination' => $public_ip_address,
+			'jump' => 'ACCEPT',
+			'protocol' => 'tcp',
+		},
+		'match_extensions' => {
+			'state' => {
+				'state' => 'RELATED,ESTABLISHED',
 			},
-		})) {
-			return;
-		}
-		
-		if (!$self->insert_rule({
-			'chain' => 'INPUT',
-			'parameters' => {
-				'in-interface' => $public_interface_name,
-				'destination' => $public_ip_address,
-				'jump' => 'ACCEPT',
-				'protocol' => 'tcp',
+			'multiport' => {
+				'destination-ports' => $destination_ports,
 			},
-			'match_extensions' => {
-				'state' => {
-					'state' => 'RELATED,ESTABLISHED',
-				},
-				'multiport' => {
-					'destination-ports' => $destination_ports,
-				},
+		},
+	})) {
+		return;
+	}
+	
+	if (!$self->insert_rule({
+		'chain' => 'INPUT',
+		'parameters' => {
+			'in-interface' => $public_interface_name,
+			'destination' => $public_ip_address,
+			'jump' => 'ACCEPT',
+			'protocol' => 'udp',
+		},
+		'match_extensions' => {
+			'state' => {
+				'state' => 'RELATED,ESTABLISHED',
 			},
-		})) {
-			return;
-		}
-		
-		if (!$self->insert_rule({
-			'chain' => 'INPUT',
-			'parameters' => {
-				'in-interface' => $public_interface_name,
-				'destination' => $public_ip_address,
-				'jump' => 'ACCEPT',
-				'protocol' => 'udp',
+			'multiport' => {
+				'destination-ports' => $destination_ports,
 			},
-			'match_extensions' => {
-				'state' => {
-					'state' => 'RELATED,ESTABLISHED',
-				},
-				'multiport' => {
-					'destination-ports' => $destination_ports,
-				},
+		},
+	})) {
+		return;
+	}
+	
+	if (!$self->insert_rule({
+		'chain' => 'FORWARD',
+		'parameters' => {
+			'in-interface' => $public_interface_name,
+			'out-interface' => $internal_interface_name,
+			'jump' => 'ACCEPT',
+		},
+		'match_extensions' => {
+			'state' => {
+				'state' => 'NEW,RELATED,ESTABLISHED',
 			},
-		})) {
-			return;
-		}
-		
-		if (!$self->insert_rule({
-			'chain' => 'FORWARD',
-			'parameters' => {
-				'in-interface' => $public_interface_name,
-				'out-interface' => $private_interface_name,
-				'jump' => 'ACCEPT',
+			'comment' => {
+				'comment' => "forward inbound packets from public $public_interface_name to internal $internal_interface_name",
 			},
-			'match_extensions' => {
-				'state' => {
-					'state' => 'NEW,RELATED,ESTABLISHED',
-				},
-				'comment' => {
-					'comment' => "forward inbound packets from public $public_interface_name to private $private_interface_name",
-				},
-			},	
-		})) {
-			return;
-		}
-		
-		if (!$self->insert_rule({
-			'chain' => 'FORWARD',
-			'parameters' => {
-				'in-interface' => $private_interface_name,
-				'out-interface' => $public_interface_name,
-				'jump' => 'ACCEPT',
+		},	
+	})) {
+		return;
+	}
+	
+	if (!$self->insert_rule({
+		'chain' => 'FORWARD',
+		'parameters' => {
+			'in-interface' => $internal_interface_name,
+			'out-interface' => $public_interface_name,
+			'jump' => 'ACCEPT',
+		},
+		'match_extensions' => {
+			'state' => {
+				'state' => 'NEW,RELATED,ESTABLISHED',
 			},
-			'match_extensions' => {
-				'comment' => {
-					'comment' => "forward outbound packets from private $private_interface_name to public $public_interface_name",
-				},
+			'comment' => {
+				'comment' => "forward outbound packets from internal $internal_interface_name to public $public_interface_name",
 			},
-		})) {
-			return;
-		}
-		
-		#if (!$self->insert_rule({
-		#	'chain' => 'INPUT',
-		#	'parameters' => {
-		#		'in-interface' => $public_interface_name,
-		#	},
-		#	'target_extensions' => {
-		#		'REJECT' => {
-		#			'reject-with' => "icmp-host-prohibited",
-		#		},
-		#	},
-		#})) {
-		#	return;
-		#}
-		#
-		#if (!$self->insert_rule({
-		#	'chain' => 'FORWARD',
-		#	'target_extensions' => {
-		#		'REJECT' => {
-		#			'reject-with' => "icmp-host-prohibited",
-		#		},
-		#	},
-		#})) {
-		#	return;
-		#}
+		},
+	})) {
+		return;
+	}
+	
+	notify($ERRORS{'DEBUG'}, 0, "successfully configured NAT on $computer_name");
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 configure_nat_reservation
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Adds a chain named after the reservation ID to the nat table.
+               Adds a rule to the PREROUTING table to jump to the reservation
+               chain.
+
+=cut
+
+sub configure_nat_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 = $self->data->get_reservation_id();
+	my $computer_name = $self->data->get_computer_hostname();
+	
+	my $nat_table_info = $self->get_table_info('nat');
+	if (!$nat_table_info) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT host $computer_name for reservation, nat table information could not be retrieved");
+		return;
 	}
 	
 	# Check if chain for reservation has already been created
-	if (defined($table_info->{$reservation_id})) {
-		notify($ERRORS{'DEBUG'}, 0, "'$reservation_id' chain already exists in nat table on $computer_name for this reservation");
+	if (defined($nat_table_info->{$reservation_id})) {
+		notify($ERRORS{'DEBUG'}, 0, "'$reservation_id' chain already exists in nat table on $computer_name");
 	}
-	else {
-		if (!$self->create_chain('nat', $reservation_id)) {
-			notify($ERRORS{'WARNING'}, 0, "failed to configure NAT on $computer_name, '$reservation_id' chain could not be created in nat table for this reservation");
-			return;
-		}
+	elsif (!$self->create_chain('nat', $reservation_id)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT host $computer_name for reservation, failed to add '$reservation_id' chain to nat table");
+		return;
 	}
 	
 	# Check if rule to jump to reservation's chain already exists in the PREROUTING table
-	my $jump_previously_configured = 0;
-	for my $rule_specification (@{$table_info->{PREROUTING}{rules}}) {
+	for my $rule_specification (@{$nat_table_info->{PREROUTING}{rules}}) {
 		if ($rule_specification =~ /-j $reservation_id(\s|$)/) {
-			$jump_previously_configured = 1;
 			notify($ERRORS{'DEBUG'}, 0, "PREROUTING chain in nat table on $computer_name already contains a rule to jump to '$reservation_id' chain: $rule_specification");
-			last;
+			return 1;;
 		}
 	}
-	if (!$jump_previously_configured) {
-		if (!$self->insert_rule({
-			'table' => 'nat',
-			'chain' => 'PREROUTING',
-			'parameters' => {
-				'jump' => $reservation_id,
-			},
-		})) {
-			notify($ERRORS{'WARNING'}, 0, "unable to configure NAT on $computer_name, failed to create rule in PREROUTING chain in nat table to jump to '$reservation_id' chain");
-			return;
-		}
+	
+	# Add a rule to the nat PREROUTING chain
+	if (!$self->insert_rule({
+		'table' => 'nat',
+		'chain' => 'PREROUTING',
+		'parameters' => {
+			'jump' => $reservation_id,
+		},
+	})) {
+		notify($ERRORS{'WARNING'}, 0, "failed to configure NAT host $computer_name for reservation, failed to create rule in PREROUTING chain in nat table to jump to '$reservation_id' chain");
+		return;
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "successfully configured NAT on $computer_name for reservation");
 	return 1;
 }
 
@@ -845,11 +886,11 @@ sub add_nat_port_forward {
 		'parameters' => {
 			'protocol' => $protocol,
 			'in-interface' => $public_interface_name,
-			'destination' => $public_ip_address,
+			#'destination' => $public_ip_address,
 		},
 		'match_extensions' => {
 			'comment' => {
-				'comment' => "change destination address: $public_ip_address:$source_port --> $destination_ip_address:$destination_port ($protocol)",
+				'comment' => "forward: $public_ip_address:$source_port --> $destination_ip_address:$destination_port ($protocol)",
 			},
 			$protocol => {
 				'destination-port' => $source_port,

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/SysV.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/SysV.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/SysV.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/SysV.pm Thu Dec 11 18:28:52 2014
@@ -132,7 +132,7 @@ sub get_service_names {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 enable_service
+=head2 _enable_service
 
  Parameters  : $service_name
  Returns     : boolean
@@ -141,7 +141,7 @@ sub get_service_names {
 
 =cut
 
-sub enable_service {
+sub _enable_service {
 	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");
@@ -181,7 +181,7 @@ sub enable_service {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 disable_service
+=head2 _disable_service
 
  Parameters  : $service_name
  Returns     : boolean
@@ -190,7 +190,7 @@ sub enable_service {
 
 =cut
 
-sub disable_service {
+sub _disable_service {
 	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");
@@ -230,6 +230,113 @@ sub disable_service {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 service_enabled
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'chkconfig --list <$service_name>' to determine if a
+               service is enabled.
+
+=cut
+
+sub service_enabled {
+	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 $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $command = "chkconfig --list $service_name";
+	my ($exit_status, $output) = $self->execute($command, 0);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if '$service_name' service is enabled on $computer_node_name: $command");
+		return;
+	}
+	elsif (grep(/(error reading information|No such file)/i, @$output)) {
+		# Output if the service does not exist: 'error reading information on service httpdx: No such file or directory'
+		notify($ERRORS{'WARNING'}, 0, "'$service_name' service does not exist on $computer_node_name");
+		return;
+	}
+	elsif (grep(/^$service_name\s+.*3:on/i, @$output)) {
+		# Output if the service is enabled: '<service name>    0:off   1:off   2:on    3:on    4:on    5:on    6:off'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is enabled on $computer_node_name");
+		return 1;
+	}
+	elsif (grep(/^$service_name\s+.*3:off/i, @$output)) {
+		# Output if the service is disabled: '<service name>    0:off   1:off   2:off   3:off   4:off   5:off   6:off'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is not enabled on $computer_node_name");
+		return 0;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine if '$service_name' service is enabled on $computer_node_name, exit status: $exit_status, output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 service_running
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'service <$service_name> status' to determine if a
+               service is running.
+
+=cut
+
+sub service_running {
+	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 $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	# Enable the service
+	my $command = "service $service_name status";
+	my ($exit_status, $output) = $self->execute($command, 0);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if '$service_name' service is running on $computer_node_name: $command");
+		return;
+	}
+	elsif (grep(/(error reading information|No such file)/i, @$output)) {
+		# Output if the service does not exist: 'error reading information on service httpdx: No such file or directory'
+		notify($ERRORS{'WARNING'}, 0, "'$service_name' service does not exist on $computer_node_name");
+		return;
+	}
+	elsif (grep(/is running/i, @$output)) {
+		# Output if the service is running: '<service name> is running'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is running on $computer_node_name");
+		return 1;
+	}
+	elsif (grep(/is not running/i, @$output)) {
+		# Output if the service is not running: '<service name> is not running'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is not running on $computer_node_name");
+		return 0;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine if '$service_name' service is running on $computer_node_name, exit status: $exit_status, output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 add_service
 
  Parameters  : $service_name
@@ -559,7 +666,7 @@ sub add_ext_sshd_service {
 	# Add the service
 	return unless $self->add_service('ext_sshd');
 	
-	return $self->enable_service('ext_sshd');
+	return $self->_enable_service('ext_sshd');
 }
 
 #/////////////////////////////////////////////////////////////////////////////

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/Upstart.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/Upstart.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/Upstart.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/Upstart.pm Thu Dec 11 18:28:52 2014
@@ -236,7 +236,7 @@ sub start_service {
 		notify($ERRORS{'DEBUG'}, 0, "'$service_name' is already running on $computer_node_name");
 		return 1;
 	}
-	elsif (grep(/process \d+/i, @$output)) {
+	elsif (grep(/running/i, @$output)) {
 		# Output if the service was started: '<service name> start/running, process <PID>'
 		notify($ERRORS{'DEBUG'}, 0, "started '$service_name' service on $computer_node_name");
 		return 1;
@@ -422,6 +422,211 @@ sub add_ext_sshd_service {
 }
 
 #/////////////////////////////////////////////////////////////////////////////
+
+=head2 service_running
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'initctl status <$service_name>' to determine if the
+               service is running.
+
+=cut
+
+sub service_running {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	$service_name = $SERVICE_NAME_MAPPINGS->{$service_name} || $service_name;
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $command = "initctl status $service_name";
+	my ($exit_status, $output) = $self->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if '$service_name' service is enabled on $computer_node_name");
+		return;
+	}
+	elsif (grep(/Unknown job/i, @$output)) {
+		# Output if the service doesn't exist: 'initctl: Unknown job: <service name>'
+		notify($ERRORS{'WARNING'}, 0, "'$service_name' service does not exist on $computer_node_name");
+		return;
+	}
+	elsif (grep(/running/i, @$output)) {
+		# Output if the service is running: '<service name> start/running, process <PID>'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is running on $computer_node_name");
+		return 1;
+	}
+	elsif (grep(/stop/i, @$output)) {
+		# Output if the service is not running: '<service name>stop/waiting'
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is not running $computer_node_name");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is running on $computer_node_name, exit status: $exit_status, command: '$command', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 service_enabled
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'initctl show-config <$service_name>' to determine if the
+               service is enabled.
+
+=cut
+
+sub service_enabled {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	$service_name = $SERVICE_NAME_MAPPINGS->{$service_name} || $service_name;
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	# Check if an override file exists and contains 'manual'
+	my $service_override_file_path = "/etc/init/$service_name.override";
+	if ($self->file_exists($service_override_file_path)) {
+		my @override_file_contents = $self->get_file_contents($service_override_file_path);
+		if (!@override_file_contents) {
+			notify($ERRORS{'WARNING'}, 0, "failed to retrieve contents of $service_override_file_path from $computer_node_name");
+		}
+		else {
+			if (grep(/manual/i, @override_file_contents)) {
+				notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is not enabled on $computer_node_name, $service_override_file_path exists and contains 'manual'");
+				return 0;
+			}
+		}
+	}
+	
+	my $command = "initctl show-config $service_name";
+	my ($exit_status, $output) = $self->execute($command);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if '$service_name' service is enabled on $computer_node_name");
+		return;
+	}
+	elsif (grep(/Unknown job/i, @$output)) {
+		# Output if the service doesn't exist: 'initctl: Unknown job: <service name>'
+		notify($ERRORS{'WARNING'}, 0, "'$service_name' service does not exist on $computer_node_name");
+		return;
+	}
+	elsif (grep(/start on/i, @$output)) {
+		# Output if the service is enabled:
+		# <service name>
+		#   start on (filesystem or runlevel [2345])
+		#   stop on runlevel [!2345]
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is enabled on $computer_node_name");
+		return 1;
+	}
+	elsif (!grep(/^initctl:/, @$output)) {
+		# Output if the service is not enabled:
+		# <service name>
+		#   stop on runlevel [06]
+		notify($ERRORS{'DEBUG'}, 0, "'$service_name' service is not enabled $computer_node_name");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to determine if '$service_name' service is enabled on $computer_node_name, exit status: $exit_status, command: '$command', output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _enable_service
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : 
+
+=cut
+
+sub _enable_service {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	$service_name = $SERVICE_NAME_MAPPINGS->{$service_name} || $service_name;
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $service_override_file_path = "/etc/init/$service_name.override";
+	
+	if (!$self->file_exists($service_override_file_path)) {
+		return 1;
+	}
+	if ($self->delete_file($service_override_file_path)) {
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to enable '$service_name' service, unable to delete override file: $service_override_file_path");
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _disable_service
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : 
+
+=cut
+
+sub _disable_service {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return 0;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	$service_name = $SERVICE_NAME_MAPPINGS->{$service_name} || $service_name;
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $service_override_file_path = "/etc/init/$service_name.override";
+	
+	if ($self->create_text_file($service_override_file_path, "manual\n")) {
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unable to disable '$service_name' service, failed to create override file: $service_override_file_path");
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
 
 1;
 __END__

Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Linux/init/systemd.pm Thu Dec 11 18:28:52 2014
@@ -130,7 +130,103 @@ sub get_service_names {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 enable_service
+=head2 service_running
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'systemctl is-active' to determines if a service is
+               running.
+
+=cut
+
+sub service_running {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $command = "systemctl is-active $service_name.service";
+	my ($exit_status, $output) = $self->execute($command, 0);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if $service_name service is running on $computer_node_name");
+		return;
+	}
+	
+	# Output should either be 'active' or 'inactive
+	if (grep(/inactive/, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "$service_name service is not running on $computer_node_name");
+		return 0;
+	}
+	elsif (grep(/active/, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "$service_name service is running on $computer_node_name");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine if $service_name service is running on $computer_node_name, output does not contain 'active' or 'inactive':\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 service_enabled
+
+ Parameters  : $service_name
+ Returns     : boolean
+ Description : Calls 'systemctl is-enabled' to determines if a service is
+               enabled.
+
+=cut
+
+sub service_enabled {
+	my $self = shift;
+	if (ref($self) !~ /linux/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my $service_name = shift;
+	if (!$service_name) {
+		notify($ERRORS{'WARNING'}, 0, "service name argument was not supplied");
+		return;
+	}
+	
+	my $computer_node_name = $self->data->get_computer_node_name();
+	
+	my $command = "systemctl is-enabled $service_name.service";
+	my ($exit_status, $output) = $self->execute($command, 0);
+	if (!defined($output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to execute command to determine if $service_name service is running on $computer_node_name");
+		return;
+	}
+	
+	# Output should either be 'enabled' or 'disabled
+	if (grep(/disabled/, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "$service_name service is disabled on $computer_node_name");
+		return 0;
+	}
+	elsif (grep(/enabled/, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "$service_name service is enabled on $computer_node_name");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to determine if $service_name service is enabled on $computer_node_name, output does not contain 'enabled' or 'disabled':\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _enable_service
 
  Parameters  : $service_name
  Returns     : boolean
@@ -139,7 +235,7 @@ sub get_service_names {
 
 =cut
 
-sub enable_service {
+sub _enable_service {
 	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");
@@ -179,7 +275,7 @@ sub enable_service {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 disable_service
+=head2 _disable_service
 
  Parameters  : $service_name
  Returns     : boolean
@@ -188,7 +284,7 @@ sub enable_service {
 
 =cut
 
-sub disable_service {
+sub _disable_service {
 	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");
@@ -254,7 +350,7 @@ sub delete_service {
 	# Disable the service before deleting it
 	if ($self->service_exists($service_name)) {
 		$self->stop_service($service_name) || return;
-		$self->disable_service($service_name) || return;
+		$self->_disable_service($service_name) || return;
 	}
 	
 	# Delete the service configuration file
@@ -478,7 +574,7 @@ sub add_ext_sshd_service {
 	
 	$self->_daemon_reload();
 	
-	return $self->enable_service('ext_sshd');
+	return $self->_enable_service('ext_sshd');
 }
 
 #/////////////////////////////////////////////////////////////////////////////

Modified: vcl/trunk/managementnode/lib/VCL/Module/State.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/State.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/State.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/State.pm Thu Dec 11 18:28:52 2014
@@ -151,6 +151,10 @@ sub initialize {
 		# Allow the OS object to access the nathost_os object
 		# This is necessary to allow the OS code to call the subroutines to forward ports
 		$self->os->set_nathost_os($self->nathost_os());
+		
+		# Allow the NAT host OS object to access the OS object
+		# This allows the NAT host OS object to retrieve info about the computer being loaded
+		$nathost_os->set_os($self->os());
 	}
 	
 	# Create a provisioning object

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1644715&r1=1644714&r2=1644715&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Thu Dec 11 18:28:52 2014
@@ -182,6 +182,7 @@ our @EXPORT = qw(
 	hash_to_xml_string
 	help
 	hostname_to_ip_address
+	insert_nathost
 	insert_reload_request
 	insert_request
 	insertloadlog
@@ -6838,6 +6839,8 @@ sub get_computer_info {
 		'module',
 		'schedule',
 		'platform',
+		'resource',
+		'resourcetype',
 	);
 	
 	# Construct the select statement
@@ -6877,6 +6880,15 @@ ON (
 )
 LEFT JOIN (schedule) ON (schedule.id = computer.scheduleid)
 LEFT JOIN (module AS predictivemodule) ON (predictivemodule.id = computer.predictivemoduleid)
+LEFT JOIN (
+   resource,
+	resourcetype
+)
+ON (
+   resource.subid = computer.id
+	AND resource.resourcetypeid = resourcetype.id
+	AND resourcetype.name = 'computer'
+)
 
 WHERE
 computer.deleted != '1'
@@ -6929,6 +6941,9 @@ EOF
 		elsif ($table eq 'predictivemodule' ) {
 			$computer_info->{predictive}{module}{$column} = $value;
 		}
+		elsif ($table eq 'resourcetype') {
+			$computer_info->{resource}{$table}{$column} = $value;
+		}
 		else {
 			$computer_info->{$table}{$column} = $value;
 		}
@@ -7018,7 +7033,8 @@ EOF
                  "datedeleted" => undef,
                  "deleted" => 0,
                  "id" => 2,
-                 "natIP" => "x.x.x.x",
+                 "publicIPaddress" => "x.x.x.x",
+                 "internalIPaddress" => "x.x.x.x",
                  "nathostcomputermap" => {
                    "computerid" => 3591,
                    "nathostid" => 2
@@ -7218,7 +7234,7 @@ sub populate_reservation_natport {
 	my $nathost_info = $request_info->{reservation}{$reservation_id}{computer}{nathost};
 	my $nathost_id = $nathost_info->{id};
 	my $nathost_hostname = $nathost_info->{HOSTNAME};
-	my $nathost_public_ip_address = $nathost_info->{natIP};
+	my $nathost_public_ip_address = $nathost_info->{publicIPaddress};
 	
 	# Make sure the nathost info is defined
 	if (!defined($nathost_id)) {
@@ -7392,7 +7408,80 @@ EOF
 		return 0;
 	}
 }
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 insert_nathost
+
+ Parameters  : $resource_type, $resource_identifier
+ Returns     : boolean
+ Description : Inserts an entry into the nathost table. The $resource_type
+               argument must either be 'computer' or 'managementnode'.
+
+=cut
+
+sub insert_nathost {
+	my ($resource_type, $resource_identifier) = @_;
+	if (!defined($resource_type)) {
+		notify($ERRORS{'WARNING'}, 0, "resource type argument was not supplied");
+		return;
+	}
+	elsif ($resource_type !~ /^(computer|managementnode)$/) {
+		notify($ERRORS{'WARNING'}, 0, "resource type argument is not valid: '$resource_type', it must either be 'computer' or 'managementnode'");
+		return;
+	}
+	elsif (!defined($resource_identifier)) {
+		notify($ERRORS{'WARNING'}, 0, "resource identifier argument was not supplied");
+		return;
+	}
 	
+	my $resource_id;
+	my $public_ip_address;
+	if ($resource_type eq 'computer') {
+		my $computer_info = get_computer_info($resource_identifier);
+		if (!$computer_info) {
+			notify($ERRORS{'WARNING'}, 0, "failed to insert nathost, info could not be retrieved for computer '$resource_identifier'");
+			return;
+		}
+		$resource_id = $computer_info->{resource}{id};
+		$public_ip_address = $computer_info->{IPaddress};
+	}
+	elsif ($resource_type eq 'managementnode') {
+		my $management_node_info = get_management_node_info($resource_identifier);
+		if (!$management_node_info) {
+			notify($ERRORS{'WARNING'}, 0, "failed to insert nathost, info could not be retrieved for management node '$resource_identifier'");
+			return;
+		}
+		$resource_id = $management_node_info->{resource_id};
+		$public_ip_address = $management_node_info->{IPaddress};
+	}
+	
+	my $insert_statement = <<EOF;
+INSERT IGNORE INTO
+nathost
+(
+   resourceid,
+   publicIPaddress
+)
+VALUES
+(
+   '$resource_id',
+	'$public_ip_address'
+)
+ON DUPLICATE KEY UPDATE
+resourceid=VALUES(resourceid),
+publicIPaddress='$public_ip_address'
+EOF
+
+	if (database_execute($insert_statement)) {
+		notify($ERRORS{'DEBUG'}, 0, "inserted entry into nathost table for $resource_type, resource ID: $resource_id, NAT host public IP address: $public_ip_address");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to insert entry into nathost table for $resource_type, resource ID: $resource_id, NAT host public IP address: $public_ip_address");
+		return 0;
+	}
+}
 
 #/////////////////////////////////////////////////////////////////////////////
 
@@ -10179,7 +10268,7 @@ EOF
 		$connect_method_info->{$connectmethod_id}{RETRIEVAL_TIME} = $timestamp;
 	}
 
-	notify($ERRORS{'DEBUG'}, 0, "retrieved connect method info:\n" . format_data($connect_method_info));
+	#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};
 }