blob: 8a053e6fcc3ce306eb4a3f0cd30673ba50067483 [file] [log] [blame]
#!/usr/bin/perl -w
###############################################################################
# $Id$
###############################################################################
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
###############################################################################
=head1 NAME
VCL::reclaim - Perl module for the VCL reclaim state
=head1 SYNOPSIS
use VCL::reclaim;
use VCL::utils;
# Set variables containing the IDs of the request and reservation
my $request_id = 5;
my $reservation_id = 6;
# Call the VCL::utils::get_request_info subroutine to populate a hash
my $request_info = get_request_info($request_id);
# Set the reservation ID in the hash
$request_info->{RESERVATIONID} = $reservation_id;
# Create a new VCL::reclaim object based on the request information
my $reclaim = VCL::reclaim->new($request_info);
=head1 DESCRIPTION
This module supports the VCL "reclaim" state.
=cut
##############################################################################
package VCL::reclaim;
# Specify the lib path using FindBin
use FindBin;
use lib "$FindBin::Bin/..";
# Configure inheritance
use base qw(VCL::Module::State);
# Specify the version of this module
our $VERSION = '2.4.1';
# Specify the version of Perl to use
use 5.008000;
use strict;
use warnings;
use diagnostics;
use VCL::utils;
##############################################################################
=head1 OBJECT METHODS
=cut
#/////////////////////////////////////////////////////////////////////////////
=head2 process
Parameters : Reference to state object
Returns : Nothing, process always exits
Description : Processes a reservation in the timeout and deleted states.
=cut
sub process {
my $self = shift;
# Get required data
my $request_data = $self->data->get_request_data();
my $reservation_id = $self->data->get_reservation_id();
my $request_state_name = $self->data->get_request_state_name();
my $request_laststate_name = $self->data->get_request_laststate_name();
my $computer_id = $self->data->get_computer_id();
my $computer_type = $self->data->get_computer_type();
my $computer_shortname = $self->data->get_computer_short_name();
my $computer_state_name = $self->data->get_computer_state_name();
my $computer_currentimage_name = $self->data->get_computer_currentimage_name(0);
my $server_request_id = $self->data->get_server_request_id();
my $public_ip_configuration = $self->data->get_management_node_public_ip_configuration() || return;
my @reservation_ids = $self->data->get_reservation_ids();
# Remove related fixedIPsr variable, if it exists
if ($server_request_id) {
my $variable_name = "fixedIPsr" . $server_request_id;
if (is_variable_set($variable_name)) {
#Delete from variable table.
my $delete_sql_statement = "DELETE variable FROM variable WHERE name = '$variable_name' ";
if (database_execute($delete_sql_statement)) {
notify($ERRORS{'DEBUG'}, 0, "Deleted server reservation entry for $variable_name from variable table");
}
}
if ($public_ip_configuration =~ /static/i) {
my $original_IPvalue = "originalIPaddr_" . $server_request_id;
if (is_variable_set($original_IPvalue)) {
my $original_Public_IP = get_variable($original_IPvalue);
if (update_computer_public_ip_address($computer_id, $original_Public_IP)) {
notify($ERRORS{'DEBUG'}, 0, "restored original IP address: $original_Public_IP for $computer_state_name ");
}
my $delete_sql_statement = "DELETE variable FROM variable WHERE name = '$original_IPvalue' ";
if (database_execute($delete_sql_statement)) {
notify($ERRORS{'DEBUG'}, 0, "Deleted server reservation entry for $original_IPvalue from variable table");
}
}
}
}
# Clean up rules on the NAT host if NAT is used
if ($self->nathost_os(0)) {
my $nathost_hostname = $self->data->get_nathost_hostname();
if ($self->nathost_os->firewall()) {
if ($self->nathost_os->firewall->can('sanitize_reservation')) {
if (!$self->nathost_os->firewall->sanitize_reservation()) {
notify($ERRORS{'CRITICAL'}, 0, "failed to sanitize firewall for reservation on NAT host $nathost_hostname");
}
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to sanitize firewall for reservation on NAT host $nathost_hostname, " . ref($self->nathost_os->firewall) . " does not implement a 'sanitize_reservation' subroutine");
}
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to sanitize firewall for reservation on NAT host $nathost_hostname, NAT host OS firewall object is not available");
}
}
# Insert into computerloadlog if request state = timeout
if ($request_state_name =~ /timeout|deleted/) {
insertloadlog($reservation_id, $computer_id, $request_state_name, "reclaim: starting $request_state_name process");
}
notify($ERRORS{'DEBUG'}, 0, "beginning to reclaim $computer_shortname:\nrequest state: $request_state_name\nrequest laststate: $request_laststate_name\ncomputer state: $computer_state_name\ncomputer type: $computer_type");
# Don't attempt to do anything to machines that are currently reloading
if ($computer_state_name =~ /maintenance|reloading/) {
notify($ERRORS{'OK'}, 0, "computer in $computer_state_name state, nothing needs to be done to the computer");
}
# If request laststate = new, nothing needs to be done
elsif ($request_laststate_name =~ /new/) {
notify($ERRORS{'OK'}, 0, "request laststate is $request_laststate_name, nothing needs to be done to the computer");
}
# Lab computers only need to be sanitized (have sshd disabled)
elsif ($computer_type =~ /lab/) {
notify($ERRORS{'OK'}, 0, "computer type is $computer_type, computer will be sanitized");
$self->call_os_sanitize();
}
# If request laststate = reserved, user did not log in
# Make sure image loaded on computer (currentimage.txt) matches what's set in computer.currentimageid
elsif ($request_laststate_name =~ /reserved/) {
notify($ERRORS{'DEBUG'}, 0, "request laststate is $request_laststate_name, checking if computer table current image matches image currently loaded on $computer_shortname");
## If server reservations and in reserved - reload
#if ($server_request_id) {
# notify($ERRORS{'DEBUG'}, 0, "Detected server reservations, computer will be reloaded");
# $self->insert_reload_and_exit();
#}
# Make sure computer current image name was retrieved from the database
if (!$computer_currentimage_name) {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve computer current image name from the database, computer will be reloaded");
$self->insert_reload_and_exit();
}
# Reload the computer if unable to retrieve the current image name
my $os_current_image_name = $self->os->get_current_image_info("current_image_name");
if (!$os_current_image_name) {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve name of image currently loaded on $computer_shortname, computer will be reloaded");
$self->insert_reload_and_exit();
}
# Compare the database current image value with what's on the computer
if ($computer_currentimage_name eq $os_current_image_name) {
notify($ERRORS{'DEBUG'}, 0, "computer table current image name ($computer_currentimage_name) matches image name on computer ($os_current_image_name), computer will be sanitized");
$self->call_os_sanitize();
}
else {
notify($ERRORS{'DEBUG'}, 0, "computer table current image name ($computer_currentimage_name) does NOT match image name on computer ($os_current_image_name), computer will be reloaded");
$self->insert_reload_and_exit();
}
}
# Request laststate is not reserved, user logged in
else {
notify($ERRORS{'OK'}, 0, "request laststate is $request_laststate_name, computer will be reloaded");
$self->insert_reload_and_exit();
}
# Update the request state to complete and exit
# Set the computer state to available if it isn't in the maintenance or reloading state
if ($computer_state_name =~ /maintenance|reloading/) {
notify($ERRORS{'OK'}, 0, "$computer_shortname in $computer_state_name state, skipping state update to available");
switch_state($request_data, 'complete', '', '', '1');
}
else {
switch_state($request_data, 'complete', 'available', '', '1');
}
notify($ERRORS{'DEBUG'}, 0, "exiting");
exit;
} ## end sub process
#/////////////////////////////////////////////////////////////////////////////
=head2 insert_reload_and_exit
Parameters : Reference to state object
Returns : Nothing, process always exits
Description : -Retrieves the next image to be loaded on the computer based on
a predictive loading algorithm
-Inserts a new reload request
-Sets the state of the request being processed to complete
-Sets the state of the computer to reload
=cut
sub insert_reload_and_exit {
my $self = shift;
my $request_data = $self->data->get_request_data;
my $computer_id = $self->data->get_computer_id();
my $computer_shortname = $self->data->get_computer_short_name();
# Run any vcl_post_reservation scripts (if exists)
if ($self->os->can("post_reservation")) {
if ($self->os->post_reservation()) {
notify($ERRORS{'OK'}, 0, "post_reservation script has been executed on $computer_shortname prior to reloading");
}
}
# Retrieve next image
my ($action, $next_image_name, $next_image_id, $next_imagerevision_id) = $self->data->get_next_image_data_structure();
if ($action =~ /unload/i) {
if ($self->provisioner->can("unload")) {
if ($self->provisioner->unload()) {
if (update_computer_imagename($computer_id, 'noimage')) {
notify($ERRORS{'DEBUG'}, 0, "set computer $computer_shortname current image to 'noimage'");
}
switch_state($request_data, 'complete', 'available', '', '1');
}
}
}
else {
#elsif ( $action =~ /reload/i ) {
if (!$next_image_name || !$next_image_id || !$next_imagerevision_id) {
notify($ERRORS{'WARNING'}, 0, "predictor module did not return required information, calling get_next_image_default from utils");
($next_image_name, $next_image_id, $next_imagerevision_id) = get_next_image_default($computer_id);
}
# Update the DataStructure object with the next image values
# These will be used by insert_reload_request()
$self->data->set_image_name($next_image_name);
$self->data->set_image_id($next_image_id);
$self->data->set_imagerevision_id($next_imagerevision_id);
notify($ERRORS{'OK'}, 0, "next image: $next_image_name, image id=$next_image_id, imagerevision id=$next_imagerevision_id");
# Insert reload request data into the database
if (insert_reload_request($request_data)) {
notify($ERRORS{'OK'}, 0, "inserted reload request into database for computer id=$computer_id, image=$next_image_name");
# Switch the request state to complete, the computer state to reload
switch_state($request_data, 'complete', 'reload', '', '1');
}
else {
notify($ERRORS{'CRITICAL'}, 0, "failed to insert reload request into database for computer id=$computer_id image=$next_image_name");
# Switch the request and computer states to failed
switch_state($request_data, 'failed', 'failed', '', '1');
}
}
notify($ERRORS{'DEBUG'}, 0, "exiting");
exit;
}
#/////////////////////////////////////////////////////////////////////////////
=head2 call_os_sanitize
Parameters : Reference to state object
Returns : If successful: true
If failed: exits
Description : Calls the OS module's sanitize subroutine. If sanitize() fails,
a reload request will be inserted into the database and this
process will exit.
=cut
sub call_os_sanitize {
my $self = shift;
# Make sure sanitize() has been implemented by the OS module
if (!$self->os->can("sanitize")) {
notify($ERRORS{'WARNING'}, 0, "sanitize subroutine has not been implemented by the " . ref($self->os) . " OS module, computer will be reloaded");
$self->insert_reload_and_exit();
}
my $computer_shortname = $self->data->get_computer_short_name();
# Attempt to call OS module's sanitize() subroutine
# This subroutine should perform all the tasks necessary to sanitize the OS if it was reserved and not logged in to
notify($ERRORS{'DEBUG'}, 0, "calling " . ref($self->os) . "::sanitize() subroutine");
if ($self->os->sanitize()) {
notify($ERRORS{'OK'}, 0, "$computer_shortname has been sanitized");
}
else {
# OS module's sanitize() subroutine returned false, meaning reload is necessary
notify($ERRORS{'WARNING'}, 0, "failed to sanitize $computer_shortname, computer will be reloaded");
$self->insert_reload_and_exit();
}
return 1;
}
#/////////////////////////////////////////////////////////////////////////////
1;
__END__
=head1 SEE ALSO
L<http://cwiki.apache.org/VCL/>
=cut