in managementnode/lib/VCL/inuse.pm [102:340]
sub process {
my $self = shift;
my $request_id = $self->data->get_request_id();
my $request_state_name = $self->data->get_request_state_name();
my $request_start = $self->data->get_request_start_time();
my $request_end = $self->data->get_request_end_time();
my $request_forimaging = $self->data->get_request_forimaging();
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 $server_request_id = $self->data->get_server_request_id();
my $imagemeta_checkuser = $self->data->get_imagemeta_checkuser();
my $is_parent_reservation = $self->data->is_parent_reservation();
my $computer_id = $self->data->get_computer_id();
my $computer_short_name = $self->data->get_computer_short_name();
my $connect_timeout_seconds = $self->os->get_timings('reconnecttimeout');
# Check if reboot operation was requested
if ($request_state_name =~ /reboot/) {
if ($self->os->can('reboot')) {
if (!$self->os->reboot()) {
notify($ERRORS{'CRITICAL'}, 0, "user requested reboot of $computer_short_name failed");
}
}
else {
notify($ERRORS{'CRITICAL'}, 0, "'$request_state_name' operation requested, " . ref($self->os) . " does not implement a 'reboot' subroutine");
}
$self->state_exit('inuse', 'inuse');
}
# Check if server reservation has been modified
if ($request_state_name =~ /servermodified/) {
if (!$self->os->add_user_accounts()) {
notify($ERRORS{'CRITICAL'}, 0, "failed to update server access");
}
$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);
my $request_end_epoch_seconds = convert_to_epoch_seconds($request_end);
my $request_remaining_seconds = ($request_end_epoch_seconds - $now_epoch_seconds);
my $request_remaining_minutes = floor($request_remaining_seconds / 60);
my $request_duration_seconds = ($request_end_epoch_seconds - $request_start_epoch_seconds);
my $request_duration_hours = floor($request_duration_seconds / 60 / 60);
my $end_time_notify_seconds = $self->os->get_timings('general_end_notice_first');
my $end_time_notify_minutes = floor($end_time_notify_seconds / 60);
my $second_end_time_notify_seconds = $self->os->get_timings('general_end_notice_second');
my $second_end_time_notify_minutes = floor($second_end_time_notify_seconds / 60);
my $now_string = strftime('%H:%M:%S', localtime($now_epoch_seconds));
my $request_end_string = strftime('%H:%M:%S', localtime($request_end_epoch_seconds));
my $request_remaining_string = strftime('%H:%M:%S', gmtime($request_remaining_seconds));
my $end_time_notify_string = strftime('%H:%M:%S', gmtime($end_time_notify_seconds));
my $connect_timeout_string = strftime('%H:%M:%S', gmtime($connect_timeout_seconds));
# Check if near the end time
# Compare remaining minutes to connect timeout minutes in case this is > 15 minutes
if ($request_remaining_minutes <= ($end_time_notify_minutes + 6)) {
# Only 1 reservation needs to handle the end time countdown
if (!$is_parent_reservation) {
notify($ERRORS{'OK'}, 0, "request end time countdown handled by parent reservation, exiting");
$self->state_exit();
}
my $sleep_seconds = ($request_remaining_seconds - $end_time_notify_seconds);
if ($sleep_seconds > 0) {
my $sleep_string = strftime('%H:%M:%S', gmtime($sleep_seconds));
notify($ERRORS{'OK'}, 0, "request end time is near, sleeping for $sleep_seconds seconds:\n" .
"current time : $now_string\n" .
"request end time : $request_end_string\n" .
"remaining time : $request_remaining_string\n" .
"notify time : $end_time_notify_string\n" .
"sleep time : $sleep_string"
);
sleep $sleep_seconds;
}
else {
notify($ERRORS{'WARNING'}, 0, "request notify end time has passed:\n" .
"current time : $now_string\n" .
"request end time : $request_end_string\n" .
"remaining time : $request_remaining_string\n" .
"notify time : $end_time_notify_string"
);
}
# Loop for $end_time_notify_minutes regardless of how much time is actually left
# The time until request.end may be short if vcld wasn't running
# This gives the user notice that the request is ending
for (my $iteration = 0; $iteration <= $end_time_notify_minutes; ++$iteration) {
$request_remaining_minutes = ($end_time_notify_minutes - $iteration);
notify($ERRORS{'OK'}, 0, "minutes until end of end of request: $request_remaining_minutes");
# Check if the request state changed for any reason
# This will occur if the user deletes the request, makeproduction is initiated, reboot is initiated, image capture is started
if ($self->request_state_changed()) {
$self->state_exit();
}
# Get the current request end time from the database
my $current_request_end = get_request_end($request_id);
my $current_request_end_epoch_seconds = convert_to_epoch_seconds($current_request_end);
# Check if the user extended the request
if ($current_request_end_epoch_seconds > $request_end_epoch_seconds) {
notify($ERRORS{'OK'}, 0, "user extended request, end time: $request_end --> $current_request_end, returning request to inuse state");
$self->state_exit('inuse', 'inuse');
}
# Notify user when 5 or 10 minutes remain
if ($request_remaining_minutes == $second_end_time_notify_minutes || $request_remaining_minutes == $end_time_notify_minutes) {
$self->notify_user_endtime_imminent("$request_remaining_minutes minutes");
}
if ($iteration < $end_time_notify_minutes) {
notify($ERRORS{'OK'}, 0, "sleeping for 60 seconds");
sleep 60;
}
}
# Notify user - endtime and image capture has started
$self->notify_user_endtime_reached();
# Initiate auto-capture process if this is an imaging request and not a cluster reservation
if ($request_forimaging && $reservation_count == 1) {
notify($ERRORS{'OK'}, 0, "initiating image auto-capture process");
if (!$self->start_imaging_request()) {
notify($ERRORS{'CRITICAL'}, 0, "failed to initiate image auto-capture process, changing request and computer state to maintenance");
$self->state_exit('maintenance', 'maintenance');
}
#Successful, cleanly exit with no state change
$self->state_exit()
}
$self->state_exit('timeout', 'timeout', 'EOR');
}
# If duration is greater than 24 hours perform end time notice checks
if ($is_parent_reservation && $request_duration_hours >= 24) {
notify($ERRORS{'DEBUG'}, 0, "checking end time notice interval, request duration: $request_duration_hours hours, parent reservation: $is_parent_reservation");
# Check end time for a notice interval - returns 0 if no notice is to be given
my $notice_interval = check_endtimenotice_interval($request_end);
if ($notice_interval) {
$self->notify_user_future_endtime($notice_interval);
}
}
else {
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
if ($request_remaining_minutes < ($connect_timeout_minutes + $end_time_notify_minutes)) {
notify($ERRORS{'DEBUG'}, 0, "skipping user connection check, connect timeout would run into the end time notice stage:\n" .
"current time : $now_string\n" .
"request end time : $request_end_string\n" .
"remaining time : $request_remaining_string\n" .
"notify time : $end_time_notify_string\n" .
"connect timeout : $connect_timeout_string"
);
$self->state_exit('inuse', 'inuse');
}
# TODO: fix user connection checking for cluster requests
if ($reservation_count > 1) {
notify($ERRORS{'OK'}, 0, "skipping user connection check for cluster request");
$self->state_exit('inuse', 'inuse');
}
# 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
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);
# 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 ($request_forimaging) {
notify($ERRORS{'OK'}, 0, "never detected user connection, skipping timeout, imaging reservation");
}
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->request_state_changed()) {
$self->state_exit();
}
else {
# Update reservation lastcheck, otherwise request will be processed immediately again
update_reservation_lastcheck($reservation_id);
$self->notify_user_timeout_inactivity();
$self->state_exit('timeout', 'inuse', 'timeout');
}
}
$self->state_exit('inuse', 'inuse');
}