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/18 20:26:21 UTC

svn commit: r1646516 - in /vcl/trunk/managementnode/lib/VCL: Module/State.pm inuse.pm reserved.pm utils.pm

Author: arkurth
Date: Thu Dec 18 19:26:20 2014
New Revision: 1646516

URL: http://svn.apache.org/r1646516
Log:
VCL-16
Updated code which inserts computerloadlog 'acknowledgetimeout', 'initialconnecttimeout' and 'reconnecttimeout' so the the timestamp of these entries is used to determine when to stop checking for ack or connection.

Removed condition in utils.pm::check_time where it would return 'poll' whenever request.laststate = reserved. This is no longer necessary.

Moved initial connection check from inuse.pm to reserved.pm. This fixed problems where the state was left in inuse/inuse after the first connection check causing the computer to always be reloaded.

Moved user_connected and check_imaging_request subroutines from inuse.pm to State.pm since it is now used by both inuse.pm and reserved.pm.

VCL-174
Removed computer IP address from email messages sent to users. This information would not be accurate when NAT is used.

Other
Cleaned up utils.pm::insertloadlog.

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/State.pm
    vcl/trunk/managementnode/lib/VCL/inuse.pm
    vcl/trunk/managementnode/lib/VCL/reserved.pm
    vcl/trunk/managementnode/lib/VCL/utils.pm

Modified: vcl/trunk/managementnode/lib/VCL/Module/State.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/State.pm?rev=1646516&r1=1646515&r2=1646516&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/State.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/State.pm Thu Dec 18 19:26:20 2014
@@ -53,6 +53,7 @@ use strict;
 use warnings;
 use diagnostics;
 use English '-no_match_vars';
+use POSIX qw(floor);
 
 use VCL::utils;
 use VCL::DataStructure;
@@ -225,13 +226,114 @@ sub initialize {
 		notify($ERRORS{'DEBUG'}, 0, "child reservation, not updating request state to 'pending'");
 	}
 	
-	notify($ERRORS{'DEBUG'}, 0, "computerloadlog states after state object is initialized:\n" . format_data(get_request_loadstate_names($request_id)));
+	#notify($ERRORS{'DEBUG'}, 0, "computerloadlog states after state object is initialized:\n" . format_data(get_request_loadstate_names($request_id)));
 	
 	return 1;
 } ## end sub initialize
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 user_connected
+
+ Parameters  : none
+ Returns     : boolean
+ Description : Checks if the user is connected to the computer. If the user
+               isn't connected and this is a cluster request, checks if a
+               computerloadlog 'connected' entry exists for any of the other
+               reservations in cluster.
+
+=cut
+
+sub user_connected {
+	my $self = shift;
+	if (ref($self) !~ /VCL::/) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a class method of a VCL object");
+		return;
+	}
+	
+	my $request_id                   = $self->data->get_request_id();
+	my @reservation_ids              = $self->data->get_reservation_ids();
+	my $reservation_id               = $self->data->get_reservation_id();
+	my $reservation_lastcheck        = $self->data->get_reservation_lastcheck_time();
+	my $reservation_count            = $self->data->get_request_reservation_count();
+	my $computer_id                  = $self->data->get_computer_id();
+	my $computer_short_name          = $self->data->get_computer_short_name();
+	my $server_request_id            = $self->data->get_server_request_id();
+	my $request_duration_epoch_secs  = $self->data->get_request_duration_epoch();
+	my $request_duration_hrs         = floor($request_duration_epoch_secs / 60 / 60);
+	my $ignore_connections_gte_min   = $self->os->get_timings('ignore_connections_gte');
+	my $ignore_connections_gte       = floor($ignore_connections_gte_min / 60);
+	
+	# Check if user deleted the request
+	$self->state_exit() if is_request_deleted($request_id);
+	
+	# Check if this is an imaging request, causes process to exit if state or laststate = image
+	$self->check_imaging_request();
+	
+	# Check if this is a server request, causes process to exit if server request
+	if ($server_request_id) {
+		notify($ERRORS{'DEBUG'}, 0, "server reservation detected, set as user is connected");
+		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
+		return 1;
+	}
+	
+	# If duration is >= 24 hrs set as connected and return
+	if ($request_duration_hrs >= $ignore_connections_gte) {
+		notify($ERRORS{'OK'}, 0, "reservation duration is $request_duration_hrs hrs is >= to ignore_connections setting $ignore_connections_gte hrs, skipping inuse checks");
+		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
+		return 1;
+	}	
+
+	# Check if the user has connected to the reservation being processed
+	if ($self->os->is_user_connected()) {
+		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
+		
+		# If this is a cluster request, update the lastcheck value for all reservations
+		# This signals the other reservation inuse processes that a connection was detected on another computer
+		if ($reservation_count > 1) {
+			update_reservation_lastcheck(@reservation_ids);
+		}
+		return 1;
+	}
+	
+	if ($reservation_count > 1) {
+		my $current_reservation_lastcheck = get_current_reservation_lastcheck($reservation_id);
+		if ($current_reservation_lastcheck ne $reservation_lastcheck) {
+			notify($ERRORS{'DEBUG'}, 0, "user connected to another computer in the cluster, reservation.lastcheck updated since this process began: $reservation_lastcheck --> $current_reservation_lastcheck");
+			return 1;
+		}
+		else {
+			notify($ERRORS{'DEBUG'}, 0, "no connection to another computer in the cluster detected, reservation.lastcheck has not been updated since this process began: $reservation_lastcheck");
+		}
+	}
+	
+	return 0;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 check_imaging_request
+
+ Parameters  : none
+ Returns     : boolean
+ Description : The inuse process exits if the request state or laststate are set
+               to image, or if the forimaging flag has been set.
+
+=cut
+
+sub check_imaging_request {
+	my $self = shift;
+	my $request_id = $self->data->get_request_id();
+	
+	my $imaging_result = is_request_imaging($request_id);
+	if ($imaging_result eq 'image') {
+		notify($ERRORS{'OK'}, 0, "image creation process has begun, exiting");
+		$self->state_exit();
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 reservation_failed
 
  Parameters  : $message
@@ -704,7 +806,7 @@ sub state_exit {
 			# Do this to ensure that reservations are not processed again quickly after this process exits
 			# For cluster requests, the parent may have had to wait a while for child processes to exit
 			# Resetting reservation.lastcheck causes reservations to wait the full interval between inuse checks
-			if ($request_state_name_new =~ /(inuse)/) {
+			if ($request_state_name_new =~ /(reserved|inuse)/) {
 				update_reservation_lastcheck(@reservation_ids);
 			}
 			
@@ -806,7 +908,7 @@ sub DESTROY {
 			my @reservation_ids = $self->data->get_reservation_ids();
 			if (@reservation_ids && $request_id) {
 				$self->state_exit();
-				notify($ERRORS{'DEBUG'}, 0, "computerloadlog states remaining after process exits:\n" . format_data(get_request_loadstate_names($request_id)));
+				#notify($ERRORS{'DEBUG'}, 0, "computerloadlog states remaining after process exits:\n" . format_data(get_request_loadstate_names($request_id)));
 			}
 			elsif (!$SETUP_MODE) {
 				notify($ERRORS{'WARNING'}, 0, "failed to retrieve the reservation ID, computerloadlog 'begin' rows not removed");

Modified: vcl/trunk/managementnode/lib/VCL/inuse.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/inuse.pm?rev=1646516&r1=1646515&r2=1646516&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/inuse.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/inuse.pm Thu Dec 18 19:26:20 2014
@@ -103,10 +103,8 @@ sub process {
 	
 	my $request_id              = $self->data->get_request_id();
 	my $request_state_name      = $self->data->get_request_state_name();
-	my $request_laststate_name  = $self->data->get_request_laststate_name();
 	my $request_start           = $self->data->get_request_start_time();
 	my $request_end             = $self->data->get_request_end_time();
-	my $request_data            = $self->data->get_request_data();
 	my $request_forimaging      = $self->data->get_request_forimaging();
 	my $request_checkuser       = $self->data->get_request_checkuser();
 	my $reservation_id          = $self->data->get_reservation_id();
@@ -117,24 +115,7 @@ sub process {
 	my $computer_id             = $self->data->get_computer_id();
 	my $computer_short_name     = $self->data->get_computer_short_name();
 	
-	
-	my $connect_timeout_seconds;
-	if ($request_laststate_name eq 'reserved') {
-		$connect_timeout_seconds = $self->os->get_timings('initialconnecttimeout');
-		notify($ERRORS{'DEBUG'}, 0, "checking for initial user connection, using 'initialconnecttimeout' variable: $connect_timeout_seconds seconds");
-	}
-	else {
-		$connect_timeout_seconds = $self->os->get_timings('reconnecttimeout');
-		notify($ERRORS{'DEBUG'}, 0, "checking for subsequent connection, using 'reconnecttimeout' variable: $connect_timeout_seconds seconds");
-	}
-
-	# Make sure connect timeout is long enough
-	# It has to be a bit longer than the ~5 minute period between inuse checks due to cluster reservations
-	# If too short, a user may be connected to one computer in a cluster and another inuse process times out before the connected computer is checked
-	my $connect_timeout_minutes = ceil($connect_timeout_seconds / 60);
-	
-	# Connect timeout must be in whole minutes
-	$connect_timeout_seconds = ($connect_timeout_minutes * 60);
+	my $connect_timeout_seconds = $self->os->get_timings('reconnecttimeout');
 	
 	# Check if reboot operation was requested
 	if ($request_state_name =~ /reboot/) {
@@ -158,6 +139,14 @@ sub process {
 		$self->state_exit('inuse', 'inuse');
 	}
 	
+	# Make sure connect timeout is long enough
+	# It has to be a bit longer than the ~5 minute period between inuse checks due to cluster reservations
+	# If too short, a user may be connected to one computer in a cluster and another inuse process times out before the connected computer is checked
+	my $connect_timeout_minutes = ceil($connect_timeout_seconds / 60);
+	
+	# Connect timeout must be in whole minutes
+	$connect_timeout_seconds = ($connect_timeout_minutes * 60);
+	
 	my $now_epoch_seconds = time;
 	
 	my $request_start_epoch_seconds = convert_to_epoch_seconds($request_start);
@@ -219,7 +208,7 @@ sub process {
 			$self->state_exit() if is_request_deleted($request_id);
 			
 			# Check if this is an imaging request, causes process to exit if state or laststate = image
-			$self->_check_imaging_request();
+			$self->check_imaging_request();
 			
 			# Get the current request end time from the database
 			my $current_request_end = get_request_end($request_id);
@@ -272,6 +261,19 @@ sub process {
 		notify($ERRORS{'DEBUG'}, 0, "skipping end time notice interval check, request duration: $request_duration_hours hours, parent reservation: $is_parent_reservation");
 	}
 	
+	# Check if the computer is responding to SSH
+	# Skip connection checks if the computer is not responding to SSH
+	# This prevents a reservatino from timing out if the user is actually connected but SSH from the management node isn't working
+	if (!$self->os->is_ssh_responding()) {
+		notify($ERRORS{'OK'}, 0, "$computer_short_name is not responding to SSH, skipping user connection check");
+		$self->state_exit('inuse', 'inuse');
+	}
+	
+	# Update the firewall if necessary - this is what allows a user to click Connect from different locations
+	if ($self->os->can('firewall_compare_update')) {
+		$self->os->firewall_compare_update();
+	}
+	
 	# Compare remaining minutes to connect timeout
 	# Connect timeout may be longer than 15 minutes
 	# Make sure connect timeout doesn't run into the end time notice
@@ -286,35 +288,16 @@ sub process {
 		$self->state_exit('inuse', 'inuse');
 	}
 	
-	# Check if the computer is responding to SSH
-	# Skip connection checks if the computer is not responding to SSH
-	# This prevents a reservatino from timing out if the user is actually connected but SSH from the management node isn't working
-	if (!$self->os->is_ssh_responding()) {
-		notify($ERRORS{'OK'}, 0, "$computer_short_name is not responding to SSH, skipping user connection check");
-		$self->state_exit('inuse', 'inuse');
-	}
-	
-	# Update the firewall if necessary - this is what allows a user to click Connect from different locations
-	# Not necessary first time inuse state is processed after reserved
-	if ($request_laststate_name ne 'reserved' && $self->os->can('firewall_compare_update')) {
-		$self->os->firewall_compare_update();
-	}
-	
 	# TODO: fix user connection checking for cluster requests
-	if ($reservation_count > 1 && $request_laststate_name ne 'reserved') {
+	if ($reservation_count > 1) {
 		notify($ERRORS{'OK'}, 0, "skipping user connection check for cluster request");
 		$self->state_exit('inuse', 'inuse');
 	}
 	
-	# Insert connecttimeout immediately before beginning to check for user connection
+	# Insert reconnecttimeout immediately before beginning to check for user connection
 	# Web uses timestamp of this to determine when next to refresh the page
 	# Important because page should refresh as soon as possible to reservation timing out
-	if ($request_laststate_name eq 'reserved') {
-		insertloadlog($reservation_id, $computer_id, "connecttimeout", "begin initial connection timeout ($connect_timeout_seconds seconds)");
-	}
-	else {
-		insertloadlog($reservation_id, $computer_id, "connecttimeout", "begin reconnection timeout ($connect_timeout_seconds seconds)");
-	}
+	insertloadlog($reservation_id, $computer_id, "reconnecttimeout", "begin reconnection timeout ($connect_timeout_seconds seconds)");
 	
 	# Check to see if user is connected. user_connected will true(1) for servers and requests > 24 hours
 	my $user_connected = $self->code_loop_timeout(sub{$self->user_connected()}, [], "waiting for user to connect to $computer_short_name", $connect_timeout_seconds, 15);
@@ -329,38 +312,24 @@ sub process {
 		elsif ($server_request_id) {
 			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, server reservation");
 		}
-		elsif ($request_forimaging && $request_laststate_name ne 'reserved') {
+		elsif ($request_forimaging) {
 			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, imaging reservation");
 		}
-		elsif ($reservation_count > 1 && $request_laststate_name ne 'reserved') {
+		elsif ($reservation_count > 1) {
 			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, cluster reservation");
 		}
 		elsif ($request_duration_hours > 24) {
 			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, request duration: $request_duration_hours hours");
 		}
+		elsif (is_request_deleted($request_id)) {
+			$self->state_exit();
+		}
 		else {
-			$self->state_exit() if is_request_deleted($request_id);
-			
 			# Update reservation lastcheck, otherwise request will be processed immediately again
 			update_reservation_lastcheck($reservation_id);
 			
-			if ($request_laststate_name eq 'reserved') {
-				$self->_notify_user_no_login();
-				$self->state_exit('timeout', 'timeout', 'nologin');
-			}
-			else {
-				$self->_notify_user_timeout();
-				$self->state_exit('timeout', 'timeout', 'timeout');
-			}
-		}
-	}
-	
-	# If this is the first time the inuse state is being processed, tighten up the firewall
-	if ($request_laststate_name eq 'reserved') {
-		# Process the connect methods again, lock the firewall down to the address the user connected from
-		my $remote_ip = $self->data->get_reservation_remote_ip();
-		if (!$self->os->process_connect_methods($remote_ip, 1)) {
-			notify($ERRORS{'CRITICAL'}, 0, "failed to process connect methods after user connected to computer");
+			$self->_notify_user_timeout();
+			$self->state_exit('timeout', 'inuse', 'timeout');
 		}
 	}
 	
@@ -369,85 +338,6 @@ sub process {
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 user_connected
-
- Parameters  : none
- Returns     : boolean
- Description : Checks if the user is connected to the computer. If the user
-               isn't connected and this is a cluster request, checks if a
-               computerloadlog 'connected' entry exists for any of the other
-               reservations in cluster.
-
-=cut
-
-sub user_connected {
-	my $self = shift;
-	if (ref($self) !~ /VCL::/) {
-		notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a class method of a VCL object");
-		return;
-	}
-	
-	my $request_id                   = $self->data->get_request_id();
-	my @reservation_ids              = $self->data->get_reservation_ids();
-	my $reservation_id               = $self->data->get_reservation_id();
-	my $reservation_lastcheck        = $self->data->get_reservation_lastcheck_time();
-	my $reservation_count            = $self->data->get_request_reservation_count();
-	my $computer_id                  = $self->data->get_computer_id();
-	my $computer_short_name          = $self->data->get_computer_short_name();
-	my $server_request_id            = $self->data->get_server_request_id();
-	my $request_duration_epoch_secs  = $self->data->get_request_duration_epoch();
-	my $request_duration_hrs         = floor($request_duration_epoch_secs / 60 / 60);
-	my $ignore_connections_gte_min   = $self->os->get_timings('ignore_connections_gte');
-	my $ignore_connections_gte       = floor($ignore_connections_gte_min / 60);
-	
-	# Check if user deleted the request
-	$self->state_exit() if is_request_deleted($request_id);
-	
-	# Check if this is an imaging request, causes process to exit if state or laststate = image
-	$self->_check_imaging_request();
-	
-	# Check if this is a server request, causes process to exit if server request
-	if ($server_request_id) {
-		notify($ERRORS{'DEBUG'}, 0, "server reservation detected, set as user is connected");
-		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
-		return 1;
-	}
-	
-	# If duration is >= 24 hrs set as connected and return
-	if ($request_duration_hrs >= $ignore_connections_gte) {
-		notify($ERRORS{'OK'}, 0, "reservation duration is $request_duration_hrs hrs is >= to ignore_connections setting $ignore_connections_gte hrs, skipping inuse checks");
-		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
-		return 1;
-	}	
-
-	# Check if the user has connected to the reservation being processed
-	if ($self->os->is_user_connected()) {
-		insertloadlog($reservation_id, $computer_id, "connected", "user connected to $computer_short_name");
-		
-		# If this is a cluster request, update the lastcheck value for all reservations
-		# This signals the other reservation inuse processes that a connection was detected on another computer
-		if ($reservation_count > 1) {
-			update_reservation_lastcheck(@reservation_ids);
-		}
-		return 1;
-	}
-	
-	if ($reservation_count > 1) {
-		my $current_reservation_lastcheck = get_current_reservation_lastcheck($reservation_id);
-		if ($current_reservation_lastcheck ne $reservation_lastcheck) {
-			notify($ERRORS{'DEBUG'}, 0, "user connected to another computer in the cluster, reservation lastcheck updated since this process began: $reservation_lastcheck --> $current_reservation_lastcheck");
-			return 1;
-		}
-		else {
-			notify($ERRORS{'DEBUG'}, 0, "no connection to another computer in the cluster detected, reservation lastcheck has not been updated since this process began: $reservation_lastcheck");
-		}
-	}
-	
-	return 0;
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 _notify_user_endtime
 
  Parameters  : $request_data_hash_reference, $notice_interval
@@ -477,7 +367,6 @@ sub _notify_user_endtime {
 	
 	my $computer_short_name             = $self->data->get_computer_short_name();
 	my $computer_type                   = $self->data->get_computer_type();
-	my $computer_public_ip_address      = $self->data->get_computer_public_ip_address();
 	my $image_os_name                   = $self->data->get_image_os_name();
 	my $image_prettyname                = $self->data->get_image_prettyname();
 	my $image_os_type                   = $self->data->get_image_os_type();
@@ -488,7 +377,7 @@ sub _notify_user_endtime {
 	my $user_emailnotices               = $self->data->get_user_emailnotices();
 	my $user_imtype_name                = $self->data->get_user_imtype_name();
 	my $user_im_id                      = $self->data->get_user_im_id();
-	my $request_forimaging              = $self->_check_imaging_request();	
+	my $request_forimaging              = $self->check_imaging_request();	
 	my $request_id                      = $self->data->get_request_id();
 	
 	my $message;
@@ -585,7 +474,6 @@ sub _notify_user_disconnect {
 	
 	my $computer_short_name             = $self->data->get_computer_short_name();
 	my $computer_type                   = $self->data->get_computer_type();
-	my $computer_public_ip_address      = $self->data->get_computer_public_ip_address();
 	my $image_os_name                   = $self->data->get_image_os_name();
 	my $image_prettyname                = $self->data->get_image_prettyname();
 	my $image_os_type                   = $self->data->get_image_os_type();
@@ -597,7 +485,7 @@ sub _notify_user_disconnect {
 	my $user_imtype_name                = $self->data->get_user_imtype_name();
 	my $user_im_id                      = $self->data->get_user_im_id();
 	my $is_parent_reservation           = $self->data->is_parent_reservation();
-	my $request_forimaging              = $self->_check_imaging_request();
+	my $request_forimaging              = $self->check_imaging_request();
 	
 	my $disconnect_string;
 	if ($disconnect_time == 0) {
@@ -711,7 +599,6 @@ sub _notify_user_timeout {
 	
 	my $computer_short_name             = $self->data->get_computer_short_name();
 	my $computer_type                   = $self->data->get_computer_type();
-	my $computer_public_ip_address      = $self->data->get_computer_public_ip_address();
 	my $image_os_name                   = $self->data->get_image_os_name();
 	my $image_prettyname                = $self->data->get_image_prettyname();
 	my $image_os_type                   = $self->data->get_image_os_type();
@@ -726,7 +613,7 @@ sub _notify_user_timeout {
 	
 	my $message = <<"EOF";
 
-Your reservation has timed out due to inactivity for image $image_prettyname at address $computer_public_ip_address.
+Your reservation has timed out due to inactivity for image $image_prettyname.
 
 To make another reservation, please revisit:
 $user_affiliation_sitewwwaddress
@@ -786,7 +673,6 @@ sub _notify_user_request_ended {
 	my $computer_id                     = $self->data->get_computer_id();
 	my $computer_short_name             = $self->data->get_computer_short_name();
 	my $computer_type                   = $self->data->get_computer_type();
-	my $computer_public_ip_address      = $self->data->get_computer_public_ip_address();
 	my $image_os_name                   = $self->data->get_image_os_name();
 	my $image_prettyname                = $self->data->get_image_prettyname();
 	my $image_os_type                   = $self->data->get_image_os_type();
@@ -891,12 +777,11 @@ sub _notify_user_no_login {
 	my $affiliation_sitewwwaddress = $self->data->get_user_affiliation_sitewwwaddress();
 	my $affiliation_helpaddress    = $self->data->get_user_affiliation_helpaddress();
 	my $image_prettyname           = $self->data->get_image_prettyname();
-	my $computer_public_ip_address = $self->data->get_computer_public_ip_address();
 	my $is_parent_reservation      = $self->data->is_parent_reservation();
 
 	my $message = <<"EOF";
 
-Your reservation has timed out for image $image_prettyname at address $computer_public_ip_address because no initial connection was made.
+Your reservation has timed out for image $image_prettyname because no initial connection was made.
 
 To make another reservation, please revisit $affiliation_sitewwwaddress.
 
@@ -932,28 +817,6 @@ EOF
 
 #/////////////////////////////////////////////////////////////////////////////
 
-=head2 _check_imaging_request
-
- Parameters  : none
- Returns     : boolean
- Description : The inuse process exits if the request state or laststate are set
-               to image, or if the forimaging flag has been set.
-
-=cut
-
-sub _check_imaging_request {
-	my $self = shift;
-	my $request_id = $self->data->get_request_id();
-	
-	my $imaging_result = is_request_imaging($request_id);
-	if ($imaging_result eq 'image') {
-		notify($ERRORS{'OK'}, 0, "image creation process has begun, exiting");
-		$self->state_exit();
-	}
-}
-
-#/////////////////////////////////////////////////////////////////////////////
-
 =head2 _start_imaging_request
 
  Parameters  : none

Modified: vcl/trunk/managementnode/lib/VCL/reserved.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/reserved.pm?rev=1646516&r1=1646515&r2=1646516&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/reserved.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/reserved.pm Thu Dec 18 19:26:20 2014
@@ -71,6 +71,7 @@ use warnings;
 use diagnostics;
 
 use VCL::utils;
+use POSIX qw(strftime);
 
 ##############################################################################
 
@@ -92,16 +93,20 @@ use VCL::utils;
 sub process {
 	my $self = shift;
 	
-	my $request_id                  = $self->data->get_request_id();
-	my $request_data                = $self->data->get_request_data();
-	my $request_logid               = $self->data->get_request_log_id();
-	my $reservation_id              = $self->data->get_reservation_id();
-	my $reservation_count           = $self->data->get_reservation_count();
-	my $computer_id                 = $self->data->get_computer_id();
-	my $computer_short_name         = $self->data->get_computer_short_name();
-	my $is_parent_reservation       = $self->data->is_parent_reservation();
-	my $server_request_id           = $self->data->get_server_request_id();
-	my $acknowledge_timeout_seconds = $self->os->get_timings('acknowledgetimeout');
+	my $request_id                      = $self->data->get_request_id();
+	my $request_data                    = $self->data->get_request_data();
+	my $request_logid                   = $self->data->get_request_log_id();
+	my $request_checkuser               = $self->data->get_request_checkuser();
+	my $reservation_id                  = $self->data->get_reservation_id();
+	my $reservation_count               = $self->data->get_reservation_count();
+	my $computer_id                     = $self->data->get_computer_id();
+	my $computer_short_name             = $self->data->get_computer_short_name();
+	my $is_parent_reservation           = $self->data->is_parent_reservation();
+	my $server_request_id               = $self->data->get_server_request_id();
+	my $imagemeta_checkuser             = $self->data->get_imagemeta_checkuser();
+	
+	my $acknowledge_timeout_seconds     = $self->os->get_timings('acknowledgetimeout');
+	my $initial_connect_timeout_seconds = $self->os->get_timings('initialconnecttimeout');
 	
 	# Update the log loaded time to now for this request
 	update_log_loaded_time($request_logid);
@@ -118,15 +123,22 @@ sub process {
 	
 	# Wait for the user to acknowledge the request by clicking Connect button or from API
 	my $user_acknowledged = $self->code_loop_timeout(sub{$self->user_acknowledged()}, [], 'waiting for user acknowledgement', $acknowledge_timeout_seconds, 1, 10);
+	if (!$user_acknowledged) {
+		$self->_notify_user_timeout($request_data);
+		$self->state_exit('timeout', 'reserved', 'noack');
+	}
 	
 	# Add noinitialconnection and then delete acknowledgetimeout
 	insertloadlog($reservation_id, $computer_id, "noinitialconnection", "user clicked Connect");
 	delete_computerloadlog_reservation($reservation_id, 'acknowledgetimeout');
 	
-	if (!$user_acknowledged) {
-		$self->_notify_user_timeout($request_data);
-		switch_state($request_data, 'timeout', 'timeout', 'noack', 1);
-	}
+	# Capture the exact time user acknowledgement was detected
+	my $connection_check_start_epoch_seconds = time;
+	
+	# Insert initialconnecttimeout immediately after user acknowledged
+	# Web uses timestamp of this to determine when next to refresh the page
+	# The timestamp of this computerloadlog entry will be used to determine when to timeout the connection checking during the inuse state
+	insertloadlog($reservation_id, $computer_id, "initialconnecttimeout", "begin initial connection timeout ($initial_connect_timeout_seconds seconds)");
 	
 	# Call OS module's grant_access() subroutine which adds user accounts to computer
 	if ($self->os->can("grant_access") && !$self->os->grant_access()) {
@@ -144,10 +156,65 @@ sub process {
 		$self->reservation_failed("OS module post_reserve failed");
 	}
 
-	# Add a 'reserved' computerloadlog entry
+	# Add a 'postreserve' computerloadlog entry
 	# Do this last - important for cluster reservation timing
 	# Parent's reserved process will loop until this exists for all child reservations
-	insertloadlog($reservation_id, $computer_id, "postreserve", "$computer_short_name post reserve successfully");
+	insertloadlog($reservation_id, $computer_id, "postreserve", "$computer_short_name post reserve successful");
+	
+	# Get the current time
+	my $now_epoch_seconds = time;
+	
+	# Calculate the exact time when connection checking should end
+	my $connection_check_end_epoch_seconds = ($connection_check_start_epoch_seconds + $initial_connect_timeout_seconds);
+	my $connect_timeout_remaining_seconds = ($connection_check_end_epoch_seconds - $now_epoch_seconds);
+	
+	my $now_string                       = strftime('%H:%M:%S', localtime($now_epoch_seconds));
+	my $connection_check_start_string    = strftime('%H:%M:%S', localtime($connection_check_start_epoch_seconds));
+	my $connection_check_end_string      = strftime('%H:%M:%S', localtime($connection_check_end_epoch_seconds));
+	my $connect_timeout_string           = strftime('%H:%M:%S', gmtime($initial_connect_timeout_seconds));
+	my $connect_timeout_remaining_string = strftime('%H:%M:%S', gmtime($connect_timeout_remaining_seconds));
+	
+	notify($ERRORS{'DEBUG'}, 0, "beginning to check for initial user connection:\n" .
+		"connection check start    :   $connection_check_start_string\n" .
+		"connect timeout total     : + $connect_timeout_string\n" .
+		"--------------------------------------\n" .
+		"connection check end      : = $connection_check_end_string\n" .
+		"current time              : - $now_string\n" .
+		"--------------------------------------\n" .
+		"connect timeout remaining : = $connect_timeout_remaining_string ($connect_timeout_remaining_seconds seconds)\n"
+	);
+	
+	# Check to see if user is connected. user_connected will true(1) for servers and requests > 24 hours
+	my $user_connected = $self->code_loop_timeout(sub{$self->user_connected()}, [], "waiting for initial user connection to $computer_short_name", $connect_timeout_remaining_seconds, 15);
+	
+	# Delete the connecttimeout immediately after acknowledgement loop ends
+	delete_computerloadlog_reservation($reservation_id, 'connecttimeout');
+	
+	if (!$user_connected) {
+		if (!$imagemeta_checkuser || !$request_checkuser) {
+			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, imagemeta checkuser: $imagemeta_checkuser, request checkuser: $request_checkuser");
+		}
+		elsif ($server_request_id) {
+			notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, server reservation");
+		}
+		elsif (is_request_deleted($request_id)) {
+			$self->state_exit();
+		}
+		else {
+			$self->_notify_user_no_login();
+			$self->state_exit('timeout', 'reserved', 'nologin');
+		}
+	}
+	
+	# Update reservation lastcheck, otherwise inuse request will be processed immediately again
+	update_reservation_lastcheck($reservation_id);
+	
+	# Tighten up the firewall
+	# Process the connect methods again, lock the firewall down to the address the user connected from
+	my $remote_ip = $self->data->get_reservation_remote_ip();
+	if (!$self->os->process_connect_methods($remote_ip, 1)) {
+		notify($ERRORS{'CRITICAL'}, 0, "failed to process connect methods after user connected to computer");
+	}
 	
 	# For cluster reservations, the parent must wait until all child reserved processes have exited
 	# Otherwise, the state will change to inuse while the child processes are still finishing up the reserved state
@@ -163,7 +230,7 @@ sub process {
 	}
 	
 	# Change the request and computer state to inuse then exit
-	switch_state($request_data, 'inuse', 'inuse', '', 1);
+	$self->state_exit('inuse');
 } ## end sub process
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -291,12 +358,11 @@ sub _notify_user_timeout {
 	my $affiliation_sitewwwaddress = $self->data->get_user_affiliation_sitewwwaddress();
 	my $affiliation_helpaddress    = $self->data->get_user_affiliation_helpaddress();
 	my $image_prettyname           = $self->data->get_image_prettyname();
-	my $computer_public_ip_address = $self->data->get_computer_public_ip_address();
 	my $is_parent_reservation      = $self->data->is_parent_reservation();
 
 	my $message = <<"EOF";
 
-Your reservation has timed out for image $image_prettyname at address $computer_public_ip_address because no initial connection was made.
+Your reservation has timed out for image $image_prettyname because no initial connection was made.
 
 To make another reservation, please revisit $affiliation_sitewwwaddress.
 

Modified: vcl/trunk/managementnode/lib/VCL/utils.pm
URL: http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/utils.pm?rev=1646516&r1=1646515&r2=1646516&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/utils.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/utils.pm Thu Dec 18 19:26:20 2014
@@ -174,6 +174,8 @@ our @EXPORT = qw(
 	get_request_current_state_name
 	get_request_end
 	get_request_info
+	get_reservation_computerloadlog_entries
+	get_reservation_computerloadlog_time
 	get_request_loadstate_names
 	get_reservation_accounts
 	get_resource_groups
@@ -1127,9 +1129,6 @@ sub check_time {
 			notify($ERRORS{'DEBUG'}, 0, "reservation will end in 10 minutes or less ($end_diff_minutes)");
 			return "end";
 		}
-		elsif ($request_laststate_name =~ /reserved/) {
-			return "poll";
-		}
 		else {
 			# End time is more than 10 minutes in the future
 			if($serverrequest) {	
@@ -1148,20 +1147,19 @@ sub check_time {
 				}
 				else {
 					return 0;
-					}
+				}
 			}
 			else {
-			#notify($ERRORS{'DEBUG'}, 0, "reservation will end in more than 10 minutes ($end_diff_minutes)");
+				#notify($ERRORS{'DEBUG'}, 0, "reservation will end in more than 10 minutes ($end_diff_minutes)");
 				my $general_inuse_check_time = ($ENV{management_node_info}->{GENERAL_INUSE_CHECK} * -1);
-
 				if ($lastcheck_diff_minutes <= $general_inuse_check_time) {
-				#notify($ERRORS{'DEBUG'}, 0, "reservation was last checked more than 5 minutes ago ($lastcheck_diff_minutes)");
-				return "poll";
-			}
-			else {
-				#notify($ERRORS{'DEBUG'}, 0, "reservation has been checked within the past 5 minutes ($lastcheck_diff_minutes)");
-				return 0;
-			}
+					#notify($ERRORS{'DEBUG'}, 0, "reservation was last checked more than 5 minutes ago ($lastcheck_diff_minutes)");
+					return "poll";
+				}
+				else {
+					#notify($ERRORS{'DEBUG'}, 0, "reservation has been checked within the past 5 minutes ($lastcheck_diff_minutes)");
+					return 0;
+				}
 			}
 		} ## end else [ if ($end_diff_minutes <= 10)
 	} ## end elsif ($request_state_name =~ /inuse|imageinuse/) [ if ($request_state_name =~ /new|imageprep|reload|tomaintenance|tovmhostinuse/)
@@ -2701,105 +2699,61 @@ sub notify_via_im {
 
 =head2 insertloadlog
 
- Parameters  : $resid,   $computerid, $loadstatename, $additionalinfo
- Returns     : 0 or 1
- Description : accepts info from processes to update the loadlog table
+ Parameters  : $reservation_id, $computer_id, $loadstatename, $additional_info
+ Returns     : boolean
+ Description : Inserts an entry into the computerloadlog table.
 
 =cut
 
 sub insertloadlog {
-	my ($resid,   $computerid, $loadstatename, $additionalinfo) = @_;
-	my ($package, $filename,   $line,          $sub)            = caller(0);
-
-	# Check the parameters
-	if (!(defined($resid))) {
-		notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, reservation id is not defined");
-		return 0;
-	}
-	elsif (!($resid)) {
-		notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, reservation id is 0");
-		return 0;
-	}
-
-	if (!(defined($computerid))) {
-		notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, computer id is not defined");
-		return 0;
-	}
-	elsif (!($computerid)) {
-		notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, computer id is 0");
-		return 0;
+	my ($reservation_id, $computer_id, $loadstatename, $additional_info) = @_;
+	if (!defined($reservation_id)) {
+		notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not supplied");
+		return;
 	}
-
-	if (!(defined($additionalinfo)) || !$additionalinfo) {
-		notify($ERRORS{'WARNING'}, 0, "additionalinfo is either not defined or 0, using 'no additional info'");
-		$additionalinfo = 'no additional info';
+	elsif (!defined($computer_id)) {
+		notify($ERRORS{'WARNING'}, 0, "computer ID argument was not supplied");
+		return;
 	}
-
-	my $loadstateid;
-	if (!(defined($loadstatename)) || !$loadstatename) {
-		notify($ERRORS{'WARNING'}, 0, "loadstatename is either not defined or 0, using NULL");
-		$loadstatename = 'NULL';
-		$loadstateid   = 'NULL';
+	elsif (!defined($loadstatename)) {
+		notify($ERRORS{'WARNING'}, 0, "computerloadstate name argument was not supplied");
+		return;
 	}
-	else {
-		# loadstatename was specified as a parameter
-		# Check if the loadstatename exists in the computerloadstate table
-		my $select_statement = "
-      SELECT DISTINCT
-      computerloadstate.id
-      FROM
-      computerloadstate
-      WHERE
-      computerloadstate.loadstatename = '$loadstatename'
-      ";
-
-		my @selected_rows = database_select($select_statement);
-		if ((scalar @selected_rows) == 0) {
-			notify($ERRORS{'WARNING'}, 0, "computerloadstate table entry does not exist: $loadstatename, using NULL");
-			$loadstateid   = 'NULL';
-			$loadstatename = 'NULL';
-		}
-		else {
-			$loadstateid = $selected_rows[0]{id};
-			#notify($ERRORS{'DEBUG'}, 0, "computerloadstate id found: id=$loadstateid, name=$loadstatename");
-		}
-	} ## end else [ if (!(defined($loadstatename)) || !$loadstatename)
+	$additional_info = 'no additional info' unless defined($additional_info);
 
-	# Escape any single quotes in additionalinfo
-	$additionalinfo =~ s/\'/\\\'/g;
+	# Escape any special characters in additional info
+	$additional_info = quotemeta $additional_info;
 
 	# Assemble the SQL statement
-	my $insert_loadlog_statement = "
-   INSERT INTO
-   computerloadlog
-   (
-      reservationid,
-      computerid,
-      loadstateid,
-      timestamp,
-      additionalinfo
-   )
-   VALUES
-   (
-      '$resid',
-      '$computerid',
-      '$loadstateid',
-      NOW(),
-      '$additionalinfo'
-   )
-   ";
+	my $insert_loadlog_statement = <<EOF;
+INSERT INTO
+computerloadlog
+(
+	reservationid,
+	computerid,
+	loadstateid,
+	timestamp,
+	additionalinfo
+)
+VALUES
+(
+	'$reservation_id',
+	'$computer_id',
+	(SELECT id FROM computerloadstate WHERE loadstatename = '$loadstatename'),
+	NOW(),
+	'$additional_info'
+)
+EOF
 
 	# Execute the insert statement, the return value should be the id of the computerloadlog row that was inserted
-	my $loadlog_id = database_execute($insert_loadlog_statement);
-	if ($loadlog_id) {
-		notify($ERRORS{'OK'}, 0, "inserted computer=$computerid, $loadstatename, $additionalinfo");
+	if (database_execute($insert_loadlog_statement)) {
+		notify($ERRORS{'OK'}, 0, "inserted '$loadstatename' computerloadlog entry");
+		return 1;
 	}
 	else {
-		notify($ERRORS{'WARNING'}, 0, "failed to insert entry into computerloadlog table");
-		return 0;
+		notify($ERRORS{'WARNING'}, 0, "failed to insert '$loadstatename' computerloadlog entry");
+		return;
 	}
-
-	return 1;
 } ## end sub insertloadlog
 
 #/////////////////////////////////////////////////////////////////////////////
@@ -8345,6 +8299,136 @@ sub switch_vmhost_id {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 get_reservation_computerloadlog_entries
+
+ Parameters  : $reservation_id
+ Returns     : array
+ Description : Retrieves computerloadlog info for a single reservation. An array
+               of hashes is returned. The array is ordered from oldest entry to
+               newest.
+               [
+                  {
+                     "additionalinfo" => "beginning to process, state is test",
+                     "computerid" => 3582,
+                     "computerloadstate" => {
+                     "loadstatename" => "begin"
+                     },
+                        "id" => 3494,
+                        "loadstateid" => 54,
+                        "reservationid" => 3115,
+                        "timestamp" => "2014-12-17 16:09:11"
+                  },
+                  {
+                     "additionalinfo" => "begin initial connection timeout (xxx seconds)",
+                     "computerid" => 3582,
+                     "computerloadstate" => {
+                     "loadstatename" => "initialconnecttimeout"
+                     },
+                        "id" => 3495,
+                        "loadstateid" => 56,
+                        "reservationid" => 3115,
+                        "timestamp" => "2014-12-17 16:09:14"
+                  }
+               ]
+
+=cut
+
+sub get_reservation_computerloadlog_entries {
+	my ($reservation_id) = @_;
+	if (!$reservation_id) {
+		notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not passed");
+		return;
+	}
+
+	my $select_statement = <<EOF;
+SELECT
+computerloadlog.*,
+computerloadstate.loadstatename AS computerloadstate_loadstatename
+
+FROM
+computerloadlog,
+computerloadstate
+
+WHERE
+computerloadlog.reservationid = $reservation_id
+AND computerloadlog.loadstateid = computerloadstate.id
+
+ORDER BY computerloadlog.timestamp ASC
+EOF
+
+	my @rows = database_select($select_statement);
+	
+	my @computerloadlog_info;
+	for my $row (@rows) {
+		for my $column (keys %$row) {
+			my $value = $row->{$column};
+			if ($column =~ /^([^_]+)_([^_]+)$/) {
+				$row->{$1}{$2} = $value;
+				delete $row->{$column};
+			}
+		}
+		
+		push @computerloadlog_info, $row;
+	}
+	
+	#notify($ERRORS{'DEBUG'}, 0, "retrieved computerloadlog info for reservation $reservation_id:\n" . format_data(@computerloadlog_info));
+	return @computerloadlog_info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_reservation_computerloadlog_time
+
+ Parameters  : $reservation_id, $loadstatename, $newest (optional)
+ Returns     : string (datetime)
+ Description : Retrieves the timestamp of a computerloadlog entry matching the
+               $loadstatename argument for a reservation and returns the time in
+               epoch seconds. By default, the timestamp of the oldest matching
+               entry is returned. The newest may be returned by providing the
+               $newest argument.
+
+=cut
+
+sub get_reservation_computerloadlog_time {
+	my ($reservation_id, $loadstatename, $newest) = @_;
+	if (!defined($reservation_id)) {
+		notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not supplied");
+		return;
+	}
+	if (!defined($loadstatename)) {
+		notify($ERRORS{'WARNING'}, 0, "computerloadstate name argument was not supplied");
+		return;
+	}
+	
+	# Get all computerloadlog entries for the reservation
+	my @computerloadlog_entries = get_reservation_computerloadlog_entries($reservation_id);
+	if (!@computerloadlog_entries) {
+		notify($ERRORS{'WARNING'}, 0, "failed to retrieve timestamp of computerloadlog '$loadstatename' entry for reservation $reservation_id, computerloadlog entries could not be retrieved");
+		return;
+	}
+	
+	my $timestamp;
+	for my $computerloadlog_entry (@computerloadlog_entries) {
+		if ($computerloadlog_entry->{computerloadstate}{loadstatename} eq $loadstatename) {
+			$timestamp = $computerloadlog_entry->{timestamp};
+			last unless $newest;
+		}
+	}
+	
+	my $type = ($newest ? 'newest' : 'oldest');
+	if ($timestamp) {
+		my $timestamp_epoch = convert_to_epoch_seconds($timestamp);
+		notify($ERRORS{'DEBUG'}, 0, "retrieved $type timestamp of first '$loadstatename' computerloadlog entry for reservation $reservation_id: '$timestamp', returning $timestamp_epoch");
+		return $timestamp_epoch;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to retrieve $type timestamp of first '$loadstatename' computerloadlog entry for reservation $reservation_id");
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 get_request_loadstate_names
 
  Parameters  : $request_id
@@ -8474,7 +8558,7 @@ sub reservation_being_processed {
 		notify($ERRORS{'DEBUG'}, 0, "reservation $reservation_id is currently being processed, computerloadlog 'begin' entry exists and running process was found: @processes_running");
 	}
 	elsif (!$computerloadlog_exists && @processes_running) {
-		notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry does NOT exist but running process was found: @processes_running, assuming reservation $reservation_id is currently being processed");
+		notify($ERRORS{'DEBUG'}, 0, "computerloadlog 'begin' entry does NOT exist but running process was found: @processes_running, assuming reservation $reservation_id is currently being processed");
 	}
 	elsif ($computerloadlog_exists && !@processes_running) {
 		notify($ERRORS{'WARNING'}, 0, "computerloadlog 'begin' entry exists but running process was NOT found, assuming reservation $reservation_id is NOT currently being processed");