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