You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by jf...@apache.org on 2008/12/12 19:20:18 UTC

svn commit: r726079 [10/32] - in /incubator/vcl/tags/import: ./ managementnode/ managementnode/bin/ managementnode/etc/ managementnode/etc/vcl/ managementnode/legacy_vcl_vbs_scripts/ managementnode/lib/ managementnode/lib/VCL/ managementnode/lib/VCL/Mo...

Added: incubator/vcl/tags/import/managementnode/lib/VCL/healthcheck.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/healthcheck.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/healthcheck.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/healthcheck.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,805 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+##############################################################################
+# $Id: healthcheck.pm 1945 2008-12-11 20:58:08Z fapeeler $
+##############################################################################
+
+=head1 NAME
+
+VCL::healthcheck
+
+=head1 SYNOPSIS
+
+ use base qw(VCL::healthcheck);
+
+=head1 DESCRIPTION
+
+ Needs to be written.
+
+=cut
+
+##############################################################################
+package VCL::healthcheck;
+
+# Specify the lib path using FindBin
+use FindBin;
+use lib "$FindBin::Bin/..";
+
+# Configure inheritance
+use base qw();
+
+# Specify the version of this module
+our $VERSION = '2.00';
+
+# Specify the version of Perl to use
+use 5.008000;
+
+use strict;
+use warnings;
+use diagnostics;
+
+use VCL::utils;
+use DBI;
+use Net::DNS;
+use VCL::Module::Provisioning::xCAT;
+use VCL::Module::Provisioning::Lab;
+
+##############################################################################
+
+=head1 OBJECT METHODS
+
+=cut
+
+#/////////////////////////////////////////////////////////////////////////////
+
+#----------GLOBALS--------------
+our $LOG = "/var/log/healthcheckvcl.log";
+our $MYDBH;
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function
+///
+/// \param
+///
+/// \return
+///
+/// \brief
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub new {
+	my ($class, %input) = @_;
+	my $obj_ref = {%input,};
+	bless $obj_ref, $class;    # bless ref to said class
+	$obj_ref->_initialize();   # more work to do
+	return $obj_ref;
+
+}
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function
+///
+/// \param
+///
+/// \return
+///
+/// \brief
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub _initialize {
+	my ($hck) = @_;
+	my ($mnid, $managementnodeid, $selh, @row, $rows, $mnresourceid, $resourceid);
+	my @hostinfo = hostname;
+	$hck->{MN}   = $hostinfo[0];
+	$hck->{MNos} = $hostinfo[1];
+	$hck->{dbh}  = getnewdbh;
+
+	#set global dbh for imagerevision check
+	$MYDBH = $hck->{dbh};
+
+	#= DBI->connect(qq{dbi:mysql:$DATABASE:$SERVER}, $WRTUSER,$WRTPASS, {PrintError => 0});
+	unless (defined $hck->{dbh}) {    # dbh is an undef on failure
+		my $outstring = DBI::errstr();
+		notify($ERRORS{'WARNING'}, $LOG, $outstring);
+		#goto SLEEP;
+		return 0;
+	}
+	$hck->{"globalmsg"}->{"header"} = "STATUS SUMMARY of VCL nodes:\n\n";
+
+	#1 get management node id and management node's resource id
+	$selh = $hck->{dbh}->prepare(
+		"SELECT m.id,r.id
+                            FROM resource r, resourcetype rt, managementnode m
+                            WHERE r.resourcetypeid = rt.id AND r.subid = m.id AND rt.name = ? AND m.hostname = ?") or notify($ERRORS{'WARNING'}, $hck->{LOG}, "Could not prepare select for management node id" . $hck->{dbh}->errstr());
+
+	$selh->execute("managementnode", $hck->{MN}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute management node id" . $hck->{dbh}->errstr());
+
+	my $dbretval = $selh->bind_columns(\($managementnodeid, $resourceid));
+	$rows = $selh->rows;
+	if ($rows != 0) {
+		while ($selh->fetch) {
+			$mnid                  = $managementnodeid;
+			$mnresourceid          = $resourceid;
+			$hck->{"mnid"}         = $managementnodeid;
+			$hck->{"mnresourceid"} = $resourceid;
+			notify($ERRORS{'OK'}, $LOG, "$hck->{MN} mnid $mnid  resourceid $resourceid");
+		}
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, $LOG, "No management id for $hck->{MN}.");
+		exit;
+	}
+
+	#2 select management node groups I belong to
+
+	$selh = $hck->{dbh}->prepare("SELECT resourcegroupid FROM resourcegroupmembers WHERE resourceid= ?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare select for management node group membership" . $hck->{dbh}->errstr());
+	$selh->execute($hck->{mnresourceid}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute statement for collecting my group membership" . $hck->{dbh}->errstr());
+	$rows = $selh->rows;
+	if ($rows != 0) {
+		while (@row = $selh->fetchrow_array) {
+			$hck->{"groupmembership"}->{$row[0]} = $row[0];
+			notify($ERRORS{'OK'}, $LOG, "$hck->{MN} resourceid $hck->{mnresourceid} is in group $row[0]");
+		}
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, $LOG, "Not a member of any groups $hck->{MN} resourceid $hck->{mnresourceid}");
+		exit;
+	}
+
+	#3 get list of computer groups I have access to control
+	$selh = $hck->{dbh}->prepare("SELECT r.resourcegroupid2 FROM resourcemap r, resourcetype rt WHERE r.resourcetypeid2=rt.id AND r.resourcegroupid1=? AND rt.name=?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare computer groups statement:" . $hck->{dbh}->errstr());
+	foreach my $grpid (sort keys(%{$hck->{groupmembership}})) {
+		$selh->execute($hck->{groupmembership}->{$grpid}, "computer") or notify($ERRORS{'WARNING'}, $LOG, "Could not execute computer goups statement:" . $hck->{dbh}->errstr());
+		$rows = $selh->rows;
+		if ($rows != 0) {
+			while (@row = $selh->fetchrow_array) {
+				$hck->{"groupscancrontrol"}->{$row[0]} = $row[0];
+				notify($ERRORS{'OK'}, $LOG, "$hck->{MN} resourceid $hck->{mnresourceid} cg= $grpid manages group $row[0]");
+			}
+		}
+		else {
+			notify($ERRORS{'WARNING'}, $LOG, "no group to control $hck->{MN} resourceid $hck->{mnresourceid} groupid $grpid ");
+		}
+	} ## end foreach my $grpid (sort keys(%{$hck->{groupmembership...
+
+	#4 foreach of the groups i can manage get the computer members
+	$selh = $hck->{dbh}->prepare(
+		"SELECT r.subid,r.id
+                                    FROM resourcegroupmembers rm,resourcetype rt,resource r
+                                    WHERE rm.resourceid=r.id AND rt.id=r.resourcetypeid AND rt.name=? AND rm.resourcegroupid =?
+                                    ") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare computer groups statement:" . $hck->{dbh}->errstr());
+	foreach my $rgroupid (sort keys(%{$hck->{groupscancrontrol}})) {
+		$selh->execute("computer", $hck->{groupscancrontrol}->{$rgroupid}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute computer goups statement:" . $hck->{dbh}->errstr());
+		$rows = $selh->rows;
+		#notify($ERRORS{'OK'},$LOG,"rows = $rows for group$hck->{groupscancrontrol}->{$rgroupid}");
+		if ($rows != 0) {
+			while (@row = $selh->fetchrow_array) {
+				$hck->{"computers"}->{$row[0]}->{"id"} = $row[0];
+				#  notify($ERRORS{'OK'},$LOG,"$hck->{MN} resourceid $row[1] computerid $row[0] in group $hck->{groupscancrontrol}->{$rgroupid}");
+			}
+		}
+		else {
+			notify($ERRORS{'WARNING'}, $LOG, "no group to control $hck->{MN} resourceid $hck->{mnresourceid} groupid $rgroupid ");
+		}
+	} ## end foreach my $rgroupid (sort keys(%{$hck->{groupscancrontrol...
+
+	#5 based from our hash table of computer ids collect individual computer information
+	$selh = $hck->{dbh}->prepare(
+		"SELECT c.hostname,c.IPaddress,c.lastcheck,s.name,c.currentimageid,c.preferredimageid,c.imagerevisionid,c.type,c.ownerid,i.name,o.name,c.deleted
+                                    FROM computer c,state s, image i, OS o
+                                    WHERE s.id=c.stateid AND i.id=c.currentimageid AND o.id=i.OSid AND c.id =?
+                                    ") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare computer info statement:" . $hck->{dbh}->errstr());
+	foreach my $cid (sort keys(%{$hck->{computers}})) {
+		$selh->execute($hck->{computers}->{$cid}->{id}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute computer info statement:" . $hck->{dbh}->errstr());
+		$rows = $selh->rows;
+		my @crow;
+		if ($rows != 0) {
+			while (@crow = $selh->fetchrow_array) {
+				$hck->{computers}->{$cid}->{"hostname"}         = $crow[0];
+				$hck->{computers}->{$cid}->{"IPaddress"}        = $crow[1];
+				$hck->{computers}->{$cid}->{"lastcheck"}        = $crow[2] if (defined($crow[2]));
+				$hck->{computers}->{$cid}->{"state"}            = $crow[3];
+				$hck->{computers}->{$cid}->{"currentimageid"}   = $crow[4];
+				$hck->{computers}->{$cid}->{"preferredimageid"} = $crow[5];
+				$hck->{computers}->{$cid}->{"imagerevisionid"}  = $crow[6];
+				$hck->{computers}->{$cid}->{"type"}             = $crow[7];
+				$hck->{computers}->{$cid}->{"ownerid"}          = $crow[8];
+				$hck->{computers}->{$cid}->{"dbimagename"}      = $crow[9];
+				$hck->{computers}->{$cid}->{"OSname"}           = $crow[10];
+				$hck->{computers}->{$cid}->{"shortname"}        = $1 if ($crow[0] =~ /([-_a-zA-Z0-9]*)\./);    #should cover all host
+				$hck->{computers}->{$cid}->{"MNos"}             = $hck->{MNos};
+				$hck->{computers}->{$cid}->{"deleted"}          = $crow[11];
+				$hck->{computers}->{$cid}->{"id"}               = $cid;
+			} ## end while (@crow = $selh->fetchrow_array)
+		} ## end if ($rows != 0)
+		else {
+			notify($ERRORS{'WARNING'}, $LOG, "no rows related to computer id $hck->{computers}->{$cid}->{id} reporting no data to pull for computer info statement ");
+		}
+	} ## end foreach my $cid (sort keys(%{$hck->{computers}}...
+} ## end sub _initialize
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function process
+///
+/// \param
+///
+/// \return
+///
+/// \brief check each computer, sort checks by type
+///   lab: ssh check,vclclientd running, adduser,deluser
+///   blade: ssh check, correct image, adduser,deluser
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub process {
+	my ($hck) = @_;
+	notify($ERRORS{'OK'}, $LOG, "in processing routine");
+	$hck->{"globalmsg"}->{"body"} = "Summary of VCL node monitoring system:\n\n";
+
+	if (!($hck->{dbh}->ping)) {
+		$hck->{dbh} = getnewdbh();
+	}
+
+	my $checkstate = $hck->{dbh}->prepare(
+		"SELECT s.name,c.lastcheck FROM computer c,state s
+                                    WHERE s.id=c.stateid AND c.id =?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare state check statement on computer:" . $hck->{dbh}->errstr());
+
+	$hck->{"computercount"}    = 0;
+	$hck->{"computerschecked"} = 0;
+
+	foreach my $cid (sort keys(%{$hck->{computers}})) {
+		#skipping virtual machines for now
+		next if ($hck->{computers}->{$cid}->{type} eq "virtualmachine");
+
+		# check ssh
+		# check uptime
+		# check vclclientd working
+		# reboot if needed
+		# update lastcheck timestamp
+		# update state if needed
+		# add to failed notification summary if needed
+		# $hostname,$os,$mnOS,$ipaddress,$log
+		# check the current image revision
+
+		#count the node
+		$hck->{"computercount"} += 1;
+		#recheck state and lastcheck time -- this is important as more machines are checked
+		if (!($hck->{dbh}->ping)) {
+			#just incase handle and statement are lost
+			$hck->{dbh} = getnewdbh();
+			$checkstate = $hck->{dbh}->prepare(
+				"SELECT s.name FROM computer c,state s
+                                   WHERE s.id=c.stateid AND c.id =?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare state check statement on computer:" . $hck->{dbh}->errstr());
+
+		}
+
+		$checkstate->execute($hck->{computers}->{$cid}->{id}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute computer check state for $hck->{computers}->{$cid}->{id}:" . $hck->{dbh}->errstr());
+		my $rows = $checkstate->rows;
+		if ($rows != 0) {
+			my @crow = $checkstate->fetchrow_array;
+			$hck->{computers}->{$cid}->{"state"} = $crow[0];
+		}
+		else {
+			notify($ERRORS{'WARNING'}, $LOG, "no rows related to computer id $hck->{computers}->{$cid}->{id} reporting no data to pull for computer info statement ");
+			$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname} : UNABLE to pull current state, skipping";
+			next;
+		}
+		if ($hck->{computers}->{$cid}->{state} =~ /inuse|reloading/) {
+			next;
+			notify($ERRORS{'OK'}, $LOG, "NODE $hck->{computers}->{$cid}->{hostname} inuse skipping");
+
+		}
+		if ($hck->{computers}->{$cid}->{state} =~ /^(maintenance|hpc|vmhostinue)/) {
+			$hck->{computers}->{$cid}->{"skip"} = 1;
+			$hck->{"computersskipped"} += 1;
+			next;
+		}
+
+		if ($hck->{computers}->{$cid}->{deleted}) {
+			#machine deleted but set on a state we monitor
+			$hck->{computers}->{$cid}->{"confirmedstate"} = "maintenance";
+			goto UPDATESTATE;
+		}
+
+		#check lastcheck
+		if (defined($hck->{computers}->{$cid}->{"lastcheck"})) {
+			my $lastcheckepoch  = convert_to_epoch_seconds($hck->{computers}->{$cid}->{lastcheck});
+			my $currentimeepoch = convert_to_epoch_seconds();
+			my $delta           = ($currentimeepoch - $lastcheckepoch);
+			#if( $delta <= (5*60) ){
+			if ($delta <= (1 * 60 * 60 * 24 + 60 * 60)) {
+				#if( $delta <= (90*60) ){
+				notify($ERRORS{'OK'}, $LOG, "NODE $hck->{computers}->{$cid}->{hostname} recently checked skipping");
+				#this node was recently checked
+				$hck->{computers}->{$cid}->{"skip"} = 1;
+				$hck->{"computersskipped"} += 1;
+				next;
+			}
+			$hck->{"computerschecked"} += 1;
+		} ## end if (defined($hck->{computers}->{$cid}->{"lastcheck"...
+
+		#handle the failed machines first
+		if ($hck->{computers}->{$cid}->{state} =~ /failed|available/) {
+
+			if (_valid_host($hck->{computers}->{$cid}->{hostname})) {
+				$hck->{computers}->{$cid}->{"valid_host"}   = 1;
+				$hck->{computers}->{$cid}->{"basechecksok"} = 0;
+				notify($ERRORS{'OK'}, $LOG, "process: reports valid host for $hck->{computers}->{$cid}->{hostname}");
+			}
+			else {
+				# for now leave state as to annoy owner to either remove or update the machine
+				$hck->{computers}->{$cid}->{"valid_host"} = 0;
+				$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname}, $hck->{computers}->{$cid}->{IPaddress} : INVALID HOSTname, remove or update\n";
+				next;
+			}
+
+			my @basestatus = _baseline_checks($hck->{computers}->{$cid});
+			$hck->{computers}->{$cid}->{"ping"}           = $basestatus[0];
+			$hck->{computers}->{$cid}->{"sshd"}           = $basestatus[1];
+			$hck->{computers}->{$cid}->{"vclclientd"}     = $basestatus[2] if ($hck->{computers}->{$cid}->{type} eq "lab");
+			$hck->{computers}->{$cid}->{"localimagename"} = $basestatus[2] if ($hck->{computers}->{$cid}->{type} eq "blade");
+			$hck->{computers}->{$cid}->{"uptime"}         = $basestatus[3];
+			$hck->{computers}->{$cid}->{"basechecksok"}   = $basestatus[4];
+			$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname} : $basestatus[5]\n" if (defined($basestatus[5]));
+			#notify($ERRORS{'OK'},$LOG,"status= $basestatus[0],$basestatus[1],$basestatus[2],$basestatus[3],$basestatus[4]");
+
+			if ($hck->{computers}->{$cid}->{basechecksok}) {
+				#baseline checks ok, do more checks
+				if (_imagerevision_check($hck->{computers}->{$cid})) {
+
+				}
+
+				if ($hck->{computers}->{$cid}->{type} eq "lab") {
+					#  if(enablesshd($hck->{computers}->{$cid}->{hostname},"eostest1",$hck->{computers}->{$cid}->{IPaddress},"new",$hck->{computers}->{$cid}->{OSname},$LOG)){
+					#good now disable it disable($hostname,$unityname,$remoteIP,$state,$osname,$log
+					#   if(disablesshd($hck->{computers}->{$cid}->{hostname},"eostest1",$hck->{computers}->{$cid}->{IPaddress},"timeout",$hck->{computers}->{$cid}->{OSname},$LOG)){
+					$hck->{computers}->{$cid}->{"confirmedstate"} = "available";
+					$hck->{"labnodesavailable"} += 1;
+					$hck->{"globalmsg"}->{"correctedbody"} .= "$hck->{computers}->{$cid}->{hostname} : was failed, now active\n" if ($hck->{computers}->{$cid}->{state} eq "failed");
+					#  }
+					# else{
+					# #failed
+					#$hck->{computers}->{$cid}->{"confirmedstate"}="failed";
+					# $hck->{"labnodesfailed"} +=1;
+					#$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname} : failed could not disablesshd\n";
+					#}
+					#}
+					#else{
+					#failed
+					#$hck->{computers}->{$cid}->{"confirmedstate"}="failed";
+					#$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname} : failed could not enablesshd\n";
+					#}
+					if ($hck->{computers}->{$cid}->{uptime} >= 10) {
+						$hck->{"globalmsg"}->{"failedbody"} .= "$hck->{computers}->{$cid}->{hostname} : UPTIME $hck->{computers}->{$cid}->{uptime} days\n";
+					}
+				} ## end if ($hck->{computers}->{$cid}->{type} eq "lab")
+				elsif ($hck->{computers}->{$cid}->{type} eq "blade") {
+					#blade tasks
+					#options fork in order to load mulitples simultaneously
+					#TASKS:
+					# 1) partly completed, basechecks are ok, pingable, sshd running/logins ok,
+					# 2) does image name match whats listed
+					#
+					$hck->{computers}->{$cid}->{"confirmedstate"} = "available";
+				}
+			} ## end if ($hck->{computers}->{$cid}->{basechecksok...
+			else {
+				#basechecks failed, reason appended to failedbody already
+				if ($hck->{computers}->{$cid}->{type} eq "lab") {
+					# can not do much about a lab machine
+					$hck->{computers}->{$cid}->{"confirmedstate"} = "failed";
+					$hck->{"labnodesfailed"} += 1;
+				}
+				elsif ($hck->{computers}->{$cid}->{type} eq "blade") {
+					$hck->{computers}->{$cid}->{"confirmedstate"} = "failed";
+					#dig deeper --
+					#if no power turn on and wait
+					#if no sshd
+				}
+			} ## end else [ if ($hck->{computers}->{$cid}->{basechecksok...
+			UPDATESTATE:
+			if ($hck->{computers}->{$cid}->{"confirmedstate"} ne $hck->{computers}->{$cid}->{"state"}) {
+				#different states update db to reflected confirmed state
+				#my $stateid;
+				#$stateid = 2 if($hck->{computers}->{$cid}->{"confirmedstate"} eq "available");
+				#$stateid = 5 if($hck->{computers}->{$cid}->{"confirmedstate"} eq "failed");
+				#$stateid = 10 if($hck->{computers}->{$cid}->{"confirmedstate"} eq "maintenance");
+				$hck->{computers}->{$cid}->{"state"} = $hck->{computers}->{$cid}->{"confirmedstate"};
+				#notify($ERRORS{'OK'}, $LOG, "basestatus check= $hck->{computers}->{$cid}->{basechecksok} setting to $hck->{computers}->{$cid}->{hostname} to $hck->{computers}->{$cid}->{confirmedstate} ") if (updatestate(0, $hck->{computers}->{$cid}->{id}, "computer", $hck->{computers}->{$cid}->{confirmedstate}, 0, $LOG));
+				if (update_computer_state($hck->{computers}->{$cid}->{id}, $hck->{computers}->{$cid}->{confirmedstate})) {
+					notify($ERRORS{'OK'}, $LOG, "basestatus check= $hck->{computers}->{$cid}->{basechecksok} setting to $hck->{computers}->{$cid}->{hostname} to $hck->{computers}->{$cid}->{confirmedstate} ");
+				}
+
+			} ## end if ($hck->{computers}->{$cid}->{"confirmedstate"...
+		} ## end if ($hck->{computers}->{$cid}->{state} =~ ...
+		if ($hck->{computers}->{$cid}->{skip}) {
+			#update lastcheck time
+			my $datestring = makedatestring;
+			my $update_lc = $hck->{dbh}->prepare("UPDATE computer SET lastcheck=? WHERE id=?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare lastcheck time update" . $hck->{dbh}->errstr());
+			$update_lc->execute($datestring, $hck->{computers}->{$cid}->{id}) or notify($ERRORS{'WARNING'}, $LOG, "Could not execute lastcheck time update");
+			$update_lc->finish;
+		}
+	}    #for loop
+	$hck->{dbh}->disconnect;
+	return 1;
+} ## end sub process
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function   _valid_host
+///
+/// \param
+///
+/// \return   1,0
+///
+/// \brief  is this a valid host in dns
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub _valid_host {
+	my ($node) = @_;
+	my @ns     = qw(152.1.1.22 152.1.2.22 152.1.1.161);
+	my $rns    = \@ns;
+	my $res = Net::DNS::Resolver->new(nameservers => $rns,
+												 tcp_timeout => 5,
+												 retry       => 2);
+	my $q = $res->search($node);
+	if ($q) {
+		foreach my $rr ($q->answer) {
+			next unless $rr->type eq "A";
+			next unless $rr->type eq "PTR";
+		}
+		return 1;
+	}
+	else {
+		return 0;
+	}
+} ## end sub _valid_host
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function _baseline_checks
+///
+/// \param
+///
+/// \return array - ping status(1,0),ssh status(1,0),uptime(1,0)- reboots, basestatus (1,0), failure statement
+///
+/// \brief  pingable, sshd, uptime
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub _baseline_checks {
+	my ($cidhash) = @_;
+	#based on type and OS
+	#ping
+	#sshd
+	#uptime
+	# ? for unix lab machines is vclclientd running
+	my @ret;
+	my $node = $cidhash->{IPaddress};
+	if ($cidhash->{type} eq "blade") {
+		$node = $cidhash->{shortname};
+	}
+
+	# node_status
+	# hashref: reference to hash with keys/values:
+	#				         {status} => <"READY","FAIL">
+	#					   	{ping} => <0,1>
+	#					   	{ssh} => <0,1>
+	#						   {rpower} => <0,1>
+	#							{nodeset} => <"boot", "install", "image", ...>
+	#							{nodetype} => <image name>
+	#							{currentimage} => <image name>
+
+	if ($cidhash->{type} eq "lab") {
+		my $identity;
+		if ($cidhash->{OSname} =~ /sun4x/) {
+			$identity = $IDENTITY_solaris_lab;
+		}
+		elsif ($cidhash->{OSname} =~ /rhel/) {
+			$identity = $IDENTITY_linux_lab;
+		}
+		else {
+			notify($ERRORS{'OK'}, $LOG, "os $cidhash->{OSname} set but not something I can handle yet, will attempt the unix identity.");
+
+			$identity = $IDENTITY_linux_lab;
+		}
+
+		#my @status = VCL::Module::Provisioning::Lab::node_status($cidhash->{hostname}, $cidhash->{OSname}, $cidhash->{MNos}, $cidhash->{IPaddress}, $identity, $LOG);
+		my $node_status = VCL::Module::Provisioning::Lab::node_status($cidhash->{hostname}, $cidhash->{OSname}, $cidhash->{MNos}, $cidhash->{IPaddress}, $identity, $LOG);
+		if ($node_status->{ping}) {
+			#pingable
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{IPaddress} pingable");
+			push(@ret, 1);
+		}
+		else {
+			push(@ret, 0, 0, 0, 0, 0, "NOT pingable");
+			return @ret;
+		}
+		#sshd
+		if ($node_status->{ssh}) {
+			push(@ret, 1);
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{IPaddress} ssh reponds");
+		}
+		else {
+			push(@ret, 0, 0, 0, 0, "sshd NOT responding");
+			return @ret;
+		}
+		#vclclientd
+		if ($node_status->{vcl_client}) {
+			push(@ret, 1);
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{IPaddress} vclclientd running");
+		}
+		else {
+			push(@ret, 0, 0, 0, "vclclientd NOT running");
+			return @ret;
+		}
+		#check_uptime ($node,$IPaddress,$OSname,$type)
+		my @check_uptime_array = check_uptime($cidhash->{hostname}, $cidhash->{IPaddress}, $cidhash->{OSname}, $cidhash->{type}, $LOG);
+		push(@ret, $check_uptime_array[0]);
+
+		#if here then basechecks are ok
+		push(@ret, 1);
+
+	} ## end if ($cidhash->{type} eq "lab")
+	elsif ($cidhash->{type} eq "blade") {
+		#my @status = VCL::Module::Provisioning::xCAT::node_status($cidhash->{shortname}, $LOG);
+		my $node_status = VCL::Module::Provisioning::xCAT::node_status($cidhash->{shortname}, $LOG);
+		# First see if it returned a hashref
+		if (ref($node_status) eq 'HASH') {
+			notify($ERRORS{'DEBUG'}, 0, "node_status returned a hash reference");
+		}
+
+		# Check if node_status returned an array ref
+		elsif (ref($node_status) eq 'ARRAY') {
+			notify($ERRORS{'OK'}, $LOG, "node_status returned an array reference");
+
+		}
+
+		# Check if node_status didn't return a reference
+		# Assume string was returned
+		elsif (!ref($node_status)) {
+			# Use scalar value of node_status's return value
+		}
+
+		else {
+			notify($ERRORS{'OK'}, $LOG, "->node_status() returned an unsupported reference type: " . ref($node_status) . ", returning");
+			return;
+		}
+
+		#host/power (pingable)
+		#if ($status[1] eq "on") {
+		if ($node_status->{rpower}) {
+			#powered on
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{shortname} power on ");
+			push(@ret, 1);
+		}
+		else {
+			push(@ret, 0, 0, 0, 0, 0, "Powered off\n");
+			return @ret;
+		}
+		#sshd
+		#if ($status[3] eq "on") {
+		if ($node_status->{ssh}) {
+			push(@ret, 1);
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{shortname} ssh reponds");
+		}
+		else {
+			push(@ret, 0, 0, 0, 0, "$cidhash->{shortname} sshd NOT responding");
+			return @ret;
+		}
+		#imagename
+		#if ($status[7]) {
+		if ($node_status->{nodetype}) {
+			notify($ERRORS{'OK'}, $LOG, "$cidhash->{shortname} imagename set $node_status->{nodetype}");
+
+			if ($node_status->{currentimage}) {
+				if ($node_status->{currentimage} =~ /\r/) {
+					chop($node_status->{currentimage});
+					#notify($ERRORS{'OK'},$LOG,"$cidhash->{shortname} imagename had carriage return $status[8]");
+				}
+				if ($node_status->{nodetype} =~ /$node_status->{currentimage}/) {    #do 7 & 8 match
+					                                                                  #notify($ERRORS{'OK'},$LOG,"$cidhash->{shortname} nodetype matches imagename on local file");
+					push(@ret, $node_status->{nodetype});
+				}
+				else {
+					#notify($ERRORS{'OK'},$LOG,"$cidhash->{shortname} nodetype DO NOT matche imagename on remote file");
+					push(@ret, "$node_status->{currentimage}");
+				}
+			} ## end if ($node_status->{currentimage})
+			else {
+				#possible linux env
+				push(@ret, $node_status->{nodetype});
+			}
+
+		} ## end if ($node_status->{nodetype})
+		else {
+			#very strange imagename for nodetype not defined
+			push(@ret, 0, 0, "imagename for nodetype not defined");
+			return @ret;
+		}
+		#uptime not checkable yet for some blades
+		#basechecks ok if made it here
+		push(@ret, 0, 1);
+
+		notify($ERRORS{'OK'}, $LOG, "$cidhash->{shortname} past basecheck flag ret = @ret");
+
+	} ## end elsif ($cidhash->{type} eq "blade")  [ if ($cidhash->{type} eq "lab")
+
+	return @ret;
+} ## end sub _baseline_checks
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function   _reload
+///
+/// \param
+///
+/// \return array - [1,0], [string]
+///
+/// \brief  trys to reload the blade if needed, returns success or reason why could not be done
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub _reload {
+	my ($cidhash) = @_;
+
+}
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function _imagerevision_check
+///
+/// \param
+///
+/// \return array - [1,0], [string]
+///
+/// \brief  checks image name and revsion number of computer id
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub _imagerevision_check {
+	my ($cidhash) = @_;
+
+	if (!($MYDBH->ping)) {
+		$MYDBH = getnewdbh();
+	}
+
+	my %imagerev;
+
+	my $sel = $MYDBH->prepare(
+		"SELECT ir.id,ir.imagename,ir.revision,ir.production
+                          FROM imagerevision ir
+                          WHERE ir.imageid = ?")                                         or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare select for imagerevision check" . $MYDBH->errstr());
+	$sel->execute($cidhash->{currentimageid}) or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare select for imagerevision check" . $MYDBH->errstr());
+
+	my $update = $MYDBH->prepare("UPDATE computer SET imagerevisionid =? WHERE id = ?") or notify($ERRORS{'WARNING'}, $LOG, "Could not prepare update for correct image revision" . $MYDBH->errstr());
+
+	my $rows = $sel->rows;
+	if ($rows != 0) {
+		while (my @row = $sel->fetchrow_array) {
+			$imagerev{"$row[0]"}{"id"}         = $row[0];
+			$imagerev{"$row[0]"}{"imagename"}  = $row[1];
+			$imagerev{"$row[0]"}{"revision"}   = $row[2];
+			$imagerev{"$row[0]"}{"production"} = $row[3];
+			if ($row[3]) {
+				#check computer version
+				if ($row[0] != $cidhash->{imagerevisionid}) {
+					$update->execute($row[0], $cidhash->{id}) or notify($ERRORS{'WARNING'}, $LOG, "Could not update for correct image revision" . $MYDBH->errstr());
+					notify($ERRORS{'OK'}, $LOG, "imagerevisionid $cidhash->{imagerevisionid} does not match on computer id $cidhash->{id} -- setting to version $row[2] revision id $row[0]");
+				}
+				else {
+					notify($ERRORS{'OK'}, $LOG, "imagerevision matches -- skipping update");
+				}
+				return 1;
+			} ## end if ($row[3])
+		} ## end while (my @row = $sel->fetchrow_array)
+	} ## end if ($rows != 0)
+	else {
+		notify($ERRORS{'WARNING'}, $LOG, "imagerevision check -- no rows found for computer id $cidhash->{id}");
+		return 0;
+	}
+
+} ## end sub _imagerevision_check
+
+=pod
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn function send_report
+///
+/// \param
+///
+/// \return  1,0
+///
+/// \brief  sends detailed report to owners of possible issues with the boxes
+///
+////////////////////////////////////////////////////////////////////////////////
+=cut
+
+sub send_report {
+	my ($hck) = @_;
+
+	#notify($ERRORS{'OK'},$LOG,"$hck->{globalmsg}->{body}\n\n $hck->{globalmsg}->{failedbody}\n");
+	if (defined($hck->{computercount})) {
+		$hck->{globalmsg}->{body} .= "Number of nodes found for this management node $hck->{MN}: $hck->{computercount}\n";
+	}
+	if (defined($hck->{"computerschecked"})) {
+		$hck->{globalmsg}->{body} .= "Number of nodes checked: $hck->{computerschecked}\n";
+	}
+	if (defined($hck->{"computersskipped"})) {
+		$hck->{globalmsg}->{body} .= "Number of nodes skipped due to recent check: $hck->{computersskipped}\n";
+	}
+	if (defined($hck->{labnodesfailed})) {
+		$hck->{globalmsg}->{body} .= "UNavailable labnodes: $hck->{labnodesfailed}\n";
+	}
+	if (defined($hck->{labnodesavailable})) {
+		$hck->{globalmsg}->{body} .= "Available labnodes: $hck->{labnodesavailable}\n";
+	}
+
+	if (defined($hck->{globalmsg}->{correctedbody})) {
+		$hck->{globalmsg}->{body} .= "\nCorrected VCL nodes:\n\n$hck->{globalmsg}->{correctedbody}\n";
+	}
+	if (defined($hck->{globalmsg}->{failedbody})) {
+		$hck->{"globalmsg"}->{body} .= "\nProblem VCL nodes:\n\n$hck->{globalmsg}->{failedbody}\n";
+
+	}
+	if (!defined($hck->{globalmsg}->{failedbody}) && !defined($hck->{globalmsg}->{correctedbody})) {
+		$hck->{globalmsg}->{body} .= "\nAll nodes report ok";
+
+	}
+	mail($SYSADMIN, "VCL node monitoring report", "$hck->{globalmsg}->{body}");
+} ## end sub send_report
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 BUGS and LIMITATIONS
+
+ There are no known bugs in this module.
+ Please report problems to the VCL team (vcl_help@ncsu.edu).
+
+=head1 AUTHOR
+
+ Aaron Peeler, aaron_peeler@ncsu.edu
+ Andy Kurth, andy_kurth@ncsu.edu
+
+=head1 SEE ALSO
+
+L<http://vcl.ncsu.edu>
+
+
+=cut

Added: incubator/vcl/tags/import/managementnode/lib/VCL/image.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/image.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/image.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/image.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,460 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+##############################################################################
+# $Id: image.pm 1945 2008-12-11 20:58:08Z fapeeler $
+##############################################################################
+
+=head1 NAME
+
+VCL::image - Perl module for the VCL image state
+
+=head1 SYNOPSIS
+
+ use VCL::image;
+ 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::image object based on the request information
+ my $image = VCL::image->new(%request_info);
+
+=head1 DESCRIPTION
+
+ This module supports the VCL "image" state.
+
+=cut
+
+##############################################################################
+package VCL::image;
+
+# 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.00';
+
+# 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  : $request_data_hash_reference
+ Returns     : 1 if successful, 0 otherwise
+ Description : Processes a reservation in the timout state. You must pass this
+               method a reference to a hash containing request data.
+
+=cut
+
+sub process {
+	my $self                       = shift;
+	my $request_id                 = $self->data->get_request_id();
+	my $reservation_id             = $self->data->get_reservation_id();
+	my $user_id                    = $self->data->get_user_id();
+	my $user_unityid               = $self->data->get_user_login_id();
+	my $user_preferredname         = $self->data->get_user_preferred_name();
+	my $user_email                 = $self->data->get_user_email();
+	my $affiliation_sitewwwaddress = $self->data->get_user_affiliation_sitewwwaddress();
+	my $affiliation_helpaddress    = $self->data->get_user_affiliation_helpaddress();
+	my $image_id                   = $self->data->get_image_id();
+	my $image_name                 = $self->data->get_image_name();
+	my $image_prettyname           = $self->data->get_image_prettyname();
+	my $image_size                 = $self->data->get_image_size();
+	my $imagerevision_id           = $self->data->get_imagerevision_id();
+	my $imagemeta_sysprep          = $self->data->get_imagemeta_sysprep();
+	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 $managementnode_shortname   = $self->data->get_management_node_short_name();
+
+	# Notify administrators that image creation is starting
+	my $body = <<"END";
+VCL Image Creation Started
+
+Request ID: $request_id
+Reservation ID: $reservation_id
+PID: $$
+
+Image ID: $image_id
+Image name: $image_name
+Base image size: $image_size
+Base revision ID: $imagerevision_id
+
+Management node: $managementnode_shortname
+
+Username: $user_unityid
+User ID: $user_id
+
+Computer ID: $computer_id
+Computer name: $computer_shortname
+
+Use Sysprep: $imagemeta_sysprep
+END
+	mail($SYSADMIN, "VCL IMAGE Creation Started: $image_name", $body, $affiliation_helpaddress);
+
+	# Make sure image does not exist in the repository
+	my $image_already_exists = $self->provisioner->does_image_exist();
+	if ($image_already_exists) {
+		notify($ERRORS{'CRITICAL'}, 0, "image $image_name already exists in the repository");
+		$self->image_creation_failed();
+	}
+	elsif (!defined($image_already_exists)) {
+		notify($ERRORS{'CRITICAL'}, 0, "image $image_name already partially exists in the repository");
+		$self->image_creation_failed();
+	}
+	else {
+		notify($ERRORS{'OK'}, 0, "image $image_name does not exist in the repository");
+	}
+
+	# Get the current timestamp
+	# This will be used for image.lastupdate, imagerevision.datecreated and currentimage.txt
+	my $timestamp = makedatestring();
+	$self->data->set_image_lastupdate($timestamp);
+	$self->data->set_imagerevision_date_created($timestamp);
+
+	# Call the create image subroutine in utils.pm
+	my $create_image_result;
+	if ($computer_type eq "blade" && $self->os) {
+		$create_image_result = 1;
+
+		notify($ERRORS{'OK'}, 0, "OS modularization supported, beginning OS module capture prepare");
+		if (!($create_image_result = $self->os->capture_prepare())) {
+			notify($ERRORS{'WARNING'}, 0, "OS module capture prepare failed");
+		}
+
+		notify($ERRORS{'OK'}, 0, "beginning provisioning module capture prepare");
+		if ($create_image_result && !($create_image_result = $self->provisioner->capture_prepare())) {
+			notify($ERRORS{'WARNING'}, 0, "provisioning module capture prepare failed");
+		}
+
+		notify($ERRORS{'OK'}, 0, "beginning OS module capture start");
+		if ($create_image_result && !($create_image_result = $self->os->capture_start())) {
+			notify($ERRORS{'WARNING'}, 0, "OS module capture start failed");
+		}
+
+		notify($ERRORS{'OK'}, 0, "beginning provisioning module capture monitor");
+		if ($create_image_result && !($create_image_result = $self->provisioner->capture_monitor())) {
+			notify($ERRORS{'WARNING'}, 0, "provisioning module capture monitor failed");
+		}
+
+	} ## end if ($computer_type eq "blade" && $self->os)
+	elsif ($computer_type eq "blade") {
+		$create_image_result = $self->provisioner->capture_prepare();
+
+		if ($create_image_result) {
+			$create_image_result = $self->provisioner->capture_monitor();
+		}
+	}
+	elsif ($computer_type eq "virtualmachine") {
+		$create_image_result = $self->provisioner->capture();
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "unsupported computer type: $computer_type");
+		$self->image_creation_failed();
+	}
+
+	# Image creation was successful, proceed to update database tables
+	if ($create_image_result) {
+		# Success
+		notify($ERRORS{'OK'}, 0, "$image_name image files successfully saved");
+
+		# Update the request state to completed, laststate to image
+		if (update_request_state($request_id, "completed", "image")) {
+			notify($ERRORS{'OK'}, 0, "request state updated to completed, laststate to image");
+		}
+		else {
+			notify($ERRORS{'CRITICAL'}, 0, "unable to update request state to completed, laststate to image");
+		}
+
+		# Get the new image size
+		my $image_size_new;
+		if ($image_size_new = $self->provisioner->get_image_size($image_name)) {
+			notify($ERRORS{'OK'}, 0, "size of $image_name: $image_size_new");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "unable to retrieve size of new revision: $image_name, old size will be used");
+			$image_size_new = $image_size;
+		}
+		$self->data->set_image_size($image_size_new);
+
+		# Update image timestamp, clear deleted flag
+		# Set test flag if according to whether this image is new or updated
+		# Update the image size
+		my $update_image_statement = "
+		UPDATE
+		image,
+		imagerevision
+		SET
+		image.lastupdate = \'$timestamp\',
+		image.deleted = \'0\',
+		image.size = \'$image_size_new\',
+		image.name = \'$image_name\',
+		imagerevision.deleted = \'0\',
+		imagerevision.datecreated = \'$timestamp\'
+		WHERE
+		image.id = $image_id
+		AND imagerevision.id = $imagerevision_id
+		";
+
+		# Execute the image update statement
+		if (database_execute($update_image_statement)) {
+			notify($ERRORS{'OK'}, 0, "image and imagerevision tables updated for image=$image_id, imagerevision=$imagerevision_id, name=$image_name, lastupdate=$timestamp, deleted=0, size=$image_size_new");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "image table could not be updated for image=$image_id");
+		}
+	} ## end if ($create_image_result)
+
+	# Check if image creation was successful and database tables were successfully updated
+	# Notify user and admins of the results
+	if ($create_image_result) {
+		$self->image_creation_successful($image_size);
+	}
+
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "image creation failed, see previous log messages");
+		$self->image_creation_failed();
+	}
+
+} ## end sub process
+#/////////////////////////////////////////////////////////////////////////////
+
+sub image_creation_successful {
+	my $self           = shift;
+	my $image_size_old = shift;
+
+	my $request_data               = $self->data->get_request_data();
+	my $request_id                 = $self->data->get_request_id();
+	my $reservation_id             = $self->data->get_reservation_id();
+	my $user_id                    = $self->data->get_user_id();
+	my $user_unityid               = $self->data->get_user_login_id();
+	my $user_preferredname         = $self->data->get_user_preferred_name();
+	my $user_email                 = $self->data->get_user_email();
+	my $affiliation_sitewwwaddress = $self->data->get_user_affiliation_sitewwwaddress();
+	my $affiliation_helpaddress    = $self->data->get_user_affiliation_helpaddress();
+	my $image_id                   = $self->data->get_image_id();
+	my $image_name                 = $self->data->get_image_name();
+	my $image_prettyname           = $self->data->get_image_prettyname();
+	my $image_size                 = $self->data->get_image_size();
+	my $imagerevision_id           = $self->data->get_imagerevision_id();
+	my $imagemeta_sysprep          = $self->data->get_imagemeta_sysprep();
+	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 $managementnode_shortname   = $self->data->get_management_node_short_name();
+
+	# Send image creation successful email to user
+	my $body_user = <<"END";
+$user_preferredname,
+Your VCL image creation request for $image_prettyname has
+succeeded.  Please visit $affiliation_sitewwwaddress and
+you should see an image called $image_prettyname.
+Please test this image to confirm it works correctly.
+
+Thank You,
+VCL Team
+END
+	mail($user_email, "VCL -- $image_prettyname Image Creation Succeeded", $body_user, $affiliation_helpaddress);
+
+	# Send mail to SYSADMIN
+	my $body_admin = <<"END";
+VCL Image Creation Completed
+
+Request ID: $request_id
+Reservation ID: $reservation_id
+PID: $$
+
+Image ID: $image_id
+Image name: $image_name
+Image size change: $image_size_old --> $image_size
+
+Revision ID: $imagerevision_id
+
+Management node: $managementnode_shortname
+
+Username: $user_unityid
+User ID: $user_id
+
+Computer ID: $computer_id
+Computer name: $computer_shortname
+
+Use Sysprep: $imagemeta_sysprep
+END
+
+	mail($SYSADMIN, "VCL IMAGE Creation Completed: $image_name", $body_admin, $affiliation_helpaddress);
+
+	# Insert reload request data into the datbase
+	if (insert_reload_request($request_data)) {
+		notify($ERRORS{'OK'}, 0, "inserted reload request into database for computer id=$computer_id");
+
+		# Switch the request state to complete, leave the computer state as is, update log ending to EOR, exit
+		switch_state($request_data, 'complete', '', 'EOR', '1');
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "failed to insert reload request into database for computer id=$computer_id");
+
+		# Switch the request and computer states to failed, set log ending to failed, exit
+		switch_state($request_data, 'failed', 'failed', 'failed', '1');
+	}
+
+	notify($ERRORS{'OK'}, 0, "exiting");
+	exit;
+} ## end sub image_creation_successful
+
+#/////////////////////////////////////////////////////////////////////////////
+
+sub image_creation_failed {
+	my $self = shift;
+
+	my $request_data               = $self->data->get_request_data();
+	my $request_id                 = $self->data->get_request_id();
+	my $reservation_id             = $self->data->get_reservation_id();
+	my $user_id                    = $self->data->get_user_id();
+	my $user_unityid               = $self->data->get_user_login_id();
+	my $user_preferredname         = $self->data->get_user_preferred_name();
+	my $user_email                 = $self->data->get_user_email();
+	my $affiliation_sitewwwaddress = $self->data->get_user_affiliation_sitewwwaddress();
+	my $affiliation_helpaddress    = $self->data->get_user_affiliation_helpaddress();
+	my $image_id                   = $self->data->get_image_id();
+	my $image_name                 = $self->data->get_image_name();
+	my $image_prettyname           = $self->data->get_image_prettyname();
+	my $image_size                 = $self->data->get_image_size();
+	my $imagerevision_id           = $self->data->get_imagerevision_id();
+	my $imagemeta_sysprep          = $self->data->get_imagemeta_sysprep();
+	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 $managementnode_shortname   = $self->data->get_management_node_short_name();
+
+	# Image process failed
+	notify($ERRORS{'CRITICAL'}, 0, "$image_name image creation failed");
+
+	# Send mail to user
+	my $body_user = <<"END";
+$user_preferredname,
+We apologize for the inconvenience.
+Your image creation of $image_prettyname has been delayed
+due to a system issue that prevented the automatic completion.
+
+The image creation request and the computing resource have
+been placed in a safe mode. The VCL system administrators
+have been notified for manual intervention.
+
+Once the issues have been resolved, you will be notified
+by the successful completion email or contacted directly
+by the VCL system administrators.
+
+If you do not receive a response within one business day, please
+reply to this email.
+
+Thank You,
+VCL Team
+END
+	mail($user_email, "VCL -- NOTICE DELAY Image Creation $image_prettyname", $body_user, $affiliation_helpaddress);
+
+	# Send mail to SYSADMIN
+	my $body_admin = <<"END";
+VCL Image Creation Failed
+
+Request ID: $request_id
+Reservation ID: $reservation_id
+PID: $$
+
+Image ID: $image_id
+Image name: $image_name
+
+Revision ID: $imagerevision_id
+
+Management node: $managementnode_shortname
+
+Username: $user_unityid
+User ID: $user_id
+
+Computer ID: $computer_id
+Computer name: $computer_shortname
+
+Use Sysprep: $imagemeta_sysprep
+END
+
+	mail($SYSADMIN, "VCL -- NOTICE FAILED Image Creation $image_prettyname", $body_admin, $affiliation_helpaddress);
+
+	# Update the request state to maintenance, laststate to image
+	if (update_request_state($request_id, "maintenance", "image")) {
+		notify($ERRORS{'OK'}, 0, "request state set to maintenance, laststate to image");
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "unable to set request state to maintenance, laststate to image");
+	}
+
+	# Update the computer state to maintenance
+	if (update_computer_state($computer_id, "maintenance")) {
+		notify($ERRORS{'OK'}, 0, "$computer_shortname state set to maintenance");
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "unable to set $computer_shortname state to maintenance");
+	}
+
+	notify($ERRORS{'OK'}, 0, "exiting");
+	exit;
+} ## end sub image_creation_failed
+
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 BUGS and LIMITATIONS
+
+ There are no known bugs in this module.
+ Please report problems to the VCL team (vcl_help@ncsu.edu).
+
+=head1 AUTHOR
+
+ Aaron Peeler, aaron_peeler@ncsu.edu
+ Andy Kurth, andy_kurth@ncsu.edu
+
+=head1 SEE ALSO
+
+L<http://vcl.ncsu.edu>
+
+=cut

Added: incubator/vcl/tags/import/managementnode/lib/VCL/inuse.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/tags/import/managementnode/lib/VCL/inuse.pm?rev=726079&view=auto
==============================================================================
--- incubator/vcl/tags/import/managementnode/lib/VCL/inuse.pm (added)
+++ incubator/vcl/tags/import/managementnode/lib/VCL/inuse.pm Fri Dec 12 10:20:10 2008
@@ -0,0 +1,865 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+##############################################################################
+# $Id: inuse.pm 1945 2008-12-11 20:58:08Z fapeeler $
+##############################################################################
+
+=head1 NAME
+
+VCL::inuse - Perl module for the VCL inuse state
+
+=head1 SYNOPSIS
+
+ use VCL::inuse;
+ 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::inuse object based on the request information
+ my $inuse = VCL::inuse->new(%request_info);
+
+=head1 DESCRIPTION
+
+ This module supports the VCL "inuse" state. The inuse state is reached after
+ a user has made a reservation, acknowledged the reservation, and connected to
+ the machine. Once connected, vcld creates a new process which then
+ creates a new instance of this module.
+
+ If the "checkuser" flag is set for the image that the user requested,
+ this process will periodically check to make sure the user is still
+ connected. Users have 15 minutes to reconnect before the machine is
+ reclaimed.
+
+ This module periodically checks the end time for the user's request versus
+ the current time. If the end time is near, notifications may be sent to the
+ user. Once the end time has been reached, the user is disconnected and the
+ request and computer are put into the "timeout" state.
+
+=cut
+
+##############################################################################
+package VCL::inuse;
+
+# 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.00';
+
+# 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  : $request_data_hash_reference
+ Returns     : 1 if successful, 0 otherwise
+ Description : Processes a reservation in the inuse state. You must pass this
+               method a reference to a hash containing request data.
+
+=cut
+
+sub process {
+	my $self = shift;
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	# Store hash variables into local variables
+	my $request_data = $self->data->get_request_data;
+
+	my $request_id            = $request_data->{id};
+	my $reservation_id        = $request_data->{RESERVATIONID};
+	my $request_end           = $request_data->{end};
+	my $request_logid         = $request_data->{logid};
+	my $request_checktime     = $request_data->{CHECKTIME};
+	my $reservation_remoteip  = $request_data->{reservation}{$reservation_id}{remoteIP};
+	my $computer_id           = $request_data->{reservation}{$reservation_id}{computer}{id};
+	my $computer_shortname    = $request_data->{reservation}{$reservation_id}{computer}{SHORTNAME};
+	my $computer_type         = $request_data->{reservation}{$reservation_id}{computer}{type};
+	my $computer_hostname     = $request_data->{reservation}{$reservation_id}{computer}{hostname};
+	my $computer_nodename     = $request_data->{reservation}{$reservation_id}{computer}{NODENAME};
+	my $computer_ipaddress    = $request_data->{reservation}{$reservation_id}{computer}{IPaddress};
+	my $image_os_name         = $request_data->{reservation}{$reservation_id}{image}{OS}{name};
+	my $imagemeta_checkuser   = $request_data->{reservation}{$reservation_id}{image}{imagemeta}{checkuser};
+	my $user_unityid          = $request_data->{user}{unityid};
+	my $request_forimaging    = $request_data->{forimaging};
+	my $identity_key          = $request_data->{reservation}{$reservation_id}{image}{IDENTITY};
+	my $image_os_type         = $self->data->get_image_os_type();
+	my $reservation_count     = $self->data->get_reservation_count();
+	my $is_parent_reservation = $self->data->is_parent_reservation();
+
+	# Set the user connection timeout limit in minutes
+	my $connect_timeout_limit = 15;
+
+	# Remove rows from computerloadlog for this reservation
+	if (delete_computerloadlog_reservation($reservation_id)) {
+		notify($ERRORS{'OK'}, 0, "rows removed from computerloadlog table for reservation $reservation_id");
+	}
+	else {
+		notify($ERRORS{'OK'}, 0, "unable to remove rows from computerloadlog table for reservation $reservation_id");
+	}
+
+	# Update the lastcheck value for this reservation to now
+	if (update_reservation_lastcheck($reservation_id)) {
+		notify($ERRORS{'OK'}, 0, "updated lastcheck time for reservation $reservation_id");
+	}
+	else {
+		notify($ERRORS{'CRITICAL'}, 0, "unable to update lastcheck time for reservation $reservation_id");
+	}
+
+	# For inuse state, check_time should return 'end', 'poll', or 'nothing'
+
+	# Is this a poll or end time
+	if ($request_checktime eq "poll") {
+		notify($ERRORS{'OK'}, 0, "beginning to poll");
+
+		if ($image_os_type =~ /windows/) {
+			if (firewall_compare_update($computer_nodename, $reservation_remoteip, $identity_key, $image_os_type)) {
+				notify($ERRORS{'OK'}, 0, "confirmed firewall scope has been updated");
+			}
+		}
+
+		# Check the imagemeta checkuser flag, request forimaging flag, and if cluster request
+		if (!$imagemeta_checkuser || $request_forimaging || ($reservation_count > 1)) {
+			# Either imagemeta checkuser flag = 0, forimaging = 1, or cluster request
+			if (!$imagemeta_checkuser) {
+				notify($ERRORS{'OK'}, 0, "imagemeta checkuser flag not set, skipping user connection check");
+			}
+			if ($request_forimaging) {
+				notify($ERRORS{'OK'}, 0, "forimaging flag is set to 1, skipping user connection check");
+			}
+			if ($reservation_count > 1) {
+				notify($ERRORS{'OK'}, 0, "reservation count is $reservation_count, skipping user connection check");
+			}
+
+			# Get a date string for the current time
+			my $date_string;
+
+			# Check end time for a notice interval
+			# This returns 0 if no notice is to be given
+			my $notice_interval = check_endtimenotice_interval($request_end);
+
+			if ($notice_interval) {
+				notify($ERRORS{'OK'}, 0, "notice interval is set to $notice_interval");
+
+				# Notify the user of the end time
+				$self->_notify_user_endtime($notice_interval);
+
+				# Set lastcheck time ahead by 16 minutes for all notices except the last (30 minute) notice
+				if ($notice_interval ne "30 minutes") {
+					my $epoch_now = convert_to_epoch_seconds();
+					$date_string = convert_to_datetime(($epoch_now + (16 * 60)));
+				}
+				else {
+					my $epoch_now = convert_to_epoch_seconds();
+					$date_string = convert_to_datetime($epoch_now);
+				}
+			} ## end if ($notice_interval)
+
+			# Check if the user deleted the request
+			if (is_request_deleted($request_id)) {
+				# User deleted request, exit queitly
+				notify($ERRORS{'OK'}, 0, "user has deleted the request, quietly exiting");
+				exit;
+			}
+
+			# If forimage flag is set - check for state change to image creation mode and exit quietly
+			if ($request_forimaging) {
+				notify($ERRORS{'DEBUG'}, 0, "request has forimaging flag enabled, checking for image state");
+				if (is_request_imaging($request_id)) {
+					notify($ERRORS{'OK'}, 0, "request is now in image creation mode, quietly exiting");
+					exit;
+				}
+			}
+
+			# Put this request back into the inuse state
+			if ($is_parent_reservation && update_request_state($request_id, "inuse", "inuse")) {
+				notify($ERRORS{'OK'}, 0, "request state set back to inuse");
+			}
+			elsif (!$is_parent_reservation) {
+				notify($ERRORS{'OK'}, 0, "child reservation, request state NOT set back to inuse");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set request state back to inuse");
+			}
+
+			# Update the lastcheck time for this reservation
+			if (update_reservation_lastcheck($reservation_id)) {
+				my $dstring = convert_to_datetime();
+				notify($ERRORS{'OK'}, 0, "updated lastcheck time for this reservation to $dstring");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to update lastcheck time for this reservation to $date_string");
+			}
+
+			notify($ERRORS{'OK'}, 0, "exiting");
+			exit;
+		}    # Close if poll and checkuser = 0
+
+
+		# Poll:
+		# Simply check for user connection
+		# If not connected:
+		#   Loop; check end time, continue to check for connection
+		#   If not connected within 15 minutes -- timeout
+		#   If end time is near prepare
+		notify($ERRORS{'OK'}, 0, "proceeding to check for user connection");
+
+		# Get epoch seconds for current and end time, calculate difference
+		my $now_epoch       = convert_to_epoch_seconds();
+		my $end_epoch       = convert_to_epoch_seconds($request_end);
+		my $time_difference = $end_epoch - $now_epoch;
+
+		# If end time is 10-15 minutes from now:
+		#    Sleep difference
+		#    Go to end mode
+		if ($time_difference >= (10 * 60) && $time_difference <= (15 * 60)) {
+			notify($ERRORS{'OK'}, 0, "end time ($time_difference seconds) is 10-15 minutes from now");
+
+			# Calculate the sleep time = time until the request end - 10 minutes
+			# User will have 10 minutes after this sleep call before disconnected
+			my $sleep_time = $time_difference - (10 * 60);
+			notify($ERRORS{'OK'}, 0, "sleeping for $sleep_time seconds");
+			sleep $sleep_time;
+			$request_data->{CHECKTIME} = "end";
+			goto ENDTIME;
+		}    # Close if poll, checkuser=1, and end time is 10-15 minutes away
+
+		notify($ERRORS{'OK'}, 0, "end time not yet reached, polling machine for user connection");
+
+		# Check the user connection, this will loop until user connects or time limit is reached
+		my $check_connection = check_connection($computer_nodename, $computer_ipaddress, $computer_type, $reservation_remoteip, $connect_timeout_limit, $image_os_name, 0, $request_id, $user_unityid);
+
+		#TESTING
+		#$check_connection = 'timeout';
+
+		# Proceed based on status of check_connection
+		if ($check_connection eq "connected") {
+			notify($ERRORS{'OK'}, 0, "user connected");
+
+			# Put this request back into the inuse state
+			if (update_request_state($request_id, "inuse", "inuse")) {
+				notify($ERRORS{'OK'}, 0, "request state set back to inuse");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set request state back to inuse");
+			}
+
+			# Update the lastcheck time for this reservation
+			if (update_reservation_lastcheck($reservation_id)) {
+				notify($ERRORS{'OK'}, 0, "updated lastcheck time for this reservation to now");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to update lastcheck time for this reservation to now");
+			}
+
+			notify($ERRORS{'OK'}, 0, "exiting");
+			exit;
+		}    # Close check_connection is connected
+
+		elsif ($check_connection eq "conn_wrong_ip") {
+			notify($ERRORS{'OK'}, 0, "polling, user connected but wrong remote IP is used");
+
+			# Update the lastcheck time for this reservation
+			if (update_reservation_lastcheck($reservation_id)) {
+				notify($ERRORS{'OK'}, 0, "updated lastcheck time for this reservation to now");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to update lastcheck time for this reservation to now");
+			}
+
+			# Put this request back into the inuse state
+			if (update_request_state($request_id, "inuse", "inuse")) {
+				notify($ERRORS{'OK'}, 0, "request state set back to inuse");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set request state back to inuse");
+			}
+
+			notify($ERRORS{'OK'}, 0, "exiting");
+			exit;
+		} ## end elsif ($check_connection eq "conn_wrong_ip")  [ if ($check_connection eq "connected")
+
+
+		elsif ($check_connection eq "timeout") {
+			notify($ERRORS{'OK'}, 0, "user did not reconnect within $connect_timeout_limit minute time limit");
+
+			notify($ERRORS{'OK'}, 0, "notifying user that request timed out");
+			$self->_notify_user_timeout();
+
+			# Put this request into the timeout state
+			if (update_request_state($request_id, "timeout", "inuse")) {
+				notify($ERRORS{'OK'}, 0, "request state set to timeout");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set request state to timeout");
+			}
+
+			# Get the current computer state directly from the database
+			my $computer_state;
+			if ($computer_state = get_computer_current_state_name($computer_id)) {
+				notify($ERRORS{'OK'}, 0, "computer $computer_id state retrieved from database: $computer_state");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to retrieve computer $computer_id state from database");
+			}
+
+			# Check if computer is in maintenance state
+			if ($computer_state =~ /maintenance/) {
+				notify($ERRORS{'OK'}, 0, "computer $computer_shortname in maintenance state, skipping update");
+			}
+			else {
+				# Computer is not in maintenance state, set its state to timeout
+				if (update_computer_state($computer_id, "timeout")) {
+					notify($ERRORS{'OK'}, 0, "computer $computer_id set to timeout state");
+				}
+				else {
+					notify($ERRORS{'WARNING'}, 0, "unable to set computer $computer_id to the timeout state");
+				}
+			}
+
+			# Update the entry in the log table with the current finalend time and ending set to timeout
+			if (update_log_ending($request_logid, "timeout")) {
+				notify($ERRORS{'OK'}, 0, "log id $request_logid finalend was updated to now and ending set to timeout");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "log id $request_logid finalend could not be updated to now and ending set to timeout");
+			}
+
+			notify($ERRORS{'OK'}, 0, "exiting");
+			exit;
+		} ## end elsif ($check_connection eq "timeout")  [ if ($check_connection eq "connected")
+
+		elsif ($check_connection eq "deleted") {
+			# Exit quietly
+			notify($ERRORS{'OK'}, 0, "user has deleted the request, quietly exiting");
+			exit;
+		}
+
+		else {
+			notify($ERRORS{'CRITICAL'}, 0, "unexpected return value from check_connection: $check_connection, treating request as connected");
+
+			# Put this request back into the inuse state
+			if (update_request_state($request_id, "inuse", "inuse")) {
+				notify($ERRORS{'OK'}, 0, "request state set back to inuse");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set request state back to inuse");
+			}
+
+			# Update the lastcheck time for this reservation
+			if (update_reservation_lastcheck($reservation_id)) {
+				notify($ERRORS{'OK'}, 0, "updated lastcheck time for this reservation to now");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to update lastcheck time for this reservation to now");
+			}
+
+			notify($ERRORS{'OK'}, 0, "exiting");
+			exit;
+		} ## end else [ if ($check_connection eq "connected")  [... [elsif ($check_connection eq "deleted")
+
+	}    # Close if checktime is poll
+
+	elsif ($request_checktime eq "end") {
+		# Time has ended
+		# Notify user to save work and exit within 10 minutes
+
+		ENDTIME:
+		my $notified        = 0;
+		my $disconnect_time = 10;
+
+		# Loop until disconnect time = 0
+		while ($disconnect_time != 0) {
+			notify($ERRORS{'OK'}, 0, "minutes left until user is disconnected: $disconnect_time");
+
+			# Notify user at 10 minutes until disconnect
+			if ($disconnect_time == 10) {
+				$self->_notify_user_disconnect($disconnect_time);
+				insertloadlog($reservation_id, $computer_id, "inuseend10", "notifying user of disconnect");
+			}
+
+			# Sleep one minute and decrement disconnect time by a minute
+			sleep 60;
+			$disconnect_time--;
+
+			# Check if the user deleted the request
+			if (is_request_deleted($request_id)) {
+				# User deleted request, exit queitly
+				notify($ERRORS{'OK'}, 0, "user has deleted the request, quietly exiting");
+				exit;
+			}
+
+			# check for state change to image creation mode and exit quietly
+			if (is_request_imaging($request_id)) {
+				notify($ERRORS{'OK'}, 0, "request is now in image creation mode, quietly exiting");
+				exit;
+			}
+
+			# Perform some actions at 5 minutes until end of request
+			if ($disconnect_time == 5) {
+				# Check for connection
+				if (isconnected($computer_hostname, $computer_type, $reservation_remoteip, $image_os_name, $computer_ipaddress)) {
+					insertloadlog($reservation_id, $computer_id, "inuseend5", "notifying user of endtime");
+					$self->_notify_user_disconnect($disconnect_time);
+				}
+				else {
+					insertloadlog($reservation_id, $computer_id, "inuseend5", "user is not connected, notification skipped");
+					notify($ERRORS{'OK'}, 0, "user has disconnected from $computer_shortname, skipping additional notices");
+				}
+			}    # Close if disconnect time = 5
+
+			# Check to see if the end time was extended
+			my $new_request_end;
+			if ($new_request_end = get_request_end($request_id)) {
+				notify($ERRORS{'OK'}, 0, "request end value in database: $new_request_end");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to retrieve updated request end value from database");
+			}
+
+			# Convert the current and new end times to epoch seconds
+			my $new_request_end_epoch = convert_to_epoch_seconds($new_request_end);
+			my $request_end_epoch     = convert_to_epoch_seconds($request_end);
+
+			# Check if request end is later than the original (user extended time)
+			if ($new_request_end_epoch > $request_end_epoch) {
+				notify($ERRORS{'OK'}, 0, "user extended end time, returning request to inuse state");
+
+				# Put this request back into the inuse state
+				if ($is_parent_reservation && update_request_state($request_id, "inuse", "inuse")) {
+					notify($ERRORS{'OK'}, 0, "request state set back to inuse");
+				}
+				elsif (!$is_parent_reservation) {
+					notify($ERRORS{'OK'}, 0, "child reservation, request state NOT set back to inuse");
+				}
+				else {
+					notify($ERRORS{'WARNING'}, 0, "unable to set request state back to inuse");
+				}
+
+				notify($ERRORS{'OK'}, 0, "exiting");
+				exit;
+			} ## end if ($new_request_end_epoch > $request_end_epoch)
+
+		}    # Close while disconnect time is not 0
+
+		# If forimage flag is set - check for state change to image creation mode and exit quietly
+		# One last check - if forimaging lets sleep 1 min and check the state
+		if ($request_forimaging) {
+			sleep 60;
+			notify($ERRORS{'OK'}, 0, "request has forimaging flag enabled checking for image state");
+			if (is_request_imaging($request_id)) {
+				notify($ERRORS{'OK'}, 0, "request is now in image creation mode, quietly exiting");
+				exit;
+			}
+		}
+
+		# Insert an entry into the load log
+		insertloadlog($reservation_id, $computer_id, "timeout", "endtime reached moving to timeout");
+		notify($ERRORS{'OK'}, 0, "end time reached, setting request to timeout state");
+
+		# Put this request into the timeout state
+		if ($is_parent_reservation && update_request_state($request_id, "timeout", "inuse")) {
+			notify($ERRORS{'OK'}, 0, "request state set to timeout");
+		}
+		elsif (!$is_parent_reservation) {
+			notify($ERRORS{'OK'}, 0, "child reservation, request state NOT set back to timeout");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "unable to set request state to timout");
+		}
+
+		# Get the current computer state directly from the database
+		my $computer_state;
+		if ($computer_state = get_computer_current_state_name($computer_id)) {
+			notify($ERRORS{'OK'}, 0, "computer $computer_id state retrieved from database: $computer_state");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "unable to retrieve computer $computer_id state from database");
+		}
+
+		# Check if computer is in maintenance state
+		if ($computer_state =~ /maintenance/) {
+			notify($ERRORS{'OK'}, 0, "computer $computer_shortname in maintenance state, skipping computer state update");
+		}
+		else {
+			notify($ERRORS{'OK'}, 0, "computer not in maintenance, setting computer to timeout state");
+			# Computer is not in maintenance state, set its state to timeout
+			if (update_computer_state($computer_id, "timeout")) {
+				notify($ERRORS{'OK'}, 0, "computer $computer_id set to timeout state");
+			}
+			else {
+				notify($ERRORS{'WARNING'}, 0, "unable to set computer $computer_id to the timeout state");
+			}
+		} ## end else [ if ($computer_state =~ /maintenance/)
+
+		# Notify user about ending request
+		$self->_notify_user_request_ended();
+
+		# Update the entry in the log table with the current finalend time and ending set to timeout
+		if ($is_parent_reservation && update_log_ending($request_logid, "EOR")) {
+			notify($ERRORS{'OK'}, 0, "log id $request_logid finalend was updated to now and ending set to EOR");
+		}
+		elsif (!$is_parent_reservation) {
+			notify($ERRORS{'OK'}, 0, "child reservation, log id $request_logid finalend was NOT updated");
+		}
+		else {
+			notify($ERRORS{'WARNING'}, 0, "log id $request_logid finalend could not be updated to now and ending set to EOR");
+		}
+
+		notify($ERRORS{'OK'}, 0, "exiting");
+		exit;
+
+	}    # Close if request checktime is end
+
+	# Not poll or end
+	else {
+		notify($ERRORS{'OK'}, 0, "returning \'$request_checktime\', exiting");
+		exit;
+	}
+
+	notify($ERRORS{'OK'}, 0, "exiting");
+	exit;
+} ## end sub process
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _notify_user_endtime
+
+ Parameters  : $request_data_hash_reference, $notice_interval
+ Returns     : 1 if successful, 0 otherwise
+ Description : Notifies the user how long they have until the end of the
+               request. Based on the user configuration, an e-mail message,
+               IM message, or wall message may be sent.
+               A notice interval string must be passed. Its value should be
+               something like "5 minutes".
+
+=cut
+
+sub _notify_user_endtime {
+	my $self            = shift;
+	my $notice_interval = shift;
+
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	my $request_data          = $self->data->get_request_data;
+	my $is_parent_reservation = $self->data->is_parent_reservation();
+
+	# Check to make sure notice interval is set
+	if (!defined($notice_interval)) {
+		notify($ERRORS{'WARNING'}, 0, "end time message not set, notice interval was not passed");
+		return 0;
+	}
+
+	# Store hash variables into local variables
+	my $request_id                 = $request_data->{id};
+	my $reservation_id             = $request_data->{RESERVATIONID};
+	my $user_preferredname         = $request_data->{user}{preferredname};
+	my $user_email                 = $request_data->{user}{email};
+	my $user_emailnotices          = $request_data->{user}{emailnotices};
+	my $user_im_name               = $request_data->{user}{IMtype}{name};
+	my $user_im_id                 = $request_data->{user}{IMid};
+	my $user_unityid               = $request_data->{user}{unityid};
+	my $affiliation_sitewwwaddress = $request_data->{user}{affiliation}{sitewwwaddress};
+	my $affiliation_helpaddress    = $request_data->{user}{affiliation}{helpaddress};
+	my $image_prettyname           = $request_data->{reservation}{$reservation_id}{image}{prettyname};
+	my $image_os_name              = $request_data->{reservation}{$reservation_id}{image}{OS}{name};
+	my $computer_ipaddress         = $request_data->{reservation}{$reservation_id}{computer}{IPaddress};
+	my $computer_type              = $request_data->{reservation}{$reservation_id}{computer}{type};
+	my $computer_shortname         = $request_data->{reservation}{$reservation_id}{computer}{SHORTNAME};
+
+	my $message = <<"EOF";
+$user_preferredname,
+You have $notice_interval until the end of your reservation for image $image_prettyname.
+
+Reservation extensions are available if the machine you are on does not have a reservation immediately following.
+
+To edit this reservation:
+-Visit $affiliation_sitewwwaddress
+-Select Current Reservations
+
+Thank You,
+VCL Team
+EOF
+
+	my $subject = "VCL -- $notice_interval until end of reservation";
+
+	# Send mail
+	if ($is_parent_reservation && $user_emailnotices) {
+		mail($user_email, $subject, $message, $affiliation_helpaddress);
+	}
+
+	# Send IM
+	if ($is_parent_reservation && $user_im_name ne "none") {
+		notify_via_IM($user_im_name, $user_im_id, $message);
+	}
+
+	return 1;
+} ## end sub _notify_user_endtime
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _notify_user_disconnect
+
+ Parameters  : $request_data_hash_reference, $disconnect_time
+ Returns     : 1 if successful, 0 otherwise
+ Description : Notifies the user that the session will be disconnected soon.
+               Based on the user configuration, an e-mail message, IM message,
+               Windows msg, or Linux wall message may be sent.
+               A scalar containing the number of minutes until the user is
+               disconnected must be passed as the 2nd parameter.
+
+=cut
+
+sub _notify_user_disconnect {
+	my $self            = shift;
+	my $disconnect_time = shift;
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	my $request_data          = $self->data->get_request_data;
+	my $is_parent_reservation = $self->data->is_parent_reservation();
+
+	# Check to make sure disconnect time was passed
+	if (!defined($disconnect_time)) {
+		notify($ERRORS{'WARNING'}, 0, "disconnect time message not set, disconnect time was not passed");
+		return 0;
+	}
+
+	# Store hash variables into local variables
+	my $request_id                 = $request_data->{id};
+	my $reservation_id             = $request_data->{RESERVATIONID};
+	my $user_preferredname         = $request_data->{user}{preferredname};
+	my $user_email                 = $request_data->{user}{email};
+	my $user_emailnotices          = $request_data->{user}{emailnotices};
+	my $user_im_name               = $request_data->{user}{IMtype}{name};
+	my $user_im_id                 = $request_data->{user}{IMid};
+	my $user_unityid               = $request_data->{user}{unityid};
+	my $affiliation_sitewwwaddress = $request_data->{user}{affiliation}{sitewwwaddress};
+	my $affiliation_helpaddress    = $request_data->{user}{affiliation}{helpaddress};
+	my $image_prettyname           = $request_data->{reservation}{$reservation_id}{image}{prettyname};
+	my $image_os_name              = $request_data->{reservation}{$reservation_id}{image}{OS}{name};
+	my $computer_ipaddress         = $request_data->{reservation}{$reservation_id}{computer}{IPaddress};
+	my $computer_type              = $request_data->{reservation}{$reservation_id}{computer}{type};
+	my $computer_shortname         = $request_data->{reservation}{$reservation_id}{computer}{SHORTNAME};
+
+	my $disconnect_string;
+	if ($disconnect_time == 0) {
+		$disconnect_string = "0 minutes";
+	}
+	elsif ($disconnect_time == 1) {
+		$disconnect_string = "1 minute";
+	}
+	else {
+		$disconnect_string = "$disconnect_time minutes";
+	}
+
+	my $message = <<"EOF";
+$user_preferredname,
+You have $disconnect_string until the end of your reservation for image $image_prettyname, please save all work and prepare to exit.
+
+Reservation extensions are available if the machine you are on does not have a reservation immediately following.
+
+Visit $affiliation_sitewwwaddress and select Current Reservations to edit this reservation.
+
+Thank you,
+VCL Team
+EOF
+
+	my $short_message = "$user_preferredname, You have $disconnect_string until the end of your reservation. Please save all work and prepare to log off.";
+
+	my $subject = "VCL -- $disconnect_string until end of reservation";
+
+	# Send mail
+	if ($is_parent_reservation && $user_emailnotices) {
+		mail($user_email, $subject, $message, $affiliation_helpaddress);
+	}
+
+	# Send IM
+	if ($is_parent_reservation && $user_im_name ne "none") {
+		notify_via_IM($user_im_name, $user_im_id, $message);
+	}
+
+	# Send message to machine
+	if ($computer_type =~ /blade|virtualmachine/) {
+		if ($image_os_name =~ /^(win|vmwarewin)/) {
+			# Notify via windows msg cmd
+			notify_via_msg($computer_shortname, $user_unityid, $short_message);
+		}
+		elsif ($image_os_name =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9])/) {
+			# Notify via wall
+			notify_via_wall($computer_shortname, $user_unityid, $short_message, $image_os_name, $computer_type);
+		}
+	} ## end if ($computer_type =~ /blade|virtualmachine/)
+	elsif ($computer_type eq "lab") {
+		# Notify via wall
+		notify_via_wall($computer_ipaddress, $user_unityid, $short_message, $image_os_name, $computer_type);
+	}
+
+	return 1;
+} ## end sub _notify_user_disconnect
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _notify_user_timeout
+
+ Parameters  : $request_data_hash_reference
+ Returns     : 1 if successful, 0 otherwise
+ Description : Notifies the user that the session has timed out.
+               Based on the user configuration, an e-mail message, IM message,
+               Windows msg, or Linux wall message may be sent.
+
+=cut
+
+sub _notify_user_timeout {
+	my $self = shift;
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	my $request_data          = $self->data->get_request_data;
+	my $is_parent_reservation = $self->data->is_parent_reservation();
+
+	# Store some hash variables into local variables
+	my $reservation_id             = $request_data->{RESERVATIONID};
+	my $user_preferredname         = $request_data->{user}{preferredname};
+	my $user_email                 = $request_data->{user}{email};
+	my $user_emailnotices          = $request_data->{user}{emailnotices};
+	my $user_im_name               = $request_data->{user}{IMtype}{name};
+	my $user_im_id                 = $request_data->{user}{IMid};
+	my $affiliation_sitewwwaddress = $request_data->{user}{affiliation}{sitewwwaddress};
+	my $affiliation_helpaddress    = $request_data->{user}{affiliation}{helpaddress};
+	my $image_prettyname           = $request_data->{reservation}{$reservation_id}{image}{prettyname};
+	my $computer_ipaddress         = $request_data->{reservation}{$reservation_id}{computer}{IPaddress};
+
+	my $message = <<"EOF";
+$user_preferredname,
+Your reservation has timed out due to inactivity for image $image_prettyname at address $computer_ipaddress.
+
+To make another reservation, please revisit:
+$affiliation_sitewwwaddress
+
+Thank you
+VCL Team
+EOF
+
+	my $subject = "VCL -- reservation timeout";
+
+	# Send mail
+	if ($is_parent_reservation && $user_emailnotices) {
+		mail($user_email, $subject, $message, $affiliation_helpaddress);
+	}
+
+	# Send IM
+	if ($is_parent_reservation && $user_im_name ne "none") {
+		notify_via_IM($user_im_name, $user_im_id, $message);
+	}
+
+	return 1;
+} ## end sub _notify_user_timeout
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 _notify_user_request_ended
+
+ Parameters  : $request_data_hash_reference
+ Returns     : 1 if successful, 0 otherwise
+ Description : Notifies the user that the session has ended.
+               Based on the user configuration, an e-mail message, IM message,
+               Windows msg, or Linux wall message may be sent.
+
+=cut
+
+sub _notify_user_request_ended {
+	my $self = shift;
+	my ($package, $filename, $line, $sub) = caller(0);
+
+	my $request_data          = $self->data->get_request_data;
+	my $is_parent_reservation = $self->data->is_parent_reservation();
+
+	# Store some hash variables into local variables
+	my $reservation_id             = $request_data->{RESERVATIONID};
+	my $user_preferredname         = $request_data->{user}{preferredname};
+	my $user_email                 = $request_data->{user}{email};
+	my $user_emailnotices          = $request_data->{user}{emailnotices};
+	my $user_im_name               = $request_data->{user}{IMtype}{name};
+	my $user_im_id                 = $request_data->{user}{IMid};
+	my $affiliation_helpaddress    = $request_data->{user}{affiliation}{helpaddress};
+	my $affiliation_sitewwwaddress = $request_data->{user}{affiliation}{sitewwwaddress};
+	my $image_prettyname           = $request_data->{reservation}{$reservation_id}{image}{prettyname};
+
+	my $subject = "VCL -- End of reservation";
+
+	my $message = <<"EOF";
+$user_preferredname,
+Your reservation of $image_prettyname has ended. Thank you for using $affiliation_sitewwwaddress.
+
+Regards,
+VCL Team
+EOF
+
+	# Send mail
+	if ($is_parent_reservation && $user_emailnotices) {
+		mail($user_email, $subject, $message, $affiliation_helpaddress);
+	}
+
+	# Send IM
+	if ($is_parent_reservation && $user_im_name ne "none") {
+		notify_via_IM($user_im_name, $user_im_id, $message);
+	}
+
+	return 1;
+} ## end sub _notify_user_request_ended
+#/////////////////////////////////////////////////////////////////////////////
+
+1;
+__END__
+
+=head1 BUGS and LIMITATIONS
+
+ There are no known bugs in this module.
+ Please report problems to the VCL team (vcl_help@ncsu.edu).
+
+=head1 AUTHOR
+
+ Aaron Peeler, aaron_peeler@ncsu.edu
+ Andy Kurth, andy_kurth@ncsu.edu
+
+=head1 SEE ALSO
+
+L<http://vcl.ncsu.edu>
+
+
+=cut