blob: 694335bf4039f1ee4d3347c6c561b51487e92413 [file]
#!/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: utils.pm 1953 2008-12-12 14:23:17Z arkurth $
##############################################################################
=head1 NAME
VCL::utils
=head1 SYNOPSIS
use VCL::utils;
=head1 DESCRIPTION
This module contains general VCL utility subroutines.
=cut
##############################################################################
package VCL::utils;
# 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 Mail::Mailer;
use Shell qw(mkdir);
use File::Find;
use Time::Local;
use DBI;
use DBI::Const::GetInfoType;
use diagnostics;
use Net::Ping;
use Fcntl qw(:DEFAULT :flock);
use FindBin;
use Getopt::Long;
use Carp;
use Text::Wrap;
use English;
use List::Util qw(min max);
#use Date::Calc qw(Delta_DHMS Time_to_Date Date_to_Time);
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
_checknstartservice
_getcurrentimage
_is_user_added
_killsysprep
_machine_os
_pingnode
_set_sshd_startmode
_sshd_status
add_user
add_users_by_group
changelinuxpassword
changewindowspasswd
check_blockrequest_time
check_connection
check_endtimenotice_interval
check_ssh
check_time
check_uptime
checkonprocess
clearfromblockrequest
collectsshkeys
construct_image_name
controlVM
convert_to_datetime
convert_to_epoch_seconds
database_execute
database_select
del_user
delete_computerloadlog_reservation
delete_request
disablesshd
doesimageexists
enablesshd
firewall_compare_update
format_data
get_computer_current_state_name
get_highest_imagerevision_info
get_image_info
get_imagemeta_info
get_imagerevision_info
get_ip_address_from_hosts
get_management_node_blockrequests
get_management_node_id
get_management_node_info
get_management_node_requests
get_management_predictive_info
get_next_image_default
get_production_imagerevision_info
get_request_by_computerid
get_request_end
get_request_info
get_reservation_remote_ip
get_vmhost_info
getanothermachine
getdynamicaddress
getimagesize
getnewdbh
getpw
getusergroupmembers
hostname
insert_reload_request
insert_request
insertloadlog
is_inblockrequest
is_request_deleted
is_request_imaging
isconnected
isfilelocked
kill_reservation_process
known_hosts
lockfile
mail
makedatestring
monitorloading
nmap_port
notify
notify_via_IM
notify_via_msg
notify_via_wall
preplogfile
remotedesktopport
rename_vcld_process
reservation_being_processed
reservations_ready
restoresshkeys
round
run_scp_command
run_ssh_command
set_hash_process_id
set_logfile_path
setimageid
setpreferredimage
setstaticaddress
string_to_ascii
switch_state
switch_vmhost_id
system_monitoring
time_exceeded
timefloor15interval
unlockfile
update_blockrequest_processing
update_cluster_info
update_computer_address
update_computer_state
update_currentimage
update_image_name
update_lastcheckin
update_log_ending
update_log_loaded_time
update_preload_flag
update_request_password
update_request_state
update_reservation_lastcheck
update_sublog_ipaddress
virtual_status_unix
virtual_status_vm
windowsroutetable
write_currentimage_txt
$CONF_FILE_PATH
$DATABASE
$DEFAULTHELPEMAIL
$DEFAULTURL
$ETHDEVICE
$FQDN
$IDENTITY_bladerhel
$IDENTITY_wxp
$IDENTITY_linux_lab
$IDENTITY_solaris_lab
$IPCONFIGURATION
$jabPass
$jabPort
$jabResource
$jabServer
$jabUser
$LINUX_IMAGE
$LINUX_IMAGEREPOSITORY
$LOGFILE
$MYSQL_SSL
$MYSQL_SSL_CERT
$PIDFILE
$PROCESSNAME
$WINDOWS_ROOT_PASSWORD
$SERVER
$SYSADMIN
$SYSPREP
$SYSPREP_2003
$TESTING
$THROTTLE
$TOOLS
$VERBOSE
$VMWAREREPOSITORY
$WRTPASS
$WRTUSER
%ERRORS
%OPTIONS
$IMAGELIBENABLE
$IMAGELIBUSER
$IMAGELIBKEY
$IMAGESERVERS
$TOOLS
$VMWAREREPOSITORY
$SYSPREP_2003
$SYSPREP
$SYSPREP_VMWARE
$SYSPREP_VMWARE2003
$VERBOSE
);
#our %ERRORS=('DEPENDENT'=>4,'UNKNOWN'=>3,'OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'MAILMASTERS'=>5);
BEGIN {
#parse config file and set globals
our ($JABBER, $jabServer, $jabUser, $jabPass, $jabResource, $jabPort) = 0;
our ($LOGFILE, $PIDFILE, $PROCESSNAME) = 0;
our ($DATABASE, $SERVER, $WRTUSER, $WRTPASS, $LockerRdUser, $rdPass) = 0;
our ($SYSADMIN, $SHARED_MAILBOX, $DEFAULTURL, $DEFAULTHELPEMAIL) = 0;
our ($XCATROOT) = 0;
our ($FQDN) = 0;
our ($MYSQL_SSL, $MYSQL_SSL_CERT);
our ($IPCONFIGURATION, $DNSserver, $GATEWAY, $NETMASK, $ETHDEVICE) = 0;
our ($LINUX_IMAGE, $THROTTLE);
our ($CORE_IMAGEREPOSITORY, $WIN_IMAGEREPOSITORY, $LINUX_IMAGEREPOSITORY);
our ($IDENTITY_linux_lab, $IDENTITY_solaris_lab, $IDENTITY_wxp, $IDENTITY_newwxp, $IDENTITY_bladerhel);
our ($IMAGELIBENABLE) = 0;
our ($IMAGESERVERS, $IMAGELIBUSER, $IMAGELIBKEY);
our ($VMWARETYPE, $VMWARE_DISK);
our ($WINDOWS_ROOT_PASSWORD);
# Set Getopt pass_through so this module doesn't erase parameters that other modules may use
Getopt::Long::Configure('pass_through');
# Set the VERBOSE flag to 0 by default
our ($VERBOSE) = 0;
# Set the TESTING flag to 0 by default
our ($TESTING) = 0;
# Use the default configuration file path if -conf isn't specified on the command line
our $BIN_PATH = $FindBin::Bin;
print STDOUT "BIN PATH: $BIN_PATH\n";
our ($CONF_FILE_PATH) = 'C:/vcldev.conf';
if (!-f $CONF_FILE_PATH) {
if ($BIN_PATH =~ /dev/) {
$CONF_FILE_PATH = "/etc/vcl/vcldev.conf";
}
else {
$CONF_FILE_PATH = "/etc/vcl/vcld.conf";
}
}
# Store the command line options in this hash
our %OPTIONS;
GetOptions(\%OPTIONS, 'verbose', 'testing', 'config=s', 'logfile=s');
# Get the command line parameters
$CONF_FILE_PATH = $OPTIONS{config} if (defined($OPTIONS{config} && $OPTIONS{config}));
print STDOUT "pre-execution: config file being used: $CONF_FILE_PATH\n";
if (open(CONF, $CONF_FILE_PATH)) {
my @conf = <CONF>;
close(CONF);
foreach my $l (@conf) {
# Remove all new line and carriage return characters from the end of the line
# Chomp doesn't always remove carriage returns
$l =~ s/[\r\n]*$//;
#logfile
if ($l =~ /^log=(.*)/ && (!defined($LOGFILE) || !($LOGFILE))) {
chomp($l);
$LOGFILE = $1;
}
#pidfile
if ($l =~ /^pidfile=(.*)/) {
chomp($l);
$PIDFILE = $1;
}
if ($l =~ /^DEFAULTURL=(.*)/) {
$DEFAULTURL = $1;
}
if ($l =~ /^DEFAULTHELPEMAIL=(.*)/) {
$DEFAULTHELPEMAIL = $1;
}
#FQDN - to many issues trying to figure out my FQDN so just tell me
if ($l =~ /^FQDN=([-.a-zA-Z0-9]*)/) {
$FQDN = $1;
}
#mysql settings
#name of db
if ($l =~ /^database=([a-zA-Z0-9]*)/) {
$DATABASE = $1;
}
#name of database server
if ($l =~ /^server=([-.a-zA-Z0-9]*)/) {
$SERVER = $1;
}
#write user name
if ($l =~ /^LockerWrtUser=([-a-zA-Z0-9]*)/) {
$WRTUSER = $1;
}
#write user password
#if($l =~ /^wrtPass=([-a-zA-Z0-9]*)/){
if ($l =~ /^wrtPass=(.*)/) {
$WRTPASS = $1;
}
#read user name
if ($l =~ /^LockerRdUser=([-a-zA-Z0-9]*)/) {
$LockerRdUser = $1;
}
#read user password
if ($l =~ /^rdPass=(.*)/) {
$rdPass = $1;
}
#is mysql ssl option enabled
if ($l =~ /^enable_mysql_ssl=(yes)/) {
$MYSQL_SSL = 1;
}
elsif ($l =~ /^enable_mysql_ssl=(no)/) {
$MYSQL_SSL = 0;
}
#collect path to cert -- only valid if $MYSQL_SSL is true
if ($l =~ /^mysql_ssl_cert=(.*)/) {
$MYSQL_SSL_CERT = $1;
}
#ipconfiguration
if ($l =~ /^ipconfiguration=(static|manualDHCP|dynamicDHCP)/) {
$IPCONFIGURATION = $1;
}
if ($l =~ /^DNSserver=([,.0-9]*)/) {
$DNSserver = $1;
}
if ($l =~ /^GATEWAY=([.0-9]*)/) {
$GATEWAY = $1;
}
if ($l =~ /^NETMASK=([.0-9]*)/) {
$NETMASK = $1;
}
if ($l =~ /^ETHDEVICE=(eth[0-9])/) {
$ETHDEVICE = $1;
}
#Sysadmin list
if ($l =~ /^sysadmin=([,.\@a-zA-Z0-9]*)/) {
$SYSADMIN = $1;
}
#sharedmailbox
if ($l =~ /^sharedmailbox=([,-.\@a-zA-Z0-9]*)/) {
$SHARED_MAILBOX = $1;
}
#jabber - stuff
if ($l =~ /^jabber=(yes)/) {
$JABBER = 1;
}
if ($l =~ /^jabber=(no)/) {
$JABBER = 0;
}
#collect remaining pieces of the jabber settings
#$jabServer,$jabUser,$jabPass,$jabResource,$jabPort
if ($l =~ /^jabServer=([.a-zA-Z0-9]*)/) {
$jabServer = $1;
}
if ($l =~ /^jabPort=([0-9]*)/) {
$jabPort = $1;
}
if ($l =~ /^jabUser=([.a-zA-Z0-9]*)/) {
$jabUser = $1;
}
if ($l =~ /^jabPass=([a-zA-Z0-9]*)/) {
$jabPass = $1;
}
if ($l =~ /^jabResource=([a-zA-Z0-9]*)/) {
$jabResource = $1;
}
#process name
if ($l =~ /^processname=([-_a-zA-Z0-9]*)/) {
$PROCESSNAME = $1;
}
#xcat linux image path
# linux kernal 2.4 - we had to modify xcat to load from seperate install tree.
if ($l =~ /^LINUXIMAGEid=(image|linux_image)/) {
$LINUX_IMAGE = $1;
}
#Linux_imagerepository
if ($l =~ /^LINUX_IMAGEREPOSITORY=([\/a-zA-Z0-9]*)/) {
$LINUX_IMAGEREPOSITORY = $1;
}
#throttle
if ($l =~ /^THROTTLE=([0-9]*)/) {
$THROTTLE = $1;
}
#ssh private keys
if ($l =~ /^IDENTITY_blade_linux=(.*)/) {
$IDENTITY_bladerhel = $1;
}
if ($l =~ /^IDENTITY_blade_win=(.*)/) {
$IDENTITY_wxp = $1;
}
if ($l =~ /^IDENTITY_solaris_lab=(.*)/) {
$IDENTITY_solaris_lab = $1;
}
if ($l =~ /^IDENTITY_linux_lab=(.*)/) {
$IDENTITY_linux_lab = $1;
}
#image library share - sync images across multiple management nodes
# $IMAGELIBENABLE,$IMAGESERVERS,$IMAGELIBUSER,$IMAGELIBKEY
if ($l =~ /^IMAGELIBENABLE=(yes)/) {
$IMAGELIBENABLE = 1;
}
elsif ($l =~ /^IMAGELIBENABLE=(no)/) {
$IMAGELIBENABLE = 0;
}
if ($l =~ /^imageservers=(.*)/) {
$IMAGESERVERS = $1;
}
if ($l =~ /^imagelibuser=([a-z0-9]*)/) {
$IMAGELIBUSER = $1;
}
if ($l =~ /^imagelibuser=([-a-zA-Z0-9]*)/) {
$IMAGELIBUSER = $1;
}
if ($l =~ /^imagelibidkey=(.*)/) {
$IMAGELIBKEY = $1;
}
#vmware settings
# localdisk
if ($l =~ /^VMWARE_DISK=(localdisk|networkdisk)/) {
$VMWARE_DISK = $1;
}
if ($l =~ /^windows_root_password=(.*)/i) {
$WINDOWS_ROOT_PASSWORD = $1;
}
if ($l =~ /^verbose=(.*)/i) {
$VERBOSE = $1;
}
if ($l =~ /^test=(.*)/i) {
$TESTING = $1;
}
} # Close foreach line in conf file
} # Close open conf file
else {
die "VCLD : $CONF_FILE_PATH does not exist, exiting -- $! \n";
}
if (!$PROCESSNAME) {
$PROCESSNAME = "vcld";
}
if (!($LOGFILE) && $LOGFILE ne '0') {
#set default
$LOGFILE = "/var/log/$PROCESSNAME.log";
}
if (!$THROTTLE) {
$THROTTLE = 0;
}
if (!$IDENTITY_bladerhel) {
}
if (!$IDENTITY_wxp) {
}
if (!$IDENTITY_solaris_lab) {
}
if (!$IDENTITY_linux_lab) {
}
if (!$WINDOWS_ROOT_PASSWORD) {
$WINDOWS_ROOT_PASSWORD = "clOudy";
}
if (!($FQDN)) {
print STDOUT "FQDN is not listed\n";
}
if (!($PIDFILE)) {
#set default
$PIDFILE = "/var/run/$PROCESSNAME.pid";
}
if (!$IPCONFIGURATION) {
#default
$IPCONFIGURATION = "manualDHCP";
}
elsif ($IPCONFIGURATION eq "static") {
#check for dependiencies
if (!$DNSserver) {
print STDOUT "pre-execution: ipconfiguration is $IPCONFIGURATION dnsserver setting is missing in configuration file\n";
}
if (!$GATEWAY) {
print STDOUT "pre-execution: ipconfiguration is $IPCONFIGURATION gateway setting is missing in configuration file\n";
}
if (!$NETMASK) {
print STDOUT "pre-execution: ipconfiguration is $IPCONFIGURATION netmask setting is missing in configuration file\n";
}
} ## end elsif ($IPCONFIGURATION eq "static") [ if (!$IPCONFIGURATION)
if (!$LINUX_IMAGE) {
$LINUX_IMAGE = "image";
}
if ($JABBER) {
#jabber is enabled - import required jabber module
# todo - check if Jabber module is installed
# i.e. perl -MNet::Jabber -e1
# check version -- perl -MNet::Jabber -e'print $Net::Jabber::VERSION\n";'
require "Net/Jabber.pm";
import Net::Jabber qw(client);
}
# Get the remaining command line parameters
$VERBOSE = $OPTIONS{verbose} if (defined($OPTIONS{verbose} && $OPTIONS{verbose}));
$TESTING = $OPTIONS{testing} if (defined($OPTIONS{testing} && $OPTIONS{testing}));
$LOGFILE = $OPTIONS{logfile} if (defined($OPTIONS{logfile} && $OPTIONS{logfile}));
print STDOUT "pre-execution: process name is set to: $PROCESSNAME\n";
print STDOUT "pre-execution: verbose mode is set to: $VERBOSE\n";
print STDOUT "pre-execution: testing mode is set to: $TESTING\n";
print STDOUT "pre-execution: log file being used: $LOGFILE\n";
print STDOUT "pre-execution: PID file being used: $PIDFILE\n";
} ## end BEGIN
#use Net::Jabber qw(Client);
our ($JABBER, $PROCESSNAME);
our %ERRORS = ('DEPENDENT' => 4, 'UNKNOWN' => 3, 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'MAILMASTERS' => 5, 'DEBUG' => 6);
our ($LockerWrtUser, $wrtPass, $database, $server);
our ($jabServer, $jabUser, $jabPass, $jabResource, $jabPort);
our ($vcldquerykey, $SYSADMIN, $SHARED_MAILBOX, $DEFAULTURL, $DEFAULTHELPEMAIL);
our ($LOGFILE, $PIDFILE, $VCLDRPCQUERYKEY);
our ($SERVER, $DATABASE, $WRTUSER, $WRTPASS);
our ($MYSQL_SSL, $MYSQL_SSL_CERT);
our ($IPCONFIGURATION, $DNSserver, $GATEWAY, $NETMASK, $ETHDEVICE);
our ($LINUX_IMAGE, $THROTTLE);
our ($FQDN);
our ($IDENTITY_linux_lab, $IDENTITY_solaris_lab, $IDENTITY_wxp, $IDENTITY_bladerhel);
our ($IMAGELIBENABLE, $IMAGESERVERS, $IMAGELIBUSER, $IMAGELIBKEY);
our ($VMWARE_DISK);
our $IDENTITY_newwxp = "$FindBin::Bin/../lib/VCL/newwinxp_blade.key";
our $XCATROOT = "/opt/xcat";
our $TOOLS = "$FindBin::Bin/../tools";
our $VMWAREREPOSITORY = "/install/vmware_images";
our $SYSPREP_2003 = "$TOOLS/Sysprep_2003";
our $SYSPREP = "$TOOLS/Sysprep";
our $SYSPREP_VMWARE = "$TOOLS/Sysprep_vmware";
our $SYSPREP_VMWARE2003 = "$TOOLS/Sysprep_vmware2003";
our $VERBOSE;
our $TESTING;
our $CONF_FILE_PATH;
our $WINDOWS_ROOT_PASSWORD;
sub makedatestring;
#/////////////////////////////////////////////////////////////////////////////
=head2 preplogfile
Parameters : nothing
Returns : nothing
Description : writes header to global log file
=cut
sub preplogfile {
my $currenttime = makedatestring();
my ($package, $filename, $line, $sub) = caller(0);
$filename =~ s(^.*/)(); #remove leading path from filename
# print initial info to log file
print STDERR "===========================================================\n";
print STDERR "OUTPUT for $filename run on $currenttime\n";
print STDERR "===========================================================\n";
}
#/////////////////////////////////////////////////////////////////////////////
=head2 notify
Parameters : $error, $LOG, $string, $data
Returns : nothing
Description : based on error value write string and/or data to
provide or default log file
=cut
sub notify {
my $error = shift;
my $LOG = shift;
my $string = shift;
my @data = @_;
# Just return if DEBUG and verbose isn't enabled
return if ($error == 6 && !$VERBOSE);
# Get the current time
my $currenttime = makedatestring();
# Redirect STDOUT and STDERR to the log file
$LOG = $LOGFILE if (!$LOG);
open(STDOUT, ">>$LOG") if $LOG;
open(STDERR, ">>$LOG") if $LOG;
# Get info about the subroutine which called this subroutine
my ($package, $filename, $line, $sub) = caller(0);
# Remove leading path from filename
$filename =~ s/.*\///;
# Remove the leading package path from the sub name (VC::...)
$sub =~ s/.*:://;
# Assemble the caller information
my $caller_info;
if (caller(1)) {
my ($caller_previous_package, $caller_previous_filename, $caller_previous_line, $caller_previous_sub) = caller(1);
$caller_previous_filename =~ s/.*\///;
$caller_previous_sub =~ s/.*:://;
$caller_info = "$filename:$caller_previous_sub($line)";
}
else {
$caller_info = "$filename:$sub($line)";
}
# Get the caller trace information
my $caller_trace = get_caller_trace(6);
# Format the message string
# Remove Windows carriage returns from the message string for consistency
$string =~ s/\r//g;
# Remove newlines from the beginning and end of the message string
$string =~ s/^\n+//;
$string =~ s/\n+$//;
# Remove any spaces from the beginning or end of the string
$string =~ s/^\s+//;
$string =~ s/\s+$//;
# Replace consecutive spaces with a single space to keep log file concise as long as string doesn't contain a quote
if ($string !~ /[\'\"]/gs) {
$string =~ s/[ \t]+/ /gs;
}
# Assemble the process identifier string
my $process_identifier = $PID;
$process_identifier .= "|$ENV{request_id}:$ENV{reservation_id}" if (defined $ENV{request_id} && defined $ENV{reservation_id});
$process_identifier .= "|$ENV{state}" if (defined $ENV{state});
# Assemble the log message
my $log_message = "$currenttime|$process_identifier|$caller_info|$string";
# Format the data if WARNING or CRITICAL, and @data was passed
my $formatted_data;
if (@data && ($error == 1 || $error == 2)) {
# Add the data to the message body if it was passed
$formatted_data = "DATA:\n" . format_data(\@data, 'DATA');
chomp $formatted_data;
}
# Assemble an email message body if CRITICAL or MAILMASTERS
my $body;
if ($error == 2 || ($error == 5 && $SHARED_MAILBOX)) {
# Get the previous several log file entries for this process
my $log_history_count = 100;
my $log_history = "RECENT LOG ENTRIES FOR THIS PROCESS:\n";
$log_history .= `grep "|$PID|" $LOG | tail -n $log_history_count`;
chomp $log_history;
# Assemble the e-mail message body
$body = <<"END";
$string
Time: $currenttime
PID: $PID
Caller: $caller_info
$caller_trace
$log_history
END
# Add the formatted data to the message body if data was passed
$body .= "\n\n$formatted_data\n" if $formatted_data;
} ## end if ($error == 2 || ($error == 5 && $SHARED_MAILBOX...
# OK, VERBOSE
if (!$error || ($error == 6 && $VERBOSE)) {
}
# WARNING
if ($error == 1) {
$log_message = "\n---- WARNING ---- \n$log_message\n$caller_trace\n\n";
}
# CRITICAL
elsif ($error == 2) {
$log_message = "\n---- CRITICAL ---- \n$log_message\n$caller_trace\n";
$log_message .= "$formatted_data\n" if $formatted_data;
$log_message .= "\n";
my $from = "root\@$FQDN";
my $to = $SYSADMIN;
my $subject = "PROBLEM -- $filename";
mail($to, $subject, $body, $from);
} ## end elsif ($error == 2) [ if ($error == 1)
# MAILMASTERS - only for email notifications
elsif ($error == 5 && $SHARED_MAILBOX) {
my $to = $SHARED_MAILBOX;
my $from = "root\@$FQDN";
my $subject = "Informational -- $filename";
mail($to, $subject, $body, $from);
}
# Add the process identifier to every line of the log message
chomp $log_message;
$log_message =~ s/\n([^\n])/\n|$process_identifier| $1/g;
# Print the log message to the log file
print STDOUT "$log_message\n";
} ## end sub notify
#/////////////////////////////////////////////////////////////////////////////
=head2 makedatestring
Parameters : empty
Returns : current time in date_time format
Description :
=cut
sub makedatestring {
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
$year += 1900;
$mon++;
my $datestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);
return $datestring;
}
#/////////////////////////////////////////////////////////////////////////////
=head2 convert_to_datetime
Parameters : time in epoch format
Returns : date in datetime format
Description : accepts time in epoch format (10 digit) and
returns time in datetime format
=cut
sub convert_to_datetime {
my ($epochtime) = shift;
if (!defined($epochtime) || $epochtime == 0) {
$epochtime = time();
}
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($epochtime);
$year += 1900;
$mon++;
my $datestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);
return $datestring;
} ## end sub convert_to_datetime
#/////////////////////////////////////////////////////////////////////////////
=head2 convert_to_epoch_seconds
Parameters : datetime
Returns : time in epoch format
Description : takes input(optional) and returns epoch 10 digit string of
the supplied date_time or the current time
=cut
sub convert_to_epoch_seconds {
my ($date_time) = shift;
if (!defined($date_time)) {
return time();
}
#somehow we got a null timestamp, set it to current time
if ($date_time =~ /0000-00-00 00:00:00/) {
$date_time = makedatestring;
}
#format received: year-mon-mday hr:min:sec
my ($vardate, $vartime) = split(/ /, $date_time);
my ($yr, $mon, $mday) = split(/-/, $vardate);
my ($hr, $min, $sec) = split(/:/, $vartime);
$mon = $mon - 1; #time uses 0-11 for months :(
my $epoch_time = timelocal($sec, $min, $hr, $mday, $mon, $yr);
return $epoch_time;
} ## end sub convert_to_epoch_seconds
#/////////////////////////////////////////////////////////////////////////////
=head2 check_endtimenotice_interval
Parameters : endtime
Returns : scalar: 2week, 1week, 2day, 1day, 30min, or 0
Description : used to send a notice to owner regarding how far out the end of
their reservation is
=cut
sub check_endtimenotice_interval {
my $end = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "endtime not set") if (!defined($end));
my $now = time();
my $epochend = convert_to_epoch_seconds($end);
#flag on: 2 & 1 week; 2,1 day, 1 hour, 30,15,10,5 minutes
#2 week: between 14 days and a 14 day -15 minutes window
if ($epochend <= (14 * 60 * 60 * 24) && $epochend >= (14 * 60 * 60 * 24 - 15 * 60)) {
return (1, "2week");
}
#1 week: between 7 days and a 14 day -15 minute window
elsif ($epochend <= (7 * 60 * 60 * 24) && $epochend >= (7 * 60 * 60 * 24 - 15 * 60)) {
return (1, "1week");
}
#2 day: between 2 days and a 2 day -15 minute window
if ($epochend <= (2 * 60 * 60 * 24) && $epochend >= (2 * 60 * 60 * 24 - 15 * 60)) {
return (1, "2day");
}
#1 day: between 1 days and a 1 day -15 minute window
if ($epochend <= (1 * 60 * 60 * 24) && $epochend >= (1 * 60 * 60 * 24 - 15 * 60)) {
return (1, "1day");
}
#30-25 minutes
if ($epochend <= (30 * 60) && $epochend >= (25 * 60)) {
return (1, "30min");
}
} ## end sub check_endtimenotice_interval
#sub new_check_endtimenotice_interval {
# my ($request_end, $base_time) = @_;
# my ($package, $filename, $line, $sub) = caller(0);
#
# # Check the parameter
# if (!defined($request_end)) {
# notify($ERRORS{'WARNING'}, 0, "request end time was not specified"");
# return 0;
# }
# elsif (!$request_end) {
# notify($ERRORS{'WARNING'}, 0, "request end time was specified but is blank"");
# return 0;
# }
#
# # Convert the request end time to epoch seconds
# my $end_epoch_seconds = convert_to_epoch_seconds($request_end);
#
# # This is only used for testing
# my @now;
# if ($base_time) {
# my $base_epoch_seconds = convert_to_epoch_seconds($base_time);
# @now = Time_to_Date($base_epoch_seconds);
# }
# else {
# @now = Time_to_Date();
# }
#
# # Get arrays from the Date::Calc::Time_to_Date functions for now and the end time
# my @end = Time_to_Date($end_epoch_seconds);
#
# # Calculate the difference
# my ($days, $hours, $minutes, $seconds) = Delta_DHMS(@now, @end);
#
# # Return a value on: 2 & 1 week; 2,1 day, 1 hour, 30,15,10,5 minutes
# my $return_value = 0;
#
# # Ignore: over 14 days away
# if ($days >= 14){
# $return_value = 0;
# }
# # 2 week notice: between 14 days and a 14 day - 15 minute window
# elsif ($days >= 13 && $hours >= 23 && $minutes >= 45){
# $return_value = "2 weeks";
# }
# # Ignore: between 7 days and 14 day - 15 minute window
# elsif ($days >= 7) {
# $return_value = 0;
# }
# # 1 week notice: between 7 days and a 7 day -15 minute window
# elsif ($days >= 6 && $hours >= 23 && $minutes >= 45) {
# $return_value = "1 week";
# }
# # Ignore: between 2 days and 7 day - 15 minute window
# elsif ($days >= 2) {
# $return_value = 0;
# }
# # 2 day notice: between 2 days and a 2 day -15 minute window
# elsif($days >= 1 && $hours >= 23 && $minutes >= 45) {
# $return_value = "2 days";
# }
# # Ignore: between 1 days and 2 day - 15 minute window
# elsif ($days >= 1) {
# $return_value = 0;
# }
# # 1 day notice: between 1 days and a 1 day -15 minute window
# elsif($days >= 0 && $hours >= 23 && $minutes >= 45) {
# $return_value = "1 day";
# }
# #30-25 minutes
# elsif ($minutes >= 25 && $minutes <= 30) {
# $return_value = "30 minutes";
# }
# notify($ERRORS{'OK'}, 0, "days: time difference is days:$days hours:$hours minutes:$minutes, returning $return_value");
# return $return_value;
#}
#/////////////////////////////////////////////////////////////////////////////
=head2 check_blockrequest_time
Parameters : start, end, and expire times
Returns : 0 or 1 and task
Description : check current time against all three tasks
expire time overides end, end overrides start
=cut
sub check_blockrequest_time {
my ($start_datetime, $end_datetime, $expire_datetime) = @_;
# Check the arguments
if (!$start_datetime) {
notify($ERRORS{'WARNING'}, 0, "start time argument was not passed correctly");
return;
}
if (!$end_datetime) {
notify($ERRORS{'WARNING'}, 0, "end time argument was not passed correctly");
return;
}
if (!$expire_datetime) {
notify($ERRORS{'WARNING'}, 0, "expire time argument was not passed correctly");
return;
}
# Get the current time in epoch seconds
my $current_time_epoch_seconds = time();
my $expire_time_epoch_seconds = convert_to_epoch_seconds($expire_datetime);
my $expire_delta_minutes = int(($expire_time_epoch_seconds - $current_time_epoch_seconds) / 60);
#notify($ERRORS{'DEBUG'}, 0, "expire: $expire_datetime, epoch: $expire_time_epoch_seconds, delta: $expire_delta_minutes minutes");
# If expire time is in the past, remove it
if ($expire_delta_minutes < 0) {
# Block request has expired
notify($ERRORS{'OK'}, 0, "block request expired " . abs($expire_delta_minutes) . " minutes ago, returning 'expire'");
return "expire";
}
if ($start_datetime =~ /^-?\d*$/ || $end_datetime =~ /^-?\d*$/) {
notify($ERRORS{'DEBUG'}, 0, "block request is not expired but has no block times assigned to it, returning 0");
return 0;
}
# Convert the argument datetimes to epoch seconds for easy calculation
my $start_time_epoch_seconds = convert_to_epoch_seconds($start_datetime);
my $end_time_epoch_seconds = convert_to_epoch_seconds($end_datetime);
# Calculate # of seconds away start, end, and expire times are from now
# Positive value means time is in the future
my $start_delta_minutes = int(($start_time_epoch_seconds - $current_time_epoch_seconds) / 60);
my $end_delta_minutes = int(($end_time_epoch_seconds - $current_time_epoch_seconds) / 60);
#notify($ERRORS{'DEBUG'}, 0, "start: $start_datetime, epoch: $start_time_epoch_seconds, delta: $start_delta_minutes minutes");
#notify($ERRORS{'DEBUG'}, 0, "end: $end_datetime, epoch: $end_time_epoch_seconds, delta: $end_delta_minutes minutes");
# 4:00 to 4:15 hours in advance: start assigning resources
if ($start_delta_minutes >= (4 * 60) && $start_delta_minutes <= (4 * 60 + 10)) {
# Block request within start window
notify($ERRORS{'OK'}, 0, "block request start time is within start window ($start_delta_minutes minutes from now), returning 'start'");
return "start";
}
# 2:00 to 2:15 hours in advance: start assigning resources
if ($start_delta_minutes >= (2 * 60) && $start_delta_minutes <= (2 * 60 + 10)) {
# Block request within start window
notify($ERRORS{'OK'}, 0, "block request start time is within start window ($start_delta_minutes minutes from now), returning 'start'");
return "start";
}
# End time it is less than 1 minute
if ($end_delta_minutes < 0) {
# Block request end time is near
notify($ERRORS{'OK'}, 0, "block request end time has been reached ($end_delta_minutes minutes from now), returning 'end'");
return "end";
}
#notify($ERRORS{'DEBUG'}, 0, "block request does not need to be processed now, returning 0");
return 0;
} ## end sub check_blockrequest_time
#/////////////////////////////////////////////////////////////////////////////
=head2 check_time
Parameters : $request_start, $request_end, $reservation_lastcheck, $request_state_name, $request_laststate_name
Returns : start, preload, end, poll, old, remove, or 0
Description : based on the input return a value used by vcld
=cut
sub check_time {
my ($request_start, $request_end, $reservation_lastcheck, $request_state_name, $request_laststate_name) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the arguments
if (!defined($request_state_name)) {
notify($ERRORS{'WARNING'}, 0, "\$request_state_name argument is not defined");
return 0;
}
if (!defined($request_laststate_name)) {
notify($ERRORS{'WARNING'}, 0, "\$request_laststate_name argument is not defined");
return 0;
}
# If lastcheck isn't set, set it to now
if (!defined($reservation_lastcheck) || !$reservation_lastcheck) {
$reservation_lastcheck = makedatestring();
}
# First convert to datetime in case epoch seconds was passed
if ($reservation_lastcheck !~ /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}/) {
$reservation_lastcheck = convert_to_datetime($reservation_lastcheck);
}
if ($request_end !~ /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}/) {
$request_end = convert_to_datetime($request_end);
}
if ($request_start !~ /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}/) {
$request_start = convert_to_datetime($request_start);
}
# Convert times to epoch seconds
my $lastcheck_epoch_seconds = convert_to_epoch_seconds($reservation_lastcheck);
my $start_time_epoch_seconds = convert_to_epoch_seconds($request_start);
my $end_time_epoch_seconds = convert_to_epoch_seconds($request_end);
# Get the current time epoch seconds
my $current_time_epoch_seconds = time();
# Calculate time differences from now in seconds
# These will be positive if in the future, negative if in the past
my $lastcheck_diff_seconds = $lastcheck_epoch_seconds - $current_time_epoch_seconds;
my $start_diff_seconds = $start_time_epoch_seconds - $current_time_epoch_seconds;
my $end_diff_seconds = $end_time_epoch_seconds - $current_time_epoch_seconds;
# Calculate the time differences from now in minutes
# These will be positive if in the future, negative if in the past
my $lastcheck_diff_minutes = round($lastcheck_diff_seconds / 60);
my $start_diff_minutes = round($start_diff_seconds / 60);
my $end_diff_minutes = round($end_diff_seconds / 60);
# Print the time differences
#notify($ERRORS{'OK'}, 0, "reservation lastcheck difference: $lastcheck_diff_minutes minutes");
#notify($ERRORS{'OK'}, 0, "request start time difference: $start_diff_minutes minutes");
#notify($ERRORS{'OK'}, 0, "request end time difference: $end_diff_minutes minutes");
# Check the state, and then figure out the return code
if ($request_state_name =~ /new|imageprep|reload|tomaintenance|tovmhostinuse/) {
if ($start_diff_minutes > 0) {
# Start time is either now or in future, $start_diff_minutes is positive
if ($start_diff_minutes > 35) {
#notify($ERRORS{'DEBUG'}, 0, "reservation will start in more than 35 minutes ($start_diff_minutes)");
return "0";
}
elsif ($start_diff_minutes >= 25 && $start_diff_minutes <= 35) {
notify($ERRORS{'DEBUG'}, 0, "reservation will start in 25-35 minutes ($start_diff_minutes)");
return "preload";
}
else {
#notify($ERRORS{'DEBUG'}, 0, "reservation will start less than 25 minutes ($start_diff_minutes)");
return "0";
}
} ## end if ($start_diff_minutes > 0)
else {
# Start time is in past, $start_diff_minutes is negative
if ($start_diff_minutes >= -17) {
notify($ERRORS{'DEBUG'}, 0, "reservation start time was in the past 17 minutes ($start_diff_minutes)");
return "start";
}
else {
notify($ERRORS{'DEBUG'}, 0, "reservation start time was more than 17 minutes ago ($start_diff_minutes)");
return "old";
}
} ## end else [ if ($start_diff_minutes > 0)
} ## end if ($request_state_name =~ /new|imageprep|reload|tomaintenance|tovmhostinuse/)
elsif ($request_state_name =~ /inuse|imageinuse/) {
if ($end_diff_minutes <= 10) {
#notify($ERRORS{'DEBUG'}, 0, "reservation will end in 10 minutes or less ($end_diff_minutes)");
return "end";
}
else {
# End time is more than 10 minutes in the future
#notify($ERRORS{'DEBUG'}, 0, "reservation will end in more than 10 minutes ($end_diff_minutes)");
if ($lastcheck_diff_minutes <= -5) {
#notify($ERRORS{'DEBUG'}, 0, "reservation was last checked more than 5 minutes ago ($lastcheck_diff_minutes)");
return "poll";
}
else {
#notify($ERRORS{'DEBUG'}, 0, "reservation has been checked within the past 5 minutes ($lastcheck_diff_minutes)");
return 0;
}
} ## end else [ if ($end_diff_minutes <= 10)
} ## end elsif ($request_state_name =~ /inuse|imageinuse/) [ if ($request_state_name =~ /new|imageprep|reload|tomaintenance|tovmhostinuse/)
elsif ($request_state_name =~ /complete|failed/) {
# Don't need to keep requests in database if laststate was...
if ($request_laststate_name =~ /image|deleted|makeproduction|reload|tomaintenance|tovmhostinuse/) {
return "remove";
}
if ($end_diff_minutes < 0) {
notify($ERRORS{'DEBUG'}, 0, "reservation end time was in the past ($end_diff_minutes)");
return "remove";
}
else {
# End time is now or in the future
#notify($ERRORS{'DEBUG'}, 0, "reservation end time is either right now or in the future ($end_diff_minutes)");
return "0";
}
} # Close if state is complete or failed
# Just return start for all other states
else {
return "start";
}
} ## end sub check_time
#/////////////////////////////////////////////////////////////////////////////
=head2 time_exceeded
Parameters : $time_slice, $limit
Returns : 1(success) or 0(failure)
Description : preform a difference check,
if delta of now and input $time_slice
is less than input $limit return 1(true)
=cut
sub time_exceeded {
my ($time_slice, $limit) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my $now = time();
my $diff = $now - $time_slice;
if ($diff > ($limit * 60)) {
#time exceeded
return 1;
}
else {
return 0;
}
} ## end sub time_exceeded
#/////////////////////////////////////////////////////////////////////////////
=head2 mail
Parameters : $to, $subject, $mailstring, $from
Returns : 1(success) or 0(failure)
Description : send an email
=cut
sub mail {
my ($to, $subject, $mailstring, $from) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Mail::Mailer relies on sendmail as written, this causes a "die" on Windows
# TODO: Reqork this subroutine to not rely on sendmail
my $osname = lc($^O);
if ($osname =~ /win/i) {
notify($ERRORS{'OK'}, 0, "sending mail from Windows not yet supported\n-----\nTo: $to\nSubject: $subject\nFrom: $from\n$mailstring\n-----");
return;
}
# Wrap text for lines longer than 72 characters
#$Text::Wrap::columns = 72;
#$mailstring = wrap('', '', $mailstring);
# compare requestor and owner, if same only mail one
if (!(defined($from))) {
$from = "vcl_help\@ncsu.edu";
}
my $mailer = Mail::Mailer->new("sendmail", "-fitecs-vclsysroot\@engr.ncsu.edu");
if ($SHARED_MAILBOX) {
my $bcc = $SHARED_MAILBOX;
if ($mailer->open({From => $from,
To => $to,
Bcc => $bcc,
Subject => $subject,}))
{
print $mailer $mailstring;
$mailer->close();
notify($ERRORS{'OK'}, 0, "SUCCESS -- Sending mail To: $to, $subject");
}
else {
notify($ERRORS{'WARNING'}, 0, "NOTICE -- Problem sending mail to: $to From");
}
} ## end if ($SHARED_MAILBOX)
else {
if ($mailer->open({From => $from,
To => $to,
Subject => $subject,}))
{
print $mailer $mailstring;
$mailer->close();
notify($ERRORS{'OK'}, 0, "SUCCESS -- Sending mail To: $to, $subject");
}
else {
notify($ERRORS{'WARNING'}, 0, "NOTICE -- Problem sending mail to: $to From");
}
} ## end else [ if ($SHARED_MAILBOX)
} ## end sub mail
#/////////////////////////////////////////////////////////////////////////////
=head2 setstaticaddress
Parameters : $node, $osname, $IPaddress
Returns : 1,0 -- success failure
Description : assigns statically assigned IPaddress
=cut
sub setstaticaddress {
my ($node, $osname, $IPaddress) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "nodename not set") if (!defined($node));
notify($ERRORS{'OK'}, 0, "osname not set") if (!defined($osname));
notify($ERRORS{'CRITICAL'}, 0, "IPaddress not set") if (!defined($IPaddress));
#collect private address -- read hosts file only useful if running
# xcat setup and private addresses are listsed in the local
# /etc/hosts file
#should also store/pull private address from the database
my $privateIP;
if (open(HOSTS, "/etc/hosts")) {
my @hosts = <HOSTS>;
close(HOSTS);
foreach my $line (@hosts) {
if ($line =~ /([0-9]*.[0-9]*.[0-9]*.[0-9]*)\s+($node)/) {
$privateIP = $1;
notify($ERRORS{'OK'}, 0, "PrivateIP address for $node collected $privateIP");
last;
}
}
} ## end if (open(HOSTS, "/etc/hosts"))
if (!defined($privateIP)) {
notify($ERRORS{'WARNING'}, 0, "private IP address not found for $node, possible issue with regex");
}
my $identity;
my @sshcmd;
if ($osname =~ /^(rh|fc|esx)/) {
$identity = $IDENTITY_bladerhel;
#create local tmp file
# down interface
#copy tmpfile to /etc/sysconfig/network-scripts/ifcfg-eth1
# up interface
#set route for correct gateway
my @eth1file;
my $tmpfile = "/tmp/ifcfg-eth_device-$node";
push(@eth1file, "DEVICE=eth1\n");
push(@eth1file, "BOOTPROTO=static\n");
push(@eth1file, "IPADDR=$IPaddress\n");
push(@eth1file, "NETMASK=$NETMASK\n");
push(@eth1file, "STARTMODE=onboot\n");
push(@eth1file, "ONBOOT=yes\n");
#write to tmpfile
if (open(TMP, ">$tmpfile")) {
print TMP @eth1file;
close(TMP);
}
else {
#print "could not write $tmpfile $!\n";
}
@sshcmd = run_ssh_command($node, $identity, "/etc/sysconfig/network-scripts/ifdown $ETHDEVICE", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l) {
#potential problem
notify($ERRORS{'OK'}, 0, "sshcmd outpuer ifdown $node $l");
}
}
#copy new ifcfg-Device
if (run_scp_command($tmpfile, "$node:/etc/sysconfig/network-scripts/ifcfg-$ETHDEVICE", $identity)) {
#confirm it got there
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "cat /etc/sysconfig/network-scripts/ifcfg-$ETHDEVICE", "root");
my $success = 0;
foreach my $i (@{$sshcmd[1]}) {
if ($i =~ /$IPaddress/) {
notify($ERRORS{'OK'}, 0, "SUCCESS - copied ifcfg_$ETHDEVICE\n");
$success = 1;
}
}
if (unlink($tmpfile)) {
notify($ERRORS{'OK'}, 0, "unlinking $tmpfile");
}
if (!$success) {
notify($ERRORS{'WARNING'}, 0, "unable to copy $tmpfile to $node file ifcfg-$ETHDEVICE did get updated with $IPaddress ");
return 0;
}
} ## end if (run_scp_command($tmpfile, "$node:/etc/sysconfig/network-scripts/ifcfg-$ETHDEVICE"...
#bring device up
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "/etc/sysconfig/network-scripts/ifup $ETHDEVICE", "root");
#should be empty
foreach my $l (@{$sshcmd[1]}) {
if ($l) {
#potential problem
notify($ERRORS{'OK'}, 0, "possible problem with ifup $ETHDEVICE $l");
}
}
#correct route table - delete old default and add new in same line
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "/sbin/route del default", "root");
#should be empty
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Usage:/) {
#potential problem
notify($ERRORS{'OK'}, 0, "possible problem with route del default $l");
}
if ($l =~ /No such process/) {
notify($ERRORS{'OK'}, 0, "$l - ok just no default route since we downed eth device");
}
}
notify($ERRORS{'OK'}, 0, "Setting default route");
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "/sbin/route add default gw $GATEWAY metric 0 $ETHDEVICE", "root");
#should be empty
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Usage:/) {
#potential problem
notify($ERRORS{'OK'}, 0, "possible problem with route add default gw $GATEWAY metric 0 $ETHDEVICE");
}
if ($l =~ /No such process/) {
notify($ERRORS{'CRITICAL'}, 0, "problem with $node $l add default gw $GATEWAY metric 0 $ETHDEVICE ");
return 0;
}
} ## end foreach my $l (@{$sshcmd[1]})
#correct external sshd file
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "cat /etc/ssh/external_sshd_config", "root");
foreach my $i (@{$sshcmd[1]}) {
if ($i =~ /No such file or directory/) {
notify($ERRORS{'OK'}, 0, "possible problem $i could not read $node /etc/ssh/external_sshd_config");
#problem
}
if ($i =~ s/ListenAddress (.*)/ListenAddress $IPaddress/) {
notify($ERRORS{'OK'}, 0, "changed Listen Address on $node");
}
} ## end foreach my $i (@{$sshcmd[1]})
#Write contents to tmp file
my $extsshtmpfile = "/tmp/extsshtmpfile$node";
if (open(TMPFILE, ">$extsshtmpfile")) {
print TMPFILE @{$sshcmd[1]};
close(TMPFILE);
}
else {
notify($ERRORS{'OK'}, 0, "could not write tmpfile $extsshtmpfile $!");
}
#copy back to host
if (run_scp_command($extsshtmpfile, "$node:/etc/ssh/external_sshd_config", $identity)) {
notify($ERRORS{'OK'}, 0, "success copied $extsshtmpfile to $node");
}
else {
notify($ERRORS{'WARNING'}, 0, "could not write copy $extsshtmpfile to $node");
}
if (unlink($extsshtmpfile)) {
notify($ERRORS{'OK'}, 0, "unlinking $extsshtmpfile");
}
#modify /etc/resolve.conf
my $search;
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "cat /etc/resolv.conf", "root");
foreach my $l (@{$sshcmd[1]}) {
chomp($l);
if ($l =~ /search/) {
$search = $l;
}
}
if (defined($search)) {
my @resolvconf;
push(@resolvconf, "$search\n");
my ($s1, $s2, $s3);
if ($DNSserver =~ /,/) {
($s1, $s2, $s3) = split(/,/, $DNSserver);
}
else {
$s1 = $DNSserver;
}
push(@resolvconf, "nameserver $s1\n");
push(@resolvconf, "nameserver $s2\n") if (defined($s2));
push(@resolvconf, "nameserver $s3\n") if (defined($s3));
my $rtmpfile = "/tmp/resolvconf$node";
if (open(RES, ">$rtmpfile")) {
print RES @resolvconf;
close(RES);
}
else {
notify($ERRORS{'OK'}, 0, "could not write to $rtmpfile $!");
}
#put resolve.conf file back on node
notify($ERRORS{'OK'}, 0, "copying in new resolv.conf");
if (run_scp_command($rtmpfile, "$node:/etc/resolv.conf", $identity)) {
notify($ERRORS{'OK'}, 0, "SUCCESS copied new resolv.conf to $node");
}
else {
notify($ERRORS{'OK'}, 0, "FALIED to copied new resolv.conf to $node");
return 0;
}
if (unlink($rtmpfile)) {
notify($ERRORS{'OK'}, 0, "unlinking $rtmpfile");
}
} ## end if (defined($search))
else {
notify($ERRORS{'WARNING'}, 0, "pulling resolve.conf from $node failed output= @{ $sshcmd[1] }");
}
} ## end if ($osname =~ /^(rh|fc|esx)/)
elsif ($osname =~ /^(win|vmwarewin|vista)/) {
$identity = $IDENTITY_wxp;
#scan adapter list to figure out which adapter is public
# run netsh command to set the public adapter to static
# correct the route table
my $myadapter;
my %ip;
my ($privateadapter, $publicadapter);
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "ipconfig -all", "root");
# build hash of needed info and set the correct private adapter.
my $id = 1;
foreach my $a (@{$sshcmd[1]}) {
if ($a =~ /Ethernet adapter (.*):/) {
$myadapter = $1;
$ip{$myadapter}{"id"} = $id;
$ip{$myadapter}{"private"} = 0;
}
if ($a =~ /IP Address([\s.]*): $privateIP/) {
$ip{$myadapter}{"private"} = 1;
}
if ($a =~ /Physical Address([\s.]*): ([-0-9]*)/) {
$ip{$myadapter}{"MACaddress"} = $2;
}
$id++;
} ## end foreach my $a (@{$sshcmd[1]})
foreach my $key (keys %ip) {
if (defined($ip{$key}{private})) {
if (!($ip{$key}{private})) {
$publicadapter = "\"$key\"";
}
}
}
#Make sure we have publicadapter defined
if (!defined($publicadapter)) {
notify($ERRORS{'WARNING'}, 0, "publicadapter not detected from $node");
return 0;
}
#setting publicadapter to static
notify($ERRORS{'OK'}, 0, "executing netsh interface ip set address name=\\\"$publicadapter\\\" source=static addr=$IPaddress mask=$NETMASK gateway=$GATEWAY gwmetric=2\n");
undef @sshcmd;
my $cmdstring = "netsh interface ip set address name=\\\"$publicadapter\\\" source=static addr=$IPaddress mask=$NETMASK gateway=$GATEWAY gwmetric=2";
@sshcmd = run_ssh_command($node, $identity, $cmdstring, "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Ok/) {
notify($ERRORS{'OK'}, 0, "successfully set $publicadapter to static");
}
}
#set dns
my ($s1, $s2, $s3);
if ($DNSserver =~ /,/) {
($s1, $s2, $s3) = split(/,/, $DNSserver);
}
else {
$s1 = $DNSserver;
}
notify($ERRORS{'OK'}, 0, "executing setting DNS netsh interface ip set dns name=\\\"$publicadapter\\\" source=static addr=$s1 register=none\n");
undef @sshcmd;
$cmdstring = "netsh interface ip set dns name=\\\"$publicadapter\\\" source=static addr=$s1 register=none";
@sshcmd = run_ssh_command($node, $identity, $cmdstring, "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Ok/) {
notify($ERRORS{'OK'}, 0, "successfully set dns $publicadapter ");
}
}
#correct route table - delete old default and add new in same line
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "route del 0.0.0.0", "root");
#should be empty
foreach my $l (@{$sshcmd[1]}) {
if ($l) {
#potential problem
notify($ERRORS{'OK'}, 0, "possible problem with route del default $l");
}
}
notify($ERRORS{'OK'}, 0, "Setting default route");
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "route -p ADD 0.0.0.0 MASK 0.0.0.0 $GATEWAY METRIC 2", "root");
#should be empty
foreach my $l (@{$sshcmd[1]}) {
if ($l) {
#potential problem
notify($ERRORS{'OK'}, 0, "possible problem with route add default gw $GATEWAY metric 0 $ETHDEVICE");
}
}
} ## end elsif ($osname =~ /^(win|vmwarewin|vista)/) [ if ($osname =~ /^(rh|fc|esx)/)
else {
# osname not defined
}
} ## end sub setstaticaddress
#/////////////////////////////////////////////////////////////////////////////
=head2 getdynamicaddress
Parameters : $node, $osname
Returns : assigned ipaddress
Description : collects the dynamically assigned ipaddress
=cut
sub getdynamicaddress {
my ($node, $osname) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "nodename not set") if (!defined($node));
notify($ERRORS{'OK'}, 0, "osname not set") if (!defined($osname));
#collect private address -- read hosts file only useful if running
# xcat setup and private addresses are listsed in the local
# /etc/hosts file
#should also store/pull private address from the database
my $privateIP;
my @sshcmd;
if (open(HOSTS, "/etc/hosts")) {
my @hosts = <HOSTS>;
close(HOSTS);
foreach my $line (@hosts) {
if ($line =~ /([0-9]*.[0-9]*.[0-9]*.[0-9]*)\s+($node)/) {
$privateIP = $1;
notify($ERRORS{'OK'}, 0, "PrivateIP address for $node collected $privateIP");
last;
}
}
} ## end if (open(HOSTS, "/etc/hosts"))
if (!defined($privateIP)) {
notify($ERRORS{'WARNING'}, 0, "private IP address not found for $node, possible issue with regex");
}
my $identity;
my $dynaIPaddress = 0;
if ($osname =~ /win|vmwarewin/) {
$identity = $IDENTITY_wxp;
@sshcmd = run_ssh_command($node, $identity, "netsh diag show ip", "root");
for my $l (@{$sshcmd[1]}) {
# skip class a,b,c private addresses
next if ($l =~ /IPAddress = $privateIP/);
next if ($l =~ /inet addr:10.([.0-9]*)/);
next if ($l =~ /inet addr:127([.0-9]*)/);
next if ($l =~ /inet addr:172([.0-9]*)/);
next if ($l =~ /inet addr:192.168([.0-9]*)/);
if ($l =~ /IPAddress = ([.0-9]*)/) {
if ($l !~ /IPAddress = $privateIP/) {
#to cover sites using eth0 as public
$dynaIPaddress = $1;
}
}
}
} ## end if ($osname =~ /win|vmwarewin/)
elsif ($osname =~ /^(rh|fc)/) {
$identity = $IDENTITY_bladerhel;
undef @sshcmd;
@sshcmd = run_ssh_command($node, $identity, "/sbin/ifconfig \|grep inet", "root");
for my $l (@{$sshcmd[1]}) {
# skip class a,b,c private addresses
next if ($l =~ /inet addr:$privateIP/);
next if ($l =~ /inet addr:10.([.0-9]*)/);
next if ($l =~ /inet addr:127([.0-9]*)/);
next if ($l =~ /inet addr:172([.0-9]*)/);
next if ($l =~ /inet addr:192.168([.0-9]*)/);
if ($l =~ /inet addr:([.0-9]*)/) {
if ($l !~ /inet addr:$privateIP/) {
#to cover sites using eth0 as public
$dynaIPaddress = $1;
}
}
} ## end for my $l (@{$sshcmd[1]})
} ## end elsif ($osname =~ /^(rh|fc)/) [ if ($osname =~ /win|vmwarewin/)
else {
notify($ERRORS{'WARNING'}, 0, "OSname $osname not supported ");
return 0;
}
return $dynaIPaddress;
} ## end sub getdynamicaddress
#/////////////////////////////////////////////////////////////////////////////
=head2 _set_sshd_startmode
Parameters : $node, $mode
Returns : 1 or 0
Description : sets the sshd service on winxp images to auto or manual
=cut
sub _set_sshd_startmode {
my ($node, $mode) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "nodename not set") if (!defined($node));
notify($ERRORS{'OK'}, 0, "ipaddress not set") if (!defined($mode));
#specific to sc command
$mode = "demand" if ($mode eq "manual");
# start using sc to change the start mode
my $cmd = "cmd /c C:\/WINDOWS\/system32\/sc config sshd start= $mode";
my @SC = run_ssh_command($node, $IDENTITY_wxp, $cmd);
for my $line (@{$SC[1]}) {
if ($line =~ /ChangeServiceConfig SUCCESS/) {
notify($ERRORS{'OK'}, 0, "successfully set sshd on $node to $mode");
return 1;
}
}
notify($ERRORS{'WARNING'}, 0, "_set_sshd_startmode failed return status $SC[0] array= @{ $SC[1] }");
return 0;
} ## end sub _set_sshd_startmode
#/////////////////////////////////////////////////////////////////////////////
=head2 _checknstartservice
Parameters : $service name
Returns : 1 or 0
Description : checks for running local service attempts to restart
xCAT specific
=cut
sub _checknstartservice {
my $service = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "service not set") if (!defined($service));
my $status = 0;
if (open(SERVICE, "/sbin/service $service status |")) {
while (<SERVICE>) {
chomp($_);
#notify($ERRORS{'OK'},0,"_checknstartservice: $_");
if ($_ =~ /running/) {
$status = 1;
notify($ERRORS{'OK'}, 0, "_checknstartservice: $service is running");
}
}
close(SERVICE);
if ($status == 1) {
return 1;
}
else {
notify($ERRORS{'OK'}, 0, "_checknstartservice: $service is not running will try to start");
# try to start service
if (open(SERVICE, "/sbin/service $service start |")) {
while (<SERVICE>) {
chomp($_);
notify($ERRORS{'WARNING'}, 0, "_checknstartservice: $_");
if ($_ =~ /started/) {
$status = 1;
last;
}
}
close(SERVICE);
if ($status == 1) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "_checknstartservice: $service could not start");
return 0;
}
} ## end if (open(SERVICE, "/sbin/service $service start |"...
else {
notify($ERRORS{'WARNING'}, 0, "_checknstartservice: WARNING -- could not run service command for $service start. $! ");
return 0;
}
} ## end else [ if ($status == 1)
} ## end if (open(SERVICE, "/sbin/service $service status |"...
else {
notify($ERRORS{'WARNING'}, 0, "_checknstartservice: WARNING -- could not run service command for $service check. $! ");
return 0;
}
} ## end sub _checknstartservice
#/////////////////////////////////////////////////////////////////////////////
=head2 check_connection
Parameters : $nodename, $ipaddress, $type, $remoteIP, $time_limit, $osname, $dbh, $requestid, $user
Returns : value - deleted failed timeout connected conn_wrong_ip
Description : uses ssh to log into remote node and preform checks on user connection
=cut
sub check_connection {
my ($nodename, $ipaddress, $type, $remoteIP, $time_limit, $osname, $dbh, $requestid, $user) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "nodename not set") if (!defined($nodename));
notify($ERRORS{'OK'}, 0, "ipaddress not set") if (!defined($ipaddress));
notify($ERRORS{'OK'}, 0, "type not set") if (!defined($type));
notify($ERRORS{'OK'}, 0, "remoteIP not set") if (!defined($remoteIP));
notify($ERRORS{'OK'}, 0, "time_limit not set") if (!defined($time_limit));
notify($ERRORS{'OK'}, 0, "osname not set") if (!defined($osname));
notify($ERRORS{'OK'}, 0, "dbh not set") if (!defined($dbh));
notify($ERRORS{'OK'}, 0, "requestid not set") if (!defined($requestid));
notify($ERRORS{'OK'}, 0, "user not set") if (!defined($user));
my $start_time = time();
my $time_exceeded = 0;
my $break = 0;
my $ret_val = "no";
$dbh = getnewdbh() if !$dbh;
my $identity;
if ($osname =~ /win|vmwarewin|vmwareesxwin|vista/) {
$identity = $IDENTITY_wxp;
}
elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|centos)/) {
$identity = $IDENTITY_bladerhel;
}
# Figure out number of loops for log messates
my $maximum_loops = $time_limit * 2;
my $loop_count = 0;
my @SSHCMD;
while (!$break) {
$loop_count++;
notify($ERRORS{'OK'}, 0, "checking for connection by $user on $nodename, attempt $loop_count ");
# confirm we still have an active db handle
if (!$dbh || !($dbh->ping)) {
notify($ERRORS{'WARNING'}, 0, "database handle died, trying to create another one");
$dbh = getnewdbh();
notify($ERRORS{'OK'}, 0, "database handle re-set") if ($dbh->ping);
notify($ERRORS{'WARNING'}, 0, "inuse process: database handle NOT re-set") if (!($dbh->ping));
}
if (is_request_deleted($requestid)) {
notify($ERRORS{'OK'}, 0, "user has deleted request");
$break = 1;
$ret_val = "deleted";
return $ret_val;
}
#notify($ERRORS{'OK'},0,"comparing wait time for connection");
$time_exceeded = time_exceeded($start_time, $time_limit);
if ($time_exceeded) {
notify($ERRORS{'OK'}, 0, "$time_limit minute time limit exceeded begin cleanup process");
#time_exceeded, begin cleanup process
$break = 1;
if ($package =~ /reserved/) {
notify($ERRORS{'OK'}, 0, "user never logged in returning nologin");
$ret_val = "nologin";
}
else {
$ret_val = "timeout";
}
return $ret_val;
} ## end if ($time_exceeded)
else { #time not exceeded check for connection
if ($type =~ /blade|virtualmachine/) {
my $shortnodename = $nodename;
$shortnodename = $1 if ($nodename =~ /([-_a-zA-Z0-9]*)\./);
if ($osname =~ /win|vmwarewin/) {
undef @SSHCMD;
@SSHCMD = run_ssh_command($shortnodename, $identity, "netstat -an", "root", 22, 1);
foreach my $line (@{$SSHCMD[1]}) {
#check for rdp and ssh connections
# rdp:3389,ssh:22
#check for connection refused, if ssh is gone something
#has happenned put in timeout state
if ($line =~ /Connection refused|Permission denied/) {
chomp($line);
notify($ERRORS{'WARNING'}, 0, "$line");
if ($package =~ /reserved/) {
$ret_val = "failed";
}
else {
$ret_val = "timeout";
}
return $ret_val;
} ## end if ($line =~ /Connection refused|Permission denied/)
if ($line =~ /\s+($ipaddress:3389)\s+([.0-9]*):([0-9]*)\s+(ESTABLISHED)/) {
if ($2 eq $remoteIP) {
$break = 1;
$ret_val = "connected";
return $ret_val;
}
else {
#this isn't the remoteIP
$ret_val = "conn_wrong_ip";
return $ret_val;
}
} ## end if ($line =~ /\s+($ipaddress:3389)\s+([.0-9]*):([0-9]*)\s+(ESTABLISHED)/)
} #foreach
} ## end if ($osname =~ /win|vmwarewin/)
#elsif($osname =~ /^(rhel|rh3image|rh4image|rhfc|fc)/){
elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|centos)/) {
#run two checks
# 1:check connected IP address
# 2:simply check who ouput
my @lines;
undef @SSHCMD;
@SSHCMD = run_ssh_command($shortnodename, $identity, "netstat -an", "root", 22, 1);
foreach my $line (@{$SSHCMD[1]}) {
if ($line =~ /Connection refused|Permission denied/) {
chomp($line);
notify($ERRORS{'WARNING'}, 0, "$line");
if ($package =~ /reserved/) {
$ret_val = "failed";
}
else {
$ret_val = "timeout";
}
return $ret_val;
} ## end if ($line =~ /Connection refused|Permission denied/)
if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s($ipaddress:22)\s+([.0-9]*):([0-9]*)(.*)(ESTABLISHED)/) {
if ($4 eq $remoteIP) {
$break = 1;
$ret_val = "connected";
return $ret_val;
}
else {
#this isn't the remoteIP
$ret_val = "conn_wrong_ip";
return $ret_val;
}
} # tcp check
} #foreach
#who; too make sure we didn't miss it through netstat
undef @SSHCMD;
@SSHCMD = run_ssh_command($shortnodename, $identity, "who", "root");
foreach my $w (@{$SSHCMD[1]}) {
if ($w =~ /$user/) {
$break = 1;
notify($ERRORS{'CRITICAL'}, 0, "found user connected through who command on node $nodename , strange that netstat missed it\nnetstat output:\n @lines");
$ret_val = "connected";
return $ret_val;
}
}
} ## end elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|centos)/) [ if ($osname =~ /win|vmwarewin/)
} ## end if ($type =~ /blade|virtualmachine/)
elsif ($type eq "lab") {
my $identity;
if ($osname =~ /sun4x_/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($osname =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
#if all else fails
$identity = $IDENTITY_solaris_lab;
}
undef @SSHCMD;
@SSHCMD = run_ssh_command($nodename, $identity, "netstat -an", "vclstaff", 24, 1);
foreach my $line (@{$SSHCMD[1]}) {
chomp($line);
if ($line =~ /Connection refused|Permission denied/) {
notify($ERRORS{'WARNING'}, 0, "$line");
if ($package =~ /reserved/) {
$ret_val = "failed";
}
else {
$ret_val = "timeout";
}
return $ret_val;
} ## end if ($line =~ /Connection refused|Permission denied/)
if ($osname =~ /sun4x_/) {
if ($line =~ /\s*($ipaddress\.22)\s+([.0-9]*)\.([0-9]*)(.*)(ESTABLISHED)/) {
if ($2 eq $remoteIP) {
$break = 1;
$ret_val = "connected";
return $ret_val;
}
else {
#this isn't the remoteIP
$ret_val = "conn_wrong_ip";
return $ret_val;
}
} ## end if ($line =~ /\s*($ipaddress\.22)\s+([.0-9]*)\.([0-9]*)(.*)(ESTABLISHED)/)
} ## end if ($osname =~ /sun4x_/)
elsif ($osname =~ /rhel/) {
if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s($ipaddress:22)\s+([.0-9]*):([0-9]*)(.*)(ESTABLISHED)/) {
if ($4 eq $remoteIP) {
$break = 1;
$ret_val = "connected";
return $ret_val;
}
else {
#this isn't the remoteIP
$ret_val = "conn_wrong_ip";
return $ret_val;
}
} ## end if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s($ipaddress:22)\s+([.0-9]*):([0-9]*)(.*)(ESTABLISHED)/)
if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s::ffff:($ipaddress:22)\s+::ffff:([.0-9]*):([0-9]*)(.*)(ESTABLISHED) /) {
if ($4 eq $remoteIP) {
$break = 1;
$ret_val = "connected";
return $ret_val;
}
else {
#this isn't the remoteIP
$ret_val = "conn_wrong_ip";
return $ret_val;
}
} ## end if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s::ffff:($ipaddress:22)\s+::ffff:([.0-9]*):([0-9]*)(.*)(ESTABLISHED) /)
} ## end elsif ($osname =~ /rhel/) [ if ($osname =~ /sun4x_/)
} #foreach
} #if lab
} #else
#sleep 30;
sleep 20;
} #while
return $ret_val;
} ## end sub check_connection
#/////////////////////////////////////////////////////////////////////////////
=head2 isconnected
Parameters : $nodename, $type, $remoteIP, $osname, $ipaddress
Returns : 1 connected 0 not connected
Description : confirms user is connected to node
assumes port 3389 for windows and port 22 for linux/solaris
=cut
sub isconnected {
my ($nodename, $type, $remoteIP, $osname, $ipaddress) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'OK'}, 0, "nodename not set") if (!defined($nodename));
notify($ERRORS{'OK'}, 0, "type not set") if (!defined($type));
notify($ERRORS{'OK'}, 0, "remoteIP not set") if (!defined($remoteIP));
notify($ERRORS{'OK'}, 0, "osname not set") if (!defined($osname));
notify($ERRORS{'OK'}, 0, "ipaddress not set") if (!defined($ipaddress));
my @netstat;
my @SSHCMD;
if ($type =~ /blade|virtualmachine/) {
my $shortname = 0;
$shortname = $1 if ($nodename =~ /([-_a-zA-Z0-9]*)\./);
if ($shortname) {
#convert shortname
$nodename = $shortname;
}
if ($osname =~ /win|vmwarewin/) {
#notify($ERRORS{'OK'},0,"checking $nodename $ipaddress");
undef @SSHCMD;
@SSHCMD = run_ssh_command($shortname, $IDENTITY_wxp, "netstat -an", "root", 22, 1);
foreach my $line (@{$SSHCMD[1]}) {
chomp($line);
if ($line =~ /Connection refused/) {
notify($ERRORS{'WARNING'}, 0, "$line");
return 0;
}
#if($line =~ /\s+($ipaddress:3389)\s+([.0-9]*):([0-9]*)\s+(ESTABLISHED)/){
if ($line =~ /\s+(TCP\s+[.0-9]*:3389)\s+([.0-9]*):([0-9]*)\s+(ESTABLISHED)/) {
#notify($ERRORS{'WARNING'},0,"$line");
return 1 if ($2 eq $remoteIP);
if ($2 ne $remoteIP) {
notify($ERRORS{'WARNING'}, 0, "not correct remote IP is connected");
return 1;
}
}
} ## end foreach my $line (@{$SSHCMD[1]})
} ## end if ($osname =~ /win|vmwarewin/)
elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9])/) {
undef @SSHCMD;
@SSHCMD = run_ssh_command($nodename, $IDENTITY_bladerhel, "netstat -an", "root", 22, 1);
foreach my $line (@{$SSHCMD[1]}) {
chomp($line);
if ($line =~ /Warning/) {
if (known_hosts($nodename, "linux", $ipaddress)) {
#good
}
next;
}
if ($line =~ /Connection refused/) {
notify($ERRORS{'WARNING'}, 0, "$line");
return 0;
}
if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s($ipaddress:22)\s+([.0-9]*):([0-9]*)(.*)(ESTABLISHED)/) {
return 1 if ($4 eq $remoteIP);
if ($4 ne $remoteIP) {
notify($ERRORS{'WARNING'}, 0, "not correct remote IP connected: $line");
return 1;
}
}
} ## end foreach my $line (@{$SSHCMD[1]})
} ## end elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9])/) [ if ($osname =~ /win|vmwarewin/)
return 0;
} ## end if ($type =~ /blade|virtualmachine/)
elsif ($type eq "lab") {
my $identity;
if ($osname =~ /sun4x_/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($osname =~ /realmrhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
#if all else fails
notify($ERRORS{'OK'}, 0, "osname $osname not found setting identity file to default");
$identity = $IDENTITY_solaris_lab;
}
undef @SSHCMD;
@SSHCMD = run_ssh_command($nodename, $identity, "netstat -an", "vclstaff", 24, 1);
foreach my $line (@{$SSHCMD[1]}) {
chomp($line);
if ($line =~ /Connection refused/) {
notify($ERRORS{'WARNING'}, 0, "$nodename $line");
return 0;
}
if ($osname =~ /sun4x_/) {
if ($line =~ /\s*($ipaddress\.22)\s+([.0-9]*)\.([0-9]*)(.*)(ESTABLISHED)/) {
return 1 if ($2 eq $remoteIP);
if ($2 ne $remoteIP) {
notify($ERRORS{'WARNING'}, 0, "not correct remote IP connected $4");
return 1;
}
}
}
elsif ($osname =~ /realmrhel3/) {
if ($line =~ /tcp\s+([0-9]*)\s+([0-9]*)\s($ipaddress:22)\s+([.0-9]*):([0-9]*)(.*)(ESTABLISHED)/) {
return 1 if ($4 eq $remoteIP);
if ($4 ne $remoteIP) {
notify($ERRORS{'WARNING'}, 0, "not correct remote IP connected $4");
return 1;
}
}
}
} ## end foreach my $line (@{$SSHCMD[1]})
return 0;
} ## end elsif ($type eq "lab") [ if ($type =~ /blade|virtualmachine/)
} ## end sub isconnected
#/////////////////////////////////////////////////////////////////////////////
=head2 update_preload_fla
Parameters : request id, flag 1,0
Returns : 1 success 0 failure
Description : update preload flag
=cut
sub update_preload_flag {
my ($request_id, $flag) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "request id is not defined") unless (defined($request_id));
notify($ERRORS{'WARNING'}, 0, "preload flag is not defined") unless (defined($flag));
my $update_statement = "
UPDATE
request
SET
preload = $flag
WHERE
id = $request_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful
notify($ERRORS{'OK'}, $LOGFILE, "preload flag updated for request_id $request_id ");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update preload flag updated for request_id $request_id");
return 0;
}
} ## end sub update_preload_flag
#/////////////////////////////////////////////////////////////////////////////
=head2 update_request_state
Parameters : request id, state name, last state(optional), log(optional)
Returns : 1 success 0 failure
Description : update states
=cut
sub update_request_state {
my ($request_id, $state_name, $laststate_name, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameters
if (!defined($request_id)) {
notify($ERRORS{'WARNING'}, $log, "unable to update request state, request id is not defined");
return 0;
}
if (!defined($state_name)) {
notify($ERRORS{'WARNING'}, $log, "unable to update request $request_id state, state name not defined");
return 0;
}
my $update_statement;
# Determine whether or not to update laststate, construct the SQL statement
if (defined $laststate_name && $laststate_name ne "") {
$update_statement = "
UPDATE
request,
state state,
state laststate
SET
request.stateid = state.id,
request.laststateid = laststate.id
WHERE
state.name = \'$state_name\'
AND laststate.name = \'$laststate_name\'
AND request.id = $request_id
";
} ## end if (defined $laststate_name && $laststate_name...
else {
$update_statement = "
UPDATE
request,
state state
SET
request.stateid = state.id
WHERE
state.name = \'$state_name\'
AND request.id = $request_id
";
$laststate_name = 'unchanged';
} ## end else [ if (defined $laststate_name && $laststate_name...
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful
notify($ERRORS{'OK'}, $LOGFILE, "request $request_id state updated to: $state_name, laststate to: $laststate_name");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update states for request $request_id");
return 0;
}
} ## end sub update_request_state
#/////////////////////////////////////////////////////////////////////////////
=head2 update_computer_state
Parameters : $computer_id, $state_name, $log
Returns : 1 success 0 failure
Description : update computer state
=cut
sub update_computer_state {
my ($computer_id, $state_name, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, $log, "computer id is not defined") unless (defined($computer_id));
notify($ERRORS{'WARNING'}, $log, "statename is not defined") unless (defined($state_name));
return 0 unless (defined $computer_id && defined $state_name);
my $update_statement = "
UPDATE
computer,
state
SET
computer.stateid = state.id
WHERE
state.name = \'$state_name\'
AND computer.id = $computer_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful
notify($ERRORS{'OK'}, $LOGFILE, "computer $computer_id state updated to: $state_name");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update states for computer $computer_id");
return 0;
}
} ## end sub update_computer_state
#/////////////////////////////////////////////////////////////////////////////
=head2 update_request_password
Parameters : $reservation_id, $password
Returns : 1 success 0 failure
Description : updates password field for reservation id
=cut
sub update_request_password {
my ($reservation_id, $password) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "reservation id is not defined") unless (defined($reservation_id));
notify($ERRORS{'WARNING'}, 0, "password is not defined") unless (defined($password));
my $update_statement = "
UPDATE
reservation
SET
pw = \'$password\'
WHERE
id = $reservation_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful
notify($ERRORS{'OK'}, $LOGFILE, "password updated for reservation_id $reservation_id ");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update password for reservation $reservation_id");
return 0;
}
} ## end sub update_request_password
#/////////////////////////////////////////////////////////////////////////////
=head2 is_request_deleted
Parameters : $request_id
Returns : return 1 if request state or laststate is set to deleted or if request does not exist
return 0 if request exists and neither request state nor laststate is set to deleted1 success 0 failure
Description : checks if request has been deleted
=cut
sub is_request_deleted {
my ($request_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($request_id))) {
notify($ERRORS{'WARNING'}, 0, "request ID was not specified");
return 0;
}
# Create the select statement
my $select_statement = "
SELECT
request.stateid AS currentstate_id,
request.laststateid AS laststate_id,
currentstate.name AS currentstate_name,
laststate.name AS laststate_name
FROM
request, state currentstate, state laststate
WHERE
request.id = $request_id
AND request.stateid = currentstate.id
AND request.laststateid = laststate.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
return 1;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return 0;
}
my $state_name = $selected_rows[0]{currentstate_name};
my $laststate_name = $selected_rows[0]{laststate_name};
#notify($ERRORS{'DEBUG'}, 0,"state=$state_name, laststate=$laststate_name");
if ($state_name eq 'deleted' || $laststate_name eq 'deleted') {
return 1;
}
return 0;
} ## end sub is_request_deleted
#/////////////////////////////////////////////////////////////////////////////
=head2 is_reservation_deleted
Parameters : $reservation_id
Returns : return 1 if reservation's request state or laststate is set to deleted or if reservation does not exist
return 0 if reservation exists and neither request state nor laststate is set to deleted: 1 success, 0 failure
Description : checks if reservation has been deleted
=cut
sub is_reservation_deleted {
my ($reservation_id) = @_;
# Check the passed parameter
if (!(defined($reservation_id))) {
notify($ERRORS{'WARNING'}, 0, "reservation ID was not specified");
return 0;
}
# Create the select statement
my $select_statement = "
SELECT
reservation.id AS reservation_id,
request.stateid AS currentstate_id,
request.laststateid AS laststate_id,
currentstate.name AS currentstate_name,
laststate.name AS laststate_name
FROM
reservation, request, state currentstate, state laststate
WHERE
reservation.id = $reservation_id
AND reservation.requestid = request.id
AND request.stateid = currentstate.id
AND request.laststateid = laststate.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
return 1;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return 0;
}
my $state_name = $selected_rows[0]{currentstate_name};
my $laststate_name = $selected_rows[0]{laststate_name};
#notify($ERRORS{'DEBUG'}, 0,"state=$state_name, laststate=$laststate_name");
if ($state_name eq 'deleted' || $laststate_name eq 'deleted') {
return 1;
}
return 0;
} ## end sub is_reservation_deleted
#/////////////////////////////////////////////////////////////////////////////
=head2 is_request_imaging
Parameters : $request_id
Returns : return 1 if request state or laststate is set to image or if request does not exist
return 0 if request exists and neither request state nor laststate is set to image success 0 failure
Description : checks if request is in imaging mode
=cut
sub is_request_imaging {
my ($request_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($request_id))) {
notify($ERRORS{'WARNING'}, 0, "request ID was not specified");
return 0;
}
# Create the select statement
my $select_statement = "
SELECT
request.stateid AS currentstate_id,
request.laststateid AS laststate_id,
currentstate.name AS currentstate_name,
laststate.name AS laststate_name
FROM
request, state currentstate, state laststate
WHERE
request.id = $request_id
AND request.stateid = currentstate.id
AND request.laststateid = laststate.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
return 1;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return 0;
}
my $state_name = $selected_rows[0]{currentstate_name};
my $laststate_name = $selected_rows[0]{laststate_name};
notify($ERRORS{'DEBUG'}, 0, "is_request_imaging currentstate= $state_name laststate= $laststate_name");
if ($state_name eq 'image' || $laststate_name eq 'image') {
return 1;
}
return 0;
} ## end sub is_request_imaging
#/////////////////////////////////////////////////////////////////////////////
=head2 get_next_image_default
Parameters : $computerid
Returns : imageid,imagerevisionid,imagename
Description : Looks for any upcoming reservations
for supplied computerid, if starttime is
within 50 minutes return that imageid. Else
fetch and return preferred image
=cut
sub get_next_image_default {
my ($computerid) = @_;
my ($calling_package, $calling_filename, $calling_line, $calling_sub) = caller(0);
if (!defined($computerid)) {
notify($ERRORS{'WARNING'}, 0, "$calling_sub $calling_package missing mandatory variable: computerid ");
return 0;
}
my $select_statement = "
SELECT DISTINCT
req.start AS starttime,
ir.imagename AS imagename,
res.imagerevisionid AS imagerevisionid,
res.imageid AS imageid
FROM
reservation res,
request req,
image i,
state s,
imagerevision ir
WHERE
res.requestid = req.id
AND req.stateid = s.id
AND i.id = res.imageid
AND ir.id = res.imagerevisionid
AND res.computerid = $computerid
AND (s.name = \'new\' OR s.name = \'reload\' OR s.name = \'imageprep\')
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
my @ret_array;
# Check to make sure 1 or more rows were returned
if (scalar @selected_rows > 0) {
# Loop through list of upcoming reservations
# Based on the start time load the next one
my $now = time();
# It contains a hash
for (@selected_rows) {
my %reservation_row = %{$_};
# $reservation_row{starttime}
# $reservation_row{imagename}
# $reservation_row{imagerevisionid}
# $reservation_row{imageid}
my $epoch_start = convert_to_epoch_seconds($reservation_row{starttime});
my $diff = $epoch_start - $now;
# If start time is less than 50 minutes from now return this image
notify($ERRORS{'OK'}, 0, "get_next_image_default : diff= $diff image= $reservation_row{imagename} imageid=$reservation_row{imageid}");
if ($diff < (50 * 60)) {
notify($ERRORS{'OK'}, 0, "get_next_image_default : future reservation detected diff= $diff image= $reservation_row{imagename} imageid=$reservation_row{imageid}");
push(@ret_array, $reservation_row{imagename}, $reservation_row{imageid}, $reservation_row{imagerevisionid});
return @ret_array;
}
} ## end for (@selected_rows)
} ## end if (scalar @selected_rows > 0)
# No upcoming reservations - fetch preferred image information
my $select_preferredimage = "
SELECT DISTINCT
imagerevision.imagename AS imagename,
imagerevision.id AS imagerevisionid,
image.id AS imageid
FROM
image,
computer,
imagerevision
WHERE
imagerevision.imageid = computer.preferredimageid
AND imagerevision.production = 1
AND computer.preferredimageid = image.id
AND computer.id = $computerid
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @preferred_selected_rows = database_select($select_preferredimage);
# Check to make sure at least 1 row were returned
if (scalar @preferred_selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "get_next_image_default failed to fetch preferred image for computerid $computerid");
return 0;
}
elsif (scalar @preferred_selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @preferred_selected_rows . " rows were returned from database select");
return 0;
}
notify($ERRORS{'OK'}, 0, "get_next_image_default : returning preferredimage image=$preferred_selected_rows[0]{imagename} imageid=$preferred_selected_rows[0]{imageid}");
push(@ret_array, $preferred_selected_rows[0]{imagename}, $preferred_selected_rows[0]{imageid}, $preferred_selected_rows[0]{imagerevisionid});
return @ret_array;
} ## end sub get_next_image
#/////////////////////////////////////////////////////////////////////////////
=head2 setimagid
Parameters : $dbh, $computerid, $image, $imageid, $imagerevisionid
Returns : 1
Description : updates imageid and imagerevisionid on provided computerid
sub setimageid {
my ($dbh, $computerid, $image, $imageid, $imagerevisionid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "setimageid: computerid is not defined") if (!(defined($computerid)));
notify($ERRORS{'WARNING'}, 0, "setimageid: image is not defined") if (!(defined($image)));
notify($ERRORS{'WARNING'}, 0, "setimageid: imageid is not defined") if (!(defined($imageid)));
$imagerevisionid = 0 if (!(defined($imagerevisionid)));
my $update_statement="UPDATE computer c SET c.currentimageid = $imageid,c.imagerevisionid = $imagerevisionid WHERE c.id = $computerid" ;
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update preferredimageid");
return 0;
}
} ## end sub setimageid
=cut
#/////////////////////////////////////////////////////////////////////////////
=head2 setpreferredimage
Parameters : $computerid, $image
Returns : 1 success, 0 failed
Description : updates preferredimageid on provided computerid
=cut
sub setpreferredimage {
my ($computerid, $imageid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "computerid: node is not defined") if (!(defined($computerid)));
notify($ERRORS{'WARNING'}, 0, "imageid: node is not defined") if (!(defined($imageid)));
my $update_statement = " UPDATE computer SET preferredimageid = $imageid WHERE id = $computerid ";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update preferredimageid");
return 0;
}
} ## end sub setpreferredimage
#/////////////////////////////////////////////////////////////////////////////
=head2 _getcurrentimage
Parameters : $node
Returns : retrieve the currentimage from currentimage.txt file on the node
Description :
=cut
sub _getcurrentimage {
my $node = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
# TODO - loop through the available ssh keys to figure out which one works
my $identity = $IDENTITY_bladerhel;
my @sshcmd = run_ssh_command($node, $identity, "cat currentimage.txt");
foreach my $s (@{$sshcmd[1]}) {
if ($s =~ /Warning: /) {
#need to run makesshgkh
#if (VCL::Module::Provisioning::xCAT::makesshgkh($node)) {
#success
#not worth output here
#}
#else {
#}
}
if ($s =~ /^(rh|win|fc|vmware)/) {
chomp($s);
if ($s =~ s/\x0d//) {
notify($ERRORS{'OK'}, 0, "stripped dos newline $s");
}
return $s;
}
} ## end foreach my $s (@{$sshcmd[1]})
return 0;
} ## end sub _getcurrentimage
#/////////////////////////////////////////////////////////////////////////////
=head2 check_ssh
Parameters : $node, $port, $log
Returns : 1(active) or 0(inactive)
Description : uses check_ssh binary from tools dir to check
the sshd statuse on the remote node
=cut
sub check_ssh {
my ($node, $port, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!(defined($log)));
notify($ERRORS{'WARNING'}, $log, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, $log, "port is not defined") if (!(defined($port)));
if (!defined($node)) {
return 0;
}
if (!defined($port)) {
$port = 22;
}
if(nmap_port($node,$port)){
notify($ERRORS{'OK'}, $log, " $node ssh port $port open");
return 1;
}
else{
notify($ERRORS{'OK'}, $log, " $node ssh port $port closed");
return 0;
}
return 0;
} ## end sub check_ssh
#/////////////////////////////////////////////////////////////////////////////
=head2 _sshd_status
Parameters : $node, $imagename, $log
Returns : on or off
Description : actually logs into remote node
=cut
sub _sshd_status {
my ($node, $imagename, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!defined($log));
notify($ERRORS{'WARNING'}, $log, "node is not defined") if (!(defined($node)));
if (!nmap_port($node, 22)) {
return "off";
}
my $identity = $IDENTITY_wxp;
if (defined($imagename)) {
$identity = $IDENTITY_bladerhel if ($imagename =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|esx[0-9]+)/);
}
#notify($ERRORS{'OK'},$log,"identity file $identity for imagename $imagename");
my @sshcmd = run_ssh_command($node, $identity, "uname -s", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /^Warning:/) {
#if (VCL::Module::Provisioning::xCAT::makesshgkh($node)) {
#}
}
return "off" if ($l =~ /noping/);
return "off" if ($l =~ /No route to host/);
return "off" if ($l =~ /Connection refused/);
return "off" if ($l =~ /Permission denied/);
} ## end foreach my $l (@{$sshcmd[1]})
return "on";
} ## end sub _sshd_status
#/////////////////////////////////////////////////////////////////////////////
=head2 _machine_os
Parameters : $node, $imagename, $log
Returns : 0 or system type name
Description : actually logs into remote node
=cut
sub _machine_os {
my ($node, $imagename) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
if (!nmap_port($node, 22)) {
notify($ERRORS{'OK'}, 0, "ssh port not open cannot check $node OS");
return 0;
}
my $identity;
if (defined($imagename)) {
$identity = $IDENTITY_bladerhel if ($imagename =~ /^(rhel|rh3image|fc|rh|esx)/);
}
else {
$identity = $IDENTITY_wxp;
}
my @sshcmd = run_ssh_command($node, $identity, "uname -s", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /CYGWIN_NT-5\.1/) {
return "WinXp";
}
elsif ($l =~ "CYGWIN_NT-5\.2") {
return "win2003";
}
elsif ($l =~ /Linux/) {
return "Linux";
}
elsif ($l =~ /Connection refused/) {
return 0;
}
elsif ($l =~ /No route to host/) {
return 0;
}
elsif ($l =~ /Permission denied/) {
return 0;
}
else {
return 0;
}
} ## end foreach my $l (@{$sshcmd[1]})
} ## end sub _machine_os
#/////////////////////////////////////////////////////////////////////////////
=head2 _is_user_added
Parameters : $node, $user, $type, $os
Returns : 1 yes user exists - 0 no
Description : logs into remote node checks to see if
supplied user account exists
=cut
sub _is_user_added {
my ($node, $user, $type, $os) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "user is not defined") if (!(defined($user)));
notify($ERRORS{'WARNING'}, 0, "type is not defined") if (!(defined($type)));
notify($ERRORS{'WARNING'}, 0, "os is not defined") if (!(defined($os)));
my @lines;
my $l;
my @SSHCMD;
if ($type =~ /blade|virtualmachine/) {
if ($os =~ /^win|winxp|wxp|win2003|vmwarewin|vmwareesxwin/) {
undef @SSHCMD;
@SSHCMD = run_ssh_command($node, $IDENTITY_wxp, "cscript.exe //Nologo list_users.vbs", "root");
foreach $l (@{$SSHCMD[1]}) {
return 1 if ($l =~ /$user/);
}
return 0;
}
elsif ($os =~ /^(rhel|rh3image|rh|fc|esx)/) {
undef @SSHCMD;
@SSHCMD = run_ssh_command($node, $IDENTITY_bladerhel, "cat /etc/passwd", "root");
foreach $l (@{$SSHCMD[1]}) {
return 1 if ($l =~ /$user/);
}
return 0;
}
else {
notify($ERRORS{'WARNING'}, 0, "osname is not defined or supported $os");
return 0;
}
} ## end if ($type =~ /blade|virtualmachine/)
elsif ($type eq "lab") {
#tobe done later
}
} ## end sub _is_user_added
#/////////////////////////////////////////////////////////////////////////////
=head2 add_user
Parameters : $node, $user, $uid, $passwd, $hostname, $os, $remoteip, $grpflag, @group
Returns : 1 success, 0 failed
Description : logs into remote node adds supplied user account
=cut
sub add_user {
my ($node, $user, $uid, $passwd, $hostname, $os, $remoteip, $grpflag, @group) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "user is not defined") if (!(defined($user)));
notify($ERRORS{'OK'}, 0, "uid is not defined") if (!(defined($uid)));
notify($ERRORS{'WARNING'}, 0, "passwd is not defined") if (!(defined($passwd)));
notify($ERRORS{'WARNING'}, 0, "os is not defined") if (!(defined($os)));
notify($ERRORS{'OK'}, 0, "remoteip is not defined") if (!(defined($remoteip)));
notify($ERRORS{'OK'}, 0, "grpflag is not defined") if (!(defined($grpflag)));
if (!(defined($grpflag))) {
$grpflag = 0;
}
elsif ($grpflag > 0) {
notify($ERRORS{'OK'}, 0, "group access memberlist= @group ");
}
# set common linux useradd string
my $useradd_string;
if (!(defined($uid))) { # check for uid if not let OS set one
$useradd_string = "/usr/sbin/useradd -d /home/$user -m $user -g ncsu";
}
else {
$useradd_string = "/usr/sbin/useradd -u $uid -d /home/$user -m $user -g ncsu";
}
if ($os =~ /win|vmwarewin/) {
my @sshcmd1 = run_ssh_command($node, $IDENTITY_wxp, "cscript.exe //Nologo add_user.vbs $user $passwd", "root");
my $delete_user = 0;
foreach my $l (@{$sshcmd1[1]}) {
if ($l =~ /The filename, directory name, or volume label syntax is incorrect/) {
#ok, user is already there must have been a problem earlier
#let delete the user and continue
$delete_user = 1;
}
}
if ($delete_user) {
notify($ERRORS{'OK'}, 0, "error $user may already be listed");
if (del_user($node, $user, "blade", $os)) {
notify($ERRORS{'OK'}, 0, "$user deleted");
}
#rerun command
if (run_ssh_command($node, $IDENTITY_wxp, "cscript.exe //Nologo add_user.vbs $user $passwd", "root")) {
#good
}
} ## end if ($delete_user)
return _is_user_added($node, $user, "blade", $os);
notify($ERRORS{'OK'}, 0, "prep $node $user $passwd");
} ## end if ($os =~ /win|vmwarewin/)
elsif ($os =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|esx)/) {
# two methods: single user or group of users
if ($grpflag) {
#assumes owner is already member of group
#ok group flag set proceed
my $allowuserstring = "AllowUsers";
foreach my $u (@group) {
#$u in form of unity:uid
my ($user_unityid, $uid) = split(":", $u);
my $cmd = "/usr/sbin/useradd -u $uid -d /home/$user_unityid -m $user_unityid -g ncsu";
if (run_ssh_command($node, $IDENTITY_bladerhel, $cmd, "root")) {
notify($ERRORS{'OK'}, 0, "added user $user_unityid to $node");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to execute $cmd");
return 0;
}
#append to ssh string
$allowuserstring .= " $user_unityid";
} ## end foreach my $u (@group)
# modify external_sshd config
my $cmdstring = "echo \"$allowuserstring\" >> /etc/ssh/external_sshd_config";
my @sshcmd;
if (run_ssh_command($node, $IDENTITY_bladerhel, $cmdstring, "root")) {
notify($ERRORS{'OK'}, 0, "adding user string to sshd conf $allowuserstring");
undef @sshcmd;
@sshcmd = run_ssh_command($node, $IDENTITY_bladerhel, "/etc/init.d/ext_sshd restart", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Stopping ext_sshd:/i) {
#notify($ERRORS{'OK'},0,"stopping sshd on $node ");
}
if ($l =~ /Starting ext_sshd:[ OK ]/i) {
notify($ERRORS{'OK'}, 0, "ext_sshd on $node started");
}
} #foreach
notify($ERRORS{'OK'}, 0, "started ext_sshd on $node");
return 1;
} ## end if (run_ssh_command($node, $IDENTITY_bladerhel...
else {
notify($ERRORS{'CRITICAL'}, 0, "failed to add $allowuserstring to external_sshd_config on $node ");
return 0;
}
} ## end if ($grpflag)
else {
#single user proceed
my @sshcmd = run_ssh_command($node, $IDENTITY_bladerhel, $useradd_string, "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /user $user exists/) {
notify($ERRORS{'OK'}, 0, "detected user already has account, deleting");
#FIXME - if type or project is not HPC related.
if (del_user($node, $user, "blade", $os)) {
notify($ERRORS{'OK'}, 0, "$user deleted");
}
if (run_ssh_command($node, $IDENTITY_bladerhel, $useradd_string, "root")) {
notify($ERRORS{'OK'}, 0, "user $user added");
}
} ## end if ($l =~ /user $user exists/)
} ## end foreach my $l (@{$sshcmd[1]})
if (_is_user_added($node, $user, "blade", $os)) {
notify($ERRORS{'OK'}, 0, "added user account $user to $node");
undef @sshcmd;
my $cmd = "echo \"AllowUsers $user\" >> /etc/ssh/external_sshd_config";
if (run_ssh_command($node, $IDENTITY_bladerhel, $cmd, "root")) {
notify($ERRORS{'DEBUG'}, 0, "added AllowUsers $user to external_sshd_config");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "failed to add AllowUsers $user to external_sshd_config");
return 0;
}
undef @sshcmd;
@sshcmd = run_ssh_command($node, $IDENTITY_bladerhel, "/etc/init.d/ext_sshd restart", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Stopping ext_sshd:/i) {
#notify($ERRORS{'OK'},0,"stopping sshd on $node ");
}
if ($l =~ /Starting ext_sshd:[ OK ]/i) {
notify($ERRORS{'OK'}, 0, "ext_sshd on $node started");
}
} #foreach
notify($ERRORS{'OK'}, 0, "started ext_sshd on $node");
return 1;
} ## end if (_is_user_added($node, $user, "blade", ...
else {
notify($ERRORS{'CRITICAL'}, 0, "PROBLEM added user $user to $node @{ $sshcmd[1] }");
return 0;
}
# add user to external_sshd config
} # grpflag true
} # rhel
else {
return 0;
}
} ## end sub add_user
#/////////////////////////////////////////////////////////////////////////////
=head2 add_users_by_group
Parameters : computer_short_name,pw,computer_hostname,OSname,%usergrpmembers
Returns : 1 sucess,0 failed
Description : adds a group users to remote machine
=cut
sub add_users_by_group {
my ($computer_short_name, $passwd, $computer_hostname, $OSname, %usermembers) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "computer_short_name is not defined") if (!(defined($computer_short_name)));
notify($ERRORS{'WARNING'}, 0, "pw is not defined") if (!(defined($passwd)));
notify($ERRORS{'WARNING'}, 0, "computer_hostname is not defined") if (!(defined($computer_hostname)));
notify($ERRORS{'WARNING'}, 0, "OSname is not defined") if (!(defined($OSname)));
#make sure we have something in our hash
if (scalar keys %usermembers < 2) {
notify($ERRORS{'WARNING'}, 0, "the supplied user group had 1 or less member");
}
foreach my $user (keys %usermembers) {
if ($OSname =~ /win|vmwarewin/) {
my $cmd = "cscript.exe //Nologo add_user.vbs $usermembers{$user}{username} $passwd";
my @cmdout = run_ssh_command($computer_short_name, $IDENTITY_wxp, $cmd, "root");
foreach my $line (@{$cmdout[1]}) {
#check for errors
notify($ERRORS{'DEBUG'}, 0, "return status $cmdout[0] output= $line");
}
}
} ## end foreach my $user (keys %usermembers)
return 1;
} ## end sub add_users_by_group
#/////////////////////////////////////////////////////////////////////////////
=head2 del_user
Parameters : $node, $user, $type, $osname
Returns : 1 success 0 failure
Description : removes user account from specificed node
=cut
sub del_user {
my ($node, $user, $type, $osname) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "user is not defined") if (!(defined($user)));
notify($ERRORS{'WARNING'}, 0, "type is not defined") if (!(defined($type)));
notify($ERRORS{'WARNING'}, 0, "osname is not defined") if (!(defined($osname)));
#set variables to use
my $cmd;
my @sshcmd;
if ($type =~ /blade|virtualmachine/) {
#my $os = _machine_os($node);
if ($osname =~ /wxp|win|vmware/) {
$cmd = "cscript.exe //Nologo del_user.vbs $user";
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, $cmd, "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /The filename, directory name, or volume label syntax is incorrect/) {
# user account not listed. no need to confirm
return 1;
}
}
notify($ERRORS{'DEBUG'}, 0, "cscript.exe //Nologo del_user.vbs $user produced output: " . join("\n", @{$sshcmd[1]}));
if (!(_is_user_added($node, $user, $type, $osname))) {
return 1;
}
else {
return 0;
}
#make sure user home dir is deleted
undef $cmd;
undef @sshcmd;
$cmd = "/bin/rm -rf /cygdrive/c/Documents\ and\ Settings/$user";
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, $cmd, "root");
foreach my $l (@{$sshcmd[1]}) {
#shouldn't have any output - report if necessary
notify($ERRORS{'DEBUG'}, 0, "$cmd produced output $l");
}
} ## end if ($osname =~ /wxp|win|vmware/)
elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|esx[0-9]+)/) {
#remove user from machine
my @file;
my $l;
undef $cmd;
undef @sshcmd;
# do not currently use userdel -r will affect HPC user storage for HPC installs
$cmd = "/usr/sbin/userdel $user";
@sshcmd = run_ssh_command($node, $IDENTITY_bladerhel, $cmd, "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /currently logged in/) {
notify($ERRORS{'WARNING'}, 0, "$user currently logged in returning 0");
return 0;
}
}
#user successfully deleted
my $path1 = "$node:/etc/ssh/external_sshd_config";
my $path2 = "/tmp/$node.sshd";
if (run_scp_command($path1, $path2, $IDENTITY_bladerhel)) {
notify($ERRORS{'DEBUG'}, 0, "scp success retrieved $path1");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve $path1");
return 0;
}
#remove from sshd
if (open(SSHDCFG, "/tmp/$node.sshd")) {
@file = <SSHDCFG>;
close SSHDCFG;
foreach $l (@file) {
$l = "" if ($l =~ /AllowUsers/);
}
if (open(SCP, ">/tmp/$node.sshd")) {
print SCP @file;
close SCP;
}
undef $path1;
undef $path2;
$path1 = "/tmp/$node.sshd";
$path2 = "$node:/etc/ssh/external_sshd_config";
if (run_scp_command($path1, $path2, $IDENTITY_bladerhel)) {
notify($ERRORS{'DEBUG'}, 0, "scp success copied $path1 to $path2");
unlink $path1;
#turn off external sshd
if (run_ssh_command($node, $IDENTITY_bladerhel, "/etc/init.d/ext_sshd stop")) {
notify($ERRORS{'DEBUG'}, 0, "turned off ext_sshd on $node");
}
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to copy $path1 to $path2");
return 0;
}
} ## end if (open(SSHDCFG, "/tmp/$node.sshd"))
} ## end elsif ($osname =~ /^(rh[0-9]image|rhel[0-9]|fc[0-9]image|rhfc[0-9]|rhas[0-9]|esx[0-9]+)/) [ if ($osname =~ /wxp|win|vmware/)
else {
notify($ERRORS{'WARNING'}, 0, "$osname does not exist ");
return 0;
}
} ## end if ($type =~ /blade|virtualmachine/)
} ## end sub del_user
#/////////////////////////////////////////////////////////////////////////////
=head2 disablesshd
Parameters : $hostname, $unityname, $remoteIP, $state, $osname, $log
Returns : 1 success 0 failure
Description : using ssh identity key log into remote lab machine
and set flag for vclclientd to disable sshd for remote user
=cut
sub disablesshd {
my ($hostname, $unityname, $remoteIP, $state, $osname, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!(defined($log)));
notify($ERRORS{'WARNING'}, $log, "hostname is not defined") if (!(defined($hostname)));
notify($ERRORS{'WARNING'}, $log, "unityname is not defined") if (!(defined($unityname)));
notify($ERRORS{'WARNING'}, $log, "remoteIP is not defined") if (!(defined($remoteIP)));
notify($ERRORS{'WARNING'}, $log, "state is not defined") if (!(defined($state)));
notify($ERRORS{'WARNING'}, $log, "osname is not defined") if (!(defined($osname)));
if (!(defined($remoteIP))) {
$remoteIP = "127.0.0.1";
}
my @lines;
my $l;
my $identity;
if ($osname =~ /sun4x_/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($osname =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
#if all else fails
$identity = $IDENTITY_solaris_lab;
}
# create clientdata file
my $clientdata = "/tmp/clientdata.$hostname";
if (open(CLIENTDATA, ">$clientdata")) {
print CLIENTDATA "$state\n";
print CLIENTDATA "$unityname\n";
print CLIENTDATA "$remoteIP\n";
close CLIENTDATA;
# scp to hostname
my $target = "vclstaff\@$hostname:/home/vclstaff/clientdata";
if (run_scp_command($clientdata, $target, $identity, "24")) {
notify($ERRORS{'OK'}, $log, "Success copied $clientdata to $target");
unlink($clientdata);
# send flag to activate changes
my @sshcmd = run_ssh_command($hostname, $identity, "echo 1 > /home/vclstaff/flag", "vclstaff", "24");
notify($ERRORS{'OK'}, $log, "setting flag to 1 on $hostname");
my $nmapchecks = 0;
# return nmap check
NMAPPORT:
if (!(nmap_port($hostname, 22))) {
return 1;
}
else {
if ($nmapchecks < 5) {
$nmapchecks++;
sleep 1;
notify($ERRORS{'OK'}, $log, "port 22 not closed yet calling NMAPPORT code block");
goto NMAPPORT;
}
else {
notify($ERRORS{'WARNING'}, $log, "port 22 never closed on client $hostname");
return 0;
}
} ## end else [ if (!(nmap_port($hostname, 22)))
} ## end if (run_scp_command($clientdata, $target, ...
else {
notify($ERRORS{'OK'}, $log, "could not copy src=$clientdata to target=$target");
return 0;
}
} ## end if (open(CLIENTDATA, ">$clientdata"))
else {
notify($ERRORS{'WARNING'}, $log, "could not open /tmp/clientdata.$hostname $! ");
return 0;
}
} ## end sub disablesshd
#/////////////////////////////////////////////////////////////////////////////
=head2 enablesshd
Parameters : $hostname, $unityname, $remoteIP, $state, $osname, $log
Returns : 1 success 0 failure
Description : using ssh identity key log into remote lab machine
and set flag for vclclientd to enable ssh access for remote user
=cut
sub enablesshd {
my ($hostname, $unityname, $remoteIP, $state, $osname, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!(defined($log)));
notify($ERRORS{'WARNING'}, $log, "hostname is not defined") if (!(defined($hostname)));
notify($ERRORS{'WARNING'}, $log, "unityname is not defined") if (!(defined($unityname)));
notify($ERRORS{'WARNING'}, $log, "remoteIP is not defined") if (!(defined($remoteIP)));
notify($ERRORS{'WARNING'}, $log, "state is not defined") if (!(defined($state)));
notify($ERRORS{'WARNING'}, $log, "osname is not defined") if (!(defined($osname)));
my $identity;
if ($osname =~ /sun4x_/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($osname =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
# create clientdata file
my $clientdata = "/tmp/clientdata.$hostname";
if (open(CLIENTDATA, ">$clientdata")) {
print CLIENTDATA "$state\n";
print CLIENTDATA "$unityname\n";
print CLIENTDATA "$remoteIP\n";
close CLIENTDATA;
# scp to hostname
my $target = "vclstaff\@$hostname:/home/vclstaff/clientdata";
if (run_scp_command($clientdata, $target, $identity, "24")) {
notify($ERRORS{'OK'}, $log, "Success copied $clientdata to $target");
unlink($clientdata);
# send flag to activate changes
my @sshcmd = run_ssh_command($hostname, $identity, "echo 1 > /home/vclstaff/flag", "vclstaff", "24");
notify($ERRORS{'OK'}, $log, "setting flag to 1 on $hostname");
my $nmapchecks = 0;
# return nmap check
NMAPPORT:
if (nmap_port($hostname, 22)) {
notify($ERRORS{'OK'}, $log, "sshd opened");
return 1;
}
else {
if ($nmapchecks < 6) {
$nmapchecks++;
sleep 1;
#notify($ERRORS{'OK'},0,"calling NMAPPORT code block");
goto NMAPPORT;
}
else {
notify($ERRORS{'WARNING'}, $log, "port 22 never opened on client $hostname");
return 0;
}
} ## end else [ if (nmap_port($hostname, 22))
} ## end if (run_scp_command($clientdata, $target, ...
else {
notify($ERRORS{'WARNING'}, $log, "could not copy src=$clientdata to target= $target");
return 0;
}
} ## end if (open(CLIENTDATA, ">$clientdata"))
else {
notify($ERRORS{'WARNING'}, $log, "could not open /tmp/clientdata.$hostname $! ");
return 0;
}
} ## end sub enablesshd
#/////////////////////////////////////////////////////////////////////////////
=head2 nmap_port
Parameters : $hostname, $port
Returns : 1 open 0 closed
Description : use nmap port scanning tool to determine if port is open
=cut
sub nmap_port {
my ($hostname, $port) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "hostname is not defined") if (!(defined($hostname)));
notify($ERRORS{'WARNING'}, 0, "port is not defined") if (!(defined($port)));
my @file;
my $l;
if (open(NMAP, "/usr/bin/nmap $hostname -P0 -p $port -T Aggressive |")) {
@file = <NMAP>;
close NMAP;
foreach $l (@file) {
if ($l =~ /open/) {
return 1;
}
elsif ($l =~ /is: closed/) {
return 0;
}
elsif ($l =~ /Host seems down/) {
return 0;
}
elsif ($l =~ /filtered/) {
return 0;
}
} ## end foreach $l (@file)
} ## end if (open(NMAP, "/usr/bin/nmap $hostname -P0 -p $port -T Aggressive |"...
else {
notify($ERRORS{'WARNING'}, 0, "problems executing /usr/bin/nmap $hostname -P0 -p $port $!");
return 0;
}
return 0;
} ## end sub nmap_port
#/////////////////////////////////////////////////////////////////////////////
=head2 _pingnode
Parameters : $hostname
Returns : 1 pingable 0 not-pingable
Description : using Net::Ping to check if node is pingable
assumes icmp echo is allowed
=cut
sub _pingnode {
my ($hostname) = $_[0];
my $p = Net::Ping->new("icmp");
my $result = $p->ping($hostname, 1);
$p->close();
if (!$result) {
return 0;
}
else {
return 1;
}
} ## end sub _pingnode
#/////////////////////////////////////////////////////////////////////////////
=head2 virtual_status_unix
Parameters : $hostname, $os, $mnOS, $ipaddress, $log
Returns : array of values - pingable,sshd,vclclientd running
Description : runs status check on supplied node
=cut
sub virtual_status_unix {
my ($hostname, $os, $mnOS, $ipaddress, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!(defined($log)));
notify($ERRORS{'WARNING'}, $log, "hostname is not defined") if (!(defined($hostname)));
notify($ERRORS{'WARNING'}, $log, "os is not defined") if (!(defined($os)));
notify($ERRORS{'WARNING'}, $log, "ManagementNode OS is not defined") if (!(defined($mnOS)));
notify($ERRORS{'WARNING'}, $log, "ipaddress is not defined") if (!(defined($ipaddress)));
my @status;
# status[0] = pingable
# status[1] = port 24 accessible
# status[2] = vclclientd running
# status[3] =
my @file;
my $p;
my $osname = lc($^O);
$mnOS = $osname;
notify($ERRORS{'DEBUG'}, $log, "virtual_status_unix MNos= $mnOS");
#is host listed in our local known_hosts file?
if (known_hosts($hostname, $mnOS, $ipaddress)) {
notify($ERRORS{'OK'}, $log, "$hostname pub key added to local known_hosts");
}
else {
notify($ERRORS{'OK'}, $log, "failed to add $hostname pub rsa key to local known_hosts");
}
#is pingable
$status[0] = _pingnode($ipaddress);
#is ssh open on admin port
my @ssh;
my ($n, $identity);
if ($os =~ /sun4x/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($os =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
notify($ERRORS{'OK'}, $log, "os $os set but not something I can handle yet, will attempt the unix identity.");
$identity = $IDENTITY_solaris_lab;
}
$status[1] = 0;
if (check_ssh($ipaddress, 24, $log)) {
my $shortname = $1 if ($hostname =~ /([-_a-zA-Z0-9]*)\./);
$shortname = $hostname if (!defined($shortname));
my @ssh = run_ssh_command($ipaddress, $identity, "echo testing", "vclstaff", 24);
foreach $n (@{$ssh[1]}) {
next if ($n =~ /Warning: Permanently added/);
notify($ERRORS{'OK'}, $log, "$n");
if ($n =~ /testing/) {
$status[1] = 1;
notify($ERRORS{'OK'}, $log, "SUCCESS $ipaddress port 24 is accessible");
}
}
if ($status[1]) {
#is vclclientd running
$status[2] = 0;
my @file = run_ssh_command($ipaddress, $identity, "pgrep vclclient", "vclstaff", 24);
foreach my $f (@{$file[1]}) {
chomp($f);
next if ($f =~ /Warning: Permanently added/);
if ($f =~ /[0-9]+/) {
#notify($ERRORS{'OK'},$log,"SUCCESS vclclientd is running on $hostname");
$status[2] = 1;
}
}
} ## end if ($status[1])
else {
# hrm -p24 is not accessible
# return so caller can try to get another machine
notify($ERRORS{'WARNING'}, $log, "FAILURE $hostname port 24 is NOT accessible ssh output @ssh");
$status[2] = 0;
}
} ## end if (check_ssh($ipaddress, 24, $log))
return @status;
} ## end sub virtual_status_unix
#/////////////////////////////////////////////////////////////////////////////
=head2 getnewdbh
Parameters : none
Returns : 0 failed or database handle
Description : gets a databasehandle
=cut
sub getnewdbh {
#my $caller_trace = get_caller_trace(7, 1);
#notify($ERRORS{'DEBUG'}, 0, "called from: $caller_trace");
my ($database) = @_;
$database = $DATABASE if !$database;
my $dbh;
# Try to use the existing database handle
if (defined $ENV{dbh} && $ENV{dbh} && $ENV{dbh}->ping) {
#notify($ERRORS{'DEBUG'}, 0, "using database handle stored in \$ENV{dbh}");
return $ENV{dbh};
}
elsif (defined $ENV{dbh}) {
notify($ERRORS{'DEBUG'}, 0, "unable to use database handle stored in \$ENV{dbh}");
}
else {
#notify($ERRORS{'DEBUG'}, 0, "\$ENV{dbh} is not defined, creating new database handle");
}
my $attempt = 0;
my $max_attempts = 5;
my $retry_delay = 2;
# Assemble the data source string
my $data_source;
if ($MYSQL_SSL) {
$data_source = "$database:$SERVER;mysql_ssl=1;mysql_ssl_ca_file=$MYSQL_SSL_CERT";
}
else {
$data_source = "$database:$SERVER";
}
# Attempt to connect to the data source and get a database handle object
my $dbi_result;
while (!$dbh && $attempt < $max_attempts) {
$attempt++;
# Attempt to connect
#notify($ERRORS{'DEBUG'}, 0, "attempting to connect to data source: $data_source, user: " . string_to_ascii($WRTUSER) . ", pass: " . string_to_ascii($WRTPASS));
$dbh = DBI->connect(qq{dbi:mysql:$data_source}, $WRTUSER, $WRTPASS, {PrintError => 0});
# Check if connect was successful
if ($dbh && $dbh->ping) {
# Set InactiveDestroy = 1 for all dbh's belonging to child processes
# Set InactiveDestroy = 0 for all dbh's belonging to vcld
if (!defined $ENV{vcld} || !$ENV{vcld}) {
$dbh->{InactiveDestroy} = 1;
}
else {
$dbh->{InactiveDestroy} = 0;
}
# Increment the dbh count environment variable if it is defined
# This is only for development and testing to see how many handles a process creates
$ENV{dbh_count}++ if defined($ENV{dbh_count});
# Store the newly created database handle in an environment variable
# Only store it if $ENV{dbh} is already defined
# It's up to other modules to determine if $ENV{dbh} is defined, they must initialize it
if (defined $ENV{dbh}) {
$ENV{dbh} = $dbh;
notify($ERRORS{'DEBUG'}, 0, "database handle stored in \$ENV{dbh} ($ENV{dbh_count})");
}
return $dbh;
} ## end if ($dbh && $dbh->ping)
# Something went wrong, construct a DBI result string
$dbi_result = "DBI result: ";
if (defined(DBI::err())) {
$dbi_result = "(" . DBI::err() . ")";
}
if (defined(DBI::errstr())) {
$dbi_result .= " " . DBI::errstr();
}
# Check for access denied
if (DBI::err() == 1045 || DBI::errstr() =~ /access denied/i) {
notify($ERRORS{'WARNING'}, 0, "unable to connect to database, $dbi_result");
return 0;
}
# Either connect or ping failed
if ($dbh && !$dbh->ping) {
notify($ERRORS{'DEBUG'}, 0, "database connect succeeded but ping failed, attempt $attempt/$max_attempts, $dbi_result");
$dbh->disconnect;
}
else {
notify($ERRORS{'DEBUG'}, 0, "database connect failed, attempt $attempt/$max_attempts, $dbi_result");
}
notify($ERRORS{'DEBUG'}, 0, "sleeping for $retry_delay seconds");
sleep $retry_delay;
next;
} ## end while (!$dbh && $attempt < $max_attempts)
# Maximum number of attempts was reached
notify($ERRORS{'WARNING'}, 0, "failed to connect to database, attempts made: $attempt/$max_attempts, $dbi_result");
return 0;
} ## end sub getnewdbh
#/////////////////////////////////////////////////////////////////////////////
=head2 notify_via_wall
Parameters : empty
Returns : 0 or 1
Description : talks to user at the console using wall
=cut
sub notify_via_wall {
my ($hostname, $username, $string, $OSname, $type) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "hostname is not defined") if (!(defined($hostname)));
notify($ERRORS{'WARNING'}, 0, "username is not defined") if (!(defined($username)));
notify($ERRORS{'WARNING'}, 0, "string is not defined") if (!(defined($string)));
notify($ERRORS{'WARNING'}, 0, "OSname is not defined") if (!(defined($OSname)));
notify($ERRORS{'WARNING'}, 0, "type is not defined") if (!(defined($type)));
my @ssh;
my $n;
my $identity;
#create file, copy to remote host, then run wall
if (open(TMP, ">/tmp/wall.$hostname")) {
print TMP $string;
close TMP;
}
else {
notify($ERRORS{'WARNING'}, 0, "could not open tmp file $!");
}
if ($type eq "blade") {
#this is only going to be rhel
if (run_scp_command("/tmp/wall.$hostname", "$hostname:/root/wall.txt", $IDENTITY_bladerhel)) {
unlink "/tmp/wall.$hostname";
if (run_ssh_command($hostname, $IDENTITY_bladerhel, " cat /root/wall.txt \| wall; /bin/rm -v /root/wall.txt", "root")) {
notify($ERRORS{'OK'}, 0, "successfully sent wall notification to $hostname");
return 1;
}
}
} ## end if ($type eq "blade")
elsif ($type eq "lab") {
if ($OSname =~ /sun4x_/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($OSname =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
#all else fails
$identity = $IDENTITY_solaris_lab;
}
if (run_scp_command("/tmp/wall.$hostname", "vclstaff\@$hostname:/home/vclstaff/wall.txt", $identity, 24)) {
unlink "/tmp/wall.$hostname";
}
else {
notify($ERRORS{'WARNING'}, 0, "could not scp tmp file for wall notification$!");
}
if ($OSname =~ /sun4x_/) {
if (run_ssh_command($hostname, $identity, "wall -a /home/vclstaff/wall.txt; /bin/rm -v /home/vclstaff/wall.txt", "vclstaff", "24")) {
notify($ERRORS{'OK'}, 0, "successfully sent wall notification to $hostname");
return 1;
}
else {
notify($ERRORS{'OK'}, 0, "wall notification $hostname failed ");
}
}
elsif ($OSname =~ /rhel/) {
if (run_ssh_command($hostname, $identity, "cat /home/vclstaff/wall.txt \| wall ; /bin/rm -v /home/vclstaff/wall.txt", "vclstaff", "24")) {
notify($ERRORS{'OK'}, 0, "successfully sent wall notification to $hostname");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "wall notification $hostname failed ");
}
}
else {
notify($ERRORS{'WARNING'}, 0, "not an OS I can handle, os is $OSname");
}
return 1;
} ## end elsif ($type eq "lab") [ if ($type eq "blade")
} ## end sub notify_via_wall
#/////////////////////////////////////////////////////////////////////////////
=head2 isfilelocked
Parameters : $file - file path
Returns : 0 no or 1 yes
Description : looks for supplied file
appends .lock to the end of supplied file
=cut
sub isfilelocked {
my ($file) = $_[0];
my $lockfile = $file . ".lock";
if (-r $lockfile) {
return 1;
}
else {
return 0;
}
} ## end sub isfilelocked
#/////////////////////////////////////////////////////////////////////////////
=head2 lockfile
Parameters : $file
Returns : 0 failed or 1 success
Description : creates $file.lock
=cut
sub lockfile {
my ($file) = $_[0];
my $lockfile = $file . ".lock";
while (!(-r $lockfile)) {
if (open(LOCK, ">$lockfile")) {
print LOCK "1";
close LOCK;
}
else {
notify($ERRORS{'WARNING'}, 0, "could not create $lockfile $!");
return 0;
}
return 1;
} ## end while (!(-r $lockfile))
} ## end sub lockfile
#/////////////////////////////////////////////////////////////////////////////
=head2 unlockfile
Parameters : $file
Returns : 0 or 1
Description : removes file if exists
=cut
sub unlockfile {
my ($file) = $_[0];
my $lockfile = $file . ".lock";
if (-r $lockfile) {
unlink $lockfile;
}
else {
# no lock file exists
}
return 1;
} ## end sub unlockfile
#/////////////////////////////////////////////////////////////////////////////
=head2 notify_via_msg
Parameters : $node, $user, $message
Returns : 0 or 1
Description : using windows msg.exe cmd writes supplied $message
to windows user console
=cut
sub notify_via_msg {
my ($node, $user, $message) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my $osname = lc($^O);
if ($osname =~ /win/i) {
notify($ERRORS{'OK'}, 0, "notifying from Windows not yet supported\n-----\nTo: $user\nNode: $node\n$message\n-----");
return;
}
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "message is not defined") if (!(defined($message)));
notify($ERRORS{'WARNING'}, 0, "user is not defined") if (!(defined($user)));
# Escape new lines
$message =~ s/\n/ /gs;
$message =~ s/\'/\\\\\\\'/gs;
notify($ERRORS{'DEBUG'}, 0, "message:\n$message");
my $command = "msg $user /TIME:180 '$message'";
if (run_ssh_command($node, $IDENTITY_wxp, $command)) {
notify($ERRORS{'OK'}, 0, "successfully sent message to Windows user $user on $node");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to send message to Windows user $user on $node");
return 0;
}
} ## end sub notify_via_msg
#/////////////////////////////////////////////////////////////////////////////
=head2 getpw
Parameters : length(optional) - if not defined sets to 6
Returns : randomized password
Description : called for standalone accounts and used in randomizing
privileged account passwords
=cut
sub getpw {
my $length = $_[0];
$length = 6 if (!(defined($length)));
my @a = ("A" .. "H", "J" .. "N", "P" .. "Z", "a" .. "k", "m" .. "z", "2" .. "9");
my $b;
srand;
for (1 .. $length) {
$b .= $a[rand(57)];
}
return $b;
} ## end sub getpw
#/////////////////////////////////////////////////////////////////////////////
=head2 changewindowspasswd
Parameters : node, account
Returns : 0 or 1
Description : changes windows password on given node for given account
=cut
sub changewindowspasswd {
# change the privileged account passwords on the blade images
my ($node, $account, $passwd) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "account is not defined") if (!(defined($account)));
#copy setpass.vbs to blade
#set password for root and administrator accounts
#remove setpass.vbs from blade
my @ssh;
my $l;
my @sshcmd;
#if not a predefined password, get one!
if (!(defined($passwd))) {
$passwd = getpw(15);
}
if (run_scp_command("$TOOLS/setpass.vbs", "$node:setpass.vbs", $IDENTITY_wxp)) {
undef @sshcmd;
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, "cscript.exe //Nologo setpass.vbs $account $passwd", "root");
for $l (@{$sshcmd[1]}) {
if ($l =~ /Input Error/) {
notify($ERRORS{'WARNING'}, 0, "$node: could not run setpass.vbs");
return 0;
}
}
if ($account eq "root") {
#must set sshd service password also...
my $cmd = "cmd /c C:\/WINDOWS\/system32\/sc config sshd password= $passwd";
undef @sshcmd;
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, "$cmd", "root");
foreach $l (@{$sshcmd[1]}) {
if ($l =~ /ChangeServiceConfig SUCCESS/) {
notify($ERRORS{'OK'}, 0, "$node: serviceConfig sshd password change success");
}
else {
notify($ERRORS{'OK'}, 0, "$node: serviceConfig $l");
}
}
} ## end if ($account eq "root")
#remove setpass.vbs
if (run_ssh_command($node, $IDENTITY_wxp, "/bin/rm -v setpass.vbs", "root")) {
#good removed setpass.vbs
}
return 1;
} ## end if (run_scp_command("$TOOLS/setpass.vbs", ...
return 0;
} ## end sub changewindowspasswd
#/////////////////////////////////////////////////////////////////////////////
=head2 _killsysprep
Parameters : node
Returns : 0 failed or 1 success
Description : stops ssh initiated sysprep command,
because the the box reboots and the command hangs
=cut
sub _killsysprep {
my $node = $_[0];
if (open(PS, "ps -ef |")) {
notify($ERRORS{'DEBUG'}, 0, "_killsysprep: listing processes sysprep for $node");
my @ps = <PS>;
close(PS);
foreach my $p (@ps) {
if (($p =~ /sysprep.cmd/) && ($p =~ /$node/)) {
notify($ERRORS{'DEBUG'}, 0, "_killsysprep: found sysprep.cmd on $node");
if ($p =~ /(root)\s+([0-9]*)/) {
notify($ERRORS{'DEBUG'}, 0, "_killsysprep: located pid $2");
if (open(KILLIT, "kill -9 $2 |")) {
close(KILLIT);
notify($ERRORS{'OK'}, 0, "killed -9 $2 : $p");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "could not execute kill -9 $!");
}
} ## end if ($p =~ /(root)\s+([0-9]*)/)
} ## end if (($p =~ /sysprep.cmd/) && ($p =~ /$node/...
} ## end foreach my $p (@ps)
} ## end if (open(PS, "ps -ef |"))
else {
notify($ERRORS{'WARNING'}, 0, "could not execute ps $!");
}
return 1;
} ## end sub _killsysprep
#/////////////////////////////////////////////////////////////////////////////
=head2 remotedesktopport
Parameters : node,state,remoteaddress
Returns : 0 failed or 1 success
Description : routine to enable or disable remotedesktop port on xp blades
only currently works with windows XP service pack 2
=cut
sub remotedesktopport {
my ($node, $state, $remoteaddress) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'CRITICAL'}, 0, "$node is not defined") if (!(defined($node)));
notify($ERRORS{'CRITICAL'}, 0, "$state is not defined") if (!(defined($state)));
#machine must have the ability to edit firewall service using netsh firewall set service...
my @list;
my $RDopen = 0;
my @sshcmd = run_ssh_command($node, $IDENTITY_wxp, "netsh firewall show state", "root");
if (!($sshcmd[0])) {
#notify($ERRORS{'WARNING'}, 0, "failed to run netsh firewall show state on $node");
}
for my $l (@{$sshcmd[1]}) {
if ($l =~ /The following command was not found: firewall show/) {
notify($ERRORS{'OK'}, 0, "firewall support is not available on $node returning true");
return 1;
}
if ($l =~ /3389/) {
#it's open
$RDopen = 1;
}
} ## end for my $l (@{$sshcmd[1]})
if ($state eq "ENABLE") {
my ($netsh, $breakdown);
if (defined($remoteaddress)) {
# if(open(HOST,"/usr/bin/host $remoteaddress 2>&1 |")){
# my @host =<HOST>;
# close(HOST);
# foreach my $h (@host) {
# #sas environment users make http reservation through load-balanced set of outgoing servers but
# # connection is attempted through a nat server with different address
# # this could be the case at other locations as well
# $breakdown=1 if($h =~ /sas.com/);
# }
# }
if (!($remoteaddress)) {
#should really check if a valid address
#it's defined but equals 0 just open
#no address was provided, just open it
#$netsh = "netsh firewall set service REMOTEDESKTOP ENABLE";
$netsh = "netsh firewall set portopening TCP 3389 RDP enable ALL";
notify($ERRORS{'OK'}, 0, "no address provided, $node remotedesktop port enable executing");
}
else {
$breakdown = 1;
if ($breakdown) {
#break down address
my ($q1, $q2, $q3, $q4) = split(/[.]/, $remoteaddress);
if ($q1) {
$remoteaddress = "$q1.$q2.0.0/255.255.0.0";
notify($ERRORS{'OK'}, 0, "enabling broad scope address $remoteaddress");
$netsh = "netsh firewall set portopening TCP 3389 RDP enable CUSTOM $remoteaddress";
}
else {
notify($ERRORS{'WARNING'}, 0, "detected sas.com but could not break appart $remoteaddress, leaving empty");
$netsh = "netsh firewall set portopening TCP 3389 RDP enable ALL";
}
} ## end if ($breakdown)
else {
$netsh = "netsh firewall set portopening TCP 3389 RDP enable CUSTOM $remoteaddress";
#$netsh = "netsh firewall set service REMOTEDESKTOP ENABLE CUSTOM $remoteaddress";
notify($ERRORS{'OK'}, 0, "$node remotedesktop port enable custom address $remoteaddress executing");
}
} ## end else [ if (!($remoteaddress))
} ## end if (defined($remoteaddress))
else {
#no address was provided, just open it
#$netsh = "netsh firewall set service REMOTEDESKTOP ENABLE";
$netsh = "netsh firewall set portopening TCP 3389 RDP enable ALL";
notify($ERRORS{'OK'}, 0, "no address provided, $node remotedesktop port enable executing");
}
my $RDopen = 0;
my @enable = run_ssh_command($node, $IDENTITY_wxp, $netsh, "root");
foreach my $e (@{$enable[1]}) {
if ($e =~ /Ok/i) {
notify($ERRORS{'DEBUG'}, 0, "netsh command $netsh executed ");
}
}
#dbl check
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, "netsh firewall show state", "root");
for my $l (@{$sshcmd[1]}) {
$RDopen = 1 if ($l =~ /3389/);
}
if ($RDopen) {
notify($ERRORS{'OK'}, 0, "$node remotedesktop port opened");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "$node remotedesktop port not opened");
return 0;
}
} ## end if ($state eq "ENABLE")
if ($state eq "DISABLE") {
if ($RDopen) {
$RDopen = 0;
#Disable it
undef @sshcmd;
if (run_ssh_command($node, $IDENTITY_wxp, "netsh firewall set service REMOTEDESKTOP DISABLE", "root")) {
notify($ERRORS{'OK'}, 0, "$node remotedesktop port disabled");
}
#dbl check
undef @sshcmd;
@sshcmd = run_ssh_command($node, $IDENTITY_wxp, "netsh firewall show state", "root");
if (!@sshcmd) {
notify($ERRORS{'WARNING'}, 0, "failed to run netsh firewall show state on $node");
}
for my $l (@{$sshcmd[1]}) {
$RDopen = 1 if ($l =~ /3389/);
}
} ## end if ($RDopen)
#is it closed or open
if ($RDopen) {
notify($ERRORS{'OK'}, 0, "$node remotedesktop port still open");
return 0;
}
else {
notify($ERRORS{'OK'}, 0, "$node remotedesktop port closed");
return 1;
}
} ## end if ($state eq "DISABLE")
} ## end sub remotedesktopport
#/////////////////////////////////////////////////////////////////////////////
=head2 hostname
Parameters : NA
Returns : hostname of this machine
Description : attempts to check local hostname using hostname cmd
if global FQDN is set the routine returns this instead
=cut
sub hostname {
my ($package, $filename, $line, $sub) = caller(0);
my @host;
my $h;
#hack
my $osname = lc($^O);
if ($osname eq 'linux') {
if ($FQDN) {
@host = ($FQDN, "linux");
return @host;
}
if (open(HOST, "/bin/hostname -f 2>&1 |")) {
@host = <HOST>;
close(HOST);
foreach $h (@host) {
if ($h =~ /([-a-z0-9]*)([.a-z]*)/) {
chomp($h);
if ($h !~ /ncsu.edu/) {
#hack
#$h .= ".hpc.ncsu.edu";
}
@host = ($h, "linux");
return @host;
}
} ## end foreach $h (@host)
} ## end if (open(HOST, "/bin/hostname -f 2>&1 |"))
else {
notify($ERRORS{'CRITICAL'}, 0, "can't $!");
return 0;
}
} ## end if ($osname eq 'linux')
elsif ($osname eq 'solaris') {
if ($FQDN) {
@host = ($FQDN, "linux");
return @host;
}
if (open(NODENAME, "< /etc/nodename")) {
@host = <NODENAME>;
close(NODENAME);
foreach $h (@host) {
if ($h =~ /([-a-z0-9]*)([.a-z]*)/) {
chomp($h);
my @host = ($h, "solaris");
return @host;
}
}
} ## end if (open(NODENAME, "< /etc/nodename"))
else {
notify($ERRORS{'CRITICAL'}, 0, "can't open /etc/nodename $!");
return 0;
}
} ## end elsif ($osname eq 'solaris') [ if ($osname eq 'linux')
elsif ($osname eq 'mswin32') {
if ($FQDN) {
@host = ($FQDN, "windows");
return @host;
}
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unknown OS type: $osname");
return 0;
}
return 0;
} ## end sub hostname
#/////////////////////////////////////////////////////////////////////////////
=head2 known_hosts
Parameters : $node , management OS, $ipaddress
Returns : 0 or 1
Description : check for or add nodenames public rsa key to local known_hosts file
=cut
sub known_hosts {
my ($node, $mnOS, $ipaddress) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'CRITICAL'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'CRITICAL'}, 0, "mnOS is not defined") if (!(defined($mnOS)));
notify($ERRORS{'CRITICAL'}, 0, "ipaddress is not defined") if (!(defined($ipaddress)));
my ($known_hosts, $existed, $ssh_keyscan, $port);
#set up dependiences
if ($mnOS eq "solaris") {
$known_hosts = "/.ssh/known_hosts";
$ssh_keyscan = "/local/openssh/bin/ssh-keyscan";
$port = 24;
}
elsif ($mnOS eq "linux") {
$known_hosts = "/root/.ssh/known_hosts";
$ssh_keyscan = "/usr/bin/ssh-keyscan";
$port = 24;
}
else {
notify($ERRORS{'WARNING'}, 0, "unsupported management node OS: $mnOS");
return 0;
}
#remove key
my @known_hosts_file;
if (open(KNOWNHOSTS, "< $known_hosts")) {
@known_hosts_file = <KNOWNHOSTS>;
close(KNOWNHOSTS);
}
else {
notify($ERRORS{'WARNING'}, 0, "could not read $known_hosts $!");
}
foreach my $l (@known_hosts_file) {
if ($l =~ /$node|$ipaddress/) {
$l = "";
$existed = 1;
}
}
#write back
if ($existed) {
if (open(KNOWNHOSTS, ">$known_hosts")) {
print KNOWNHOSTS @known_hosts_file;
close(KNOWNHOSTS);
}
else {
notify($ERRORS{'WARNING'}, 0, "could not write to $known_hosts file $!");
}
}
#proceed to get public rsa key
#notify($ERRORS{'OK'},0,"executing $ssh_keyscan -t rsa -p $port $node >> $known_hosts");
if (open(KEYSCAN, "$ssh_keyscan -t rsa -p $port $node >> $known_hosts 2>&1|")) {
my @ret = <KEYSCAN>;
close(KEYSCAN);
foreach my $r (@ret) {
notify($ERRORS{'OK'}, 0, "$r");
return 0 if ($r =~ /Name or service not known/);
}
return 1;
} ## end if (open(KEYSCAN, "$ssh_keyscan -t rsa -p $port $node >> $known_hosts 2>&1|"...
else {
notify($ERRORS{'WARNING'}, 0, "could not execute append of $node public key to $known_hosts file $!");
return 0;
}
} ## end sub known_hosts
#/////////////////////////////////////////////////////////////////////////////
=head2 changelinuxpassword
Parameters : $node, $account, $passwd
Returns : 0 or 1
Description : changes linux root password on stock blade installs
=cut
sub changelinuxpassword {
# change the privileged account passwords on the blade images
my ($node, $account, $passwd) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, 0, "account is not defined") if (!(defined($account)));
#set password for root and administrator accounts
#remove setpass.vbs from blade
my @ssh;
my $l;
if ($account eq "root") {
#if not a predefined password, get one!
$passwd = getpw(15) if (!(defined($passwd)));
notify($ERRORS{'OK'}, 0, "password for $node is $passwd");
if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |")) {
$passwd = <OPENSSL>;
chomp $passwd;
close(OPENSSL);
if ($passwd =~ /command not found/) {
notify($ERRORS{'CRITICAL'}, 0, "failed $passwd ");
return 0;
}
my $tmpfile = "/tmp/shadow.$node";
if (open(TMP, ">$tmpfile")) {
print TMP "$account:$passwd:13061:0:99999:7:::\n";
close(TMP);
if (run_ssh_command($node, $IDENTITY_bladerhel, "cat /etc/shadow \|grep -v $account >> $tmpfile", "root")) {
notify($ERRORS{'DEBUG'}, 0, "collected /etc/shadow file from $node");
if (run_scp_command($tmpfile, "$node:/etc/shadow", $IDENTITY_bladerhel)) {
notify($ERRORS{'DEBUG'}, 0, "copied updated /etc/shadow file to $node");
if (run_ssh_command($node, $IDENTITY_bladerhel, "chmod 600 /etc/shadow", "root")) {
notify($ERRORS{'DEBUG'}, 0, "updated permissions to 600 on /etc/shadow file on $node");
unlink $tmpfile;
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to change file permissions on $node /etc/shadow");
unlink $tmpfile;
return 0;
}
} ## end if (run_scp_command($tmpfile, "$node:/etc/shadow"...
else {
notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
}
} ## end if (run_ssh_command($node, $IDENTITY_bladerhel...
else {
notify($ERRORS{'WARNING'}, 0, "failed to copy contents of shadow file on $node ");
unlink $tmpfile;
return 0;
}
} ## end if (open(TMP, ">$tmpfile"))
else {
notify($ERRORS{'OK'}, 0, "failed could open $tmpfile $!");
}
} ## end if (open(OPENSSL, "openssl passwd -1 $passwd 2>&1 |"...
return 0;
} ## end if ($account eq "root")
else {
#actual user
#push it through passwd cmd stdin
my @sshcmd = run_ssh_command($node, $IDENTITY_bladerhel, "echo $passwd \| /usr/bin/passwd -f $account --stdin", "root");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /authentication tokens updated successfully/) {
notify($ERRORS{'OK'}, 0, "successfully changed local password account $account");
return 1;
}
}
} ## end else [ if ($account eq "root")
} ## end sub changelinuxpassword
#/////////////////////////////////////////////////////////////////////////////
=head2 getanothermachine
Parameters : useid,imagename
Returns : available machine if successful or 0 on failure
Description : NOT COMPLETED - to be used in case of a failure on reservation,
if the box is reloading or failed in some fashion
using rpc call to php on webserver
=cut
sub getanothermachine {
my ($userid, $imageid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "userid is not defined") if (!(defined($userid)));
notify($ERRORS{'WARNING'}, 0, "imagid is not defined") if (!(defined($imageid)));
my $function = "getUserResources";
#Parameters for getUserResources function :
#$userprivs - array of privileges to look for (such as imageAdmin, imageCheckOut, etc); don't include 'block' or 'cascade'
#$resourceprivs- array of privileges to look for (such as available, administer, manageGroup); don't include 'block' or 'cascade'
#$onlygroups - (optional) if 1, return the resource groups instead of the resources
#$includedeleted - (optional) included deleted resources if 1, don't if 0
#$userid - (optional) id from the user table, if not given, use the id of the currently logged in user
my $arg1 = "imageAdmin:imageCheckOut";
my $arg2 = "available:";
my $arg3 = 0;
my $arg4 = 0;
my $arg5 = $userid;
eval {
my $doc = get("https://vcl.ncsu.edu/scheduling/index.php?mode=vcldquery&key=$VCLDRPCQUERYKEY&query=$function,$arg1,$arg2,$arg3,$arg4,$arg5");
}
} ## end sub getanothermachine
#/////////////////////////////////////////////////////////////////////////////
=head2 getusergroupmembers
Parameters : usergroupid
Returns : array of user group memebers
Description : queries database and collects user members of supplied usergroupid
=cut
sub getusergroupmembers {
my $usergroupid = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "usergroupid is not defined") if (!(defined($usergroupid)));
if (!(defined($usergroupid))) {
return ();
}
my $select_statement = "
SELECT
user.unityid,
user.uid
FROM
user,
usergroupmembers
WHERE
user.id = usergroupmembers.userid
AND usergroupmembers.usergroupid = '$usergroupid'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "no data returned for usergroupid $usergroupid returning empty lists");
return ();
}
my %hash;
my (@retarray);
for (@selected_rows) {
my %hash = %{$_};
push(@retarray, "$hash{unityid}:$hash{uid}");
}
return @retarray;
} ## end sub getusergroupmembers
#/////////////////////////////////////////////////////////////////////////////
=head2 getimagesize
Parameters : imagename
Returns : 0 failure or size of image
Description : in size of Kilobytes
=cut
sub getimagesize {
my $imagename = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "imagename is not defined") if (!(defined($imagename)));
if (!(defined($imagename))) {
return 0;
}
my $IMAGEREPOSITORY;
if ($imagename =~ /^(win|rh3image)/) {
$IMAGEREPOSITORY = "/install/image/x86";
}
elsif ($imagename =~ /^(rh([0-9])image|fc([0-9])image)/) {
$IMAGEREPOSITORY = "/install/$LINUX_IMAGE/x86";
}
elsif ($imagename =~ /^(vmware)/) {
$IMAGEREPOSITORY = "$VMWAREREPOSITORY/$imagename";
}
else {
return 0;
}
#list files in image directory, account for main .gz file and any .gz.00X files
if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |")) {
my @filelist = <FILELIST>;
close(FILELIST);
my $size = 0;
foreach my $f (@filelist) {
if ($f =~ /$imagename.gz|vmdk/) {
my ($presize, $blah) = split(" ", $f);
$size += $presize;
}
}
if ($size == 0) {
#strange imagename not found
return 0;
}
return int($size / 1024);
} ## end if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |"...
return 0;
} ## end sub getimagesize
#/////////////////////////////////////////////////////////////////////////////
=head2 doesimageexists
Parameters : imagename
Returns : 0 or 1
Description : scans our image local image library for requested image
returns 1 if found or 0 if not
attempts to scp image files from peer management nodes
=cut
sub doesimageexists {
my $imagename = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($imagename)));
if (!(defined($imagename))) {
return 0;
}
my ($IMAGEREPOSITORY, $TMPLREPOSITORY, $basetmpl);
if ($imagename =~ /^(win|rh3image)/) {
$IMAGEREPOSITORY = "/install/image/x86";
$TMPLREPOSITORY = "$XCATROOT/install/image/x86";
$basetmpl = "wxp2-base.tmpl";
}
elsif ($imagename =~ /^(rh([0-9])image|fc([0-9])image)/) {
$IMAGEREPOSITORY = "/install/$LINUX_IMAGE/x86";
$TMPLREPOSITORY = "$XCATROOT/install/$LINUX_IMAGE/x86";
$basetmpl = "rhel4-base-v0.tmpl";
}
elsif ($imagename =~ /^rhel([0-9])/) {
$IMAGEREPOSITORY = "$XCATROOT/install/rhas$1/x86";
$TMPLREPOSITORY = "$XCATROOT/install/rhas$1/x86";
$basetmpl = "rhel$1-base-v0.tmpl";
}
elsif ($imagename =~ /^rhfc([0-9])/) {
$IMAGEREPOSITORY = "$XCATROOT/install/rhfc$1/x86";
$TMPLREPOSITORY = "$XCATROOT/install/rhfc$1/x86";
$basetmpl = "rhfc$1-base-v0.tmpl";
}
elsif ($imagename =~ /^esx([0-9]+)/) {
$IMAGEREPOSITORY = "$XCATROOT/install/esx$1/x86";
$TMPLREPOSITORY = "$XCATROOT/install/esx$1/x86";
$basetmpl = "esx$1-base-v0.tmpl";
}
elsif ($imagename =~ /^(vmware)/) {
$IMAGEREPOSITORY = "$VMWAREREPOSITORY";
goto IMAGEREPOSCHK;
}
#does template file exist
if (-e "$TMPLREPOSITORY/$imagename.tmpl") {
#good
notify($ERRORS{'OK'}, 0, "template $imagename.tmpl exists");
}
else {
#try to create it.
if (open(IMAGE, "/bin/cp $TMPLREPOSITORY/$basetmpl $TMPLREPOSITORY/$imagename.tmpl |")) {
my @Images = <IMAGE>;
close(IMAGE);
if (-e "$TMPLREPOSITORY/$imagename.tmpl") {
#good
notify($ERRORS{'OK'}, 0, "template $imagename.tmpl exists");
}
foreach my $i (@Images) {
#if anything could mean failure
if ($i) {
notify($ERRORS{'OK'}, 0, "@Images");
}
}
} ## end if (open(IMAGE, "/bin/cp $TMPLREPOSITORY/$basetmpl $TMPLREPOSITORY/$imagename.tmpl |"...
} ## end else [ if (-e "$TMPLREPOSITORY/$imagename.tmpl")
IMAGEREPOSCHK:
if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |")) {
my @images = <IMAGES>;
close(IMAGES);
foreach my $i (@images) {
if ($i =~ /$imagename/) {
notify($ERRORS{'OK'}, 0, "image $imagename exists");
return 1;
}
}
} ## end if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |"...
notify($ERRORS{'OK'}, 0, "IMAGELIBENABLE= $IMAGELIBENABLE ");
if ($IMAGELIBENABLE) {
#proceed to copy image from other management nodes
notify($ERRORS{'OK'}, 0, "image $IMAGEREPOSITORY/$imagename does NOT exists attempting to pull from other management nodes");
#globals being used - $IMAGELIBENABLE,$IMAGESERVERS,$IMAGELIBUSER,$IMAGELIBKEY
my @serverlist = split(/,/, $IMAGESERVERS);
my $length = @serverlist;
if ($length == 0) {
notify($ERRORS{'CRITICAL'}, 0, "imageservers variable is not listed correctly or does not contain any information");
return 0;
}
foreach my $s (@serverlist) {
#first pass - use my current repository paths
notify($ERRORS{'OK'}, 0, "checking for $imagename on $s");
my @sshcmd = run_ssh_command($s, $IMAGELIBKEY, "ls -1 $IMAGEREPOSITORY", $IMAGELIBUSER);
foreach my $i (@{$sshcmd[1]}) {
if ($i =~ /Permission denied/) {
notify($ERRORS{'CRITICAL'}, 0, "identity key $IMAGELIBKEY not valid for $IMAGELIBUSER @ $s");
}
if ($i =~ /$imagename/) {
notify($ERRORS{'OK'}, 0, "SUCCESS image $imagename exists on $s, attempting to copy");
#great - fetch it
if (run_scp_command("$IMAGELIBUSER\@$s:$IMAGEREPOSITORY/$imagename*", $IMAGEREPOSITORY, $IMAGELIBKEY)) {
#double check our image set has been copied
if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |")) {
my @images = <IMAGES>;
close(IMAGES);
foreach my $i (@images) {
if ($i =~ /$imagename/) {
notify($ERRORS{'OK'}, 0, "image $imagename exists");
return 1;
}
}
} ## end if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |"...
} ## end if (run_scp_command("$IMAGELIBUSER\@$s:$IMAGEREPOSITORY/$imagename*"...
} ## ($i =~ /$imagename/)
} ## foreach my $i
} ## end foreach my $s (@serverlist)
} ## end if ($IMAGELIBENABLE)
else {
notify($ERRORS{'OK'}, 0, "imagelibenable disabled");
}
notify($ERRORS{'WARNING'}, 0, "image $IMAGEREPOSITORY/$imagename does NOT exists");
return 0;
} ## end sub doesimageexists
#/////////////////////////////////////////////////////////////////////////////
=head2 collectsshkeys
Parameters : node
Returns : 0 or 1
Description : collects ssh keys from client
=cut
sub collectsshkeys {
my $node = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
if (!(defined($node))) {
return 0;
}
my ($id, $ipaddress, $type, $hostname, $currentimage, $osname);
#if lab client and OS is linux or solaris fetch ssh keys
#store repective key into computer table for the node
my $dbh = getnewdbh;
#collect a little information about the node.
my $sel = $dbh->prepare("SELECT c.id,c.IPaddress,c.hostname,c.type,o.name,i.name FROM computer c, OS o, image i WHERE c.currentimageid=i.id AND i.OSid=o.id AND c.hostname REGEXP ?") or notify($ERRORS{'WARNING'}, 0, "could not prepare collect computer detail statement" . $dbh->errstr());
$sel->execute($node) or notify($ERRORS{'WARNING'}, 0, "Problem could not execute on computer detail : " . $dbh->errstr);
my $rows = $sel->rows;
$sel->bind_columns(\($id, $ipaddress, $hostname, $type, $osname, $currentimage));
if ($rows) {
if ($sel->fetch) {
print "$id,$ipaddress,$hostname,$type,$osname,$currentimage\n";
}
}
else {
notify($ERRORS{'CRITICAL'}, 0, "no information found in computer table for $node ");
$dbh->disconnect if !defined $ENV{dbh};
return 0;
}
#what identity do we use
my $key;
if ($type =~ /lab/) {
if ($osname =~ /rhel/) {
$key = $IDENTITY_linux_lab;
}
else {
$key = $IDENTITY_solaris_lab;
}
}
#send fetch keys flag to node
my @sshcmd = run_ssh_command($ipaddress, $key, "echo fetch > /home/vclstaff/clientdata; echo 1 > /home/vclstaff/flag", "vclstaff", "24");
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /Warning|denied|No such/) {
notify($ERRORS{'CRITICAL'}, 0, "node $node ouput @{ $sshcmd[1] }");
}
}
#retrieve the keys
#sleep 6, node flag check is every 5 sec
sleep 6;
my ($loop, $ct) = 0;
undef @sshcmd;
@sshcmd = run_ssh_command($ipaddress, $key, "ls -1", "vclstaff", "24");
foreach my $l (@{$sshcmd[1]}) {
chomp($l);
if ($l =~ /ssh_host/) {
#print "$l\n";
if (!(-d "/tmp/$id")) {
notify($ERRORS{'OK'}, 0, "creating /tmp/$id") if (mkdir("/tmp/$id"));
}
if (run_scp_command("vclstaff\@$ipaddress:/home/vclstaff/$l", "/tmp/$id/$l", $key, "24")) {
$ct++;
}
}
} #foreach
if ($ct < 6) {
notify($ERRORS{'OK'}, 0, "count copied, is less than 6 trying again");
if ($loop > 2) {
notify($ERRORS{'CRITICAL'}, 0, "could not copy 6 ssh keys from $node");
$dbh->disconnect if !defined $ENV{dbh};
return 0;
}
$loop++;
goto COLLECT;
} ## end if ($ct < 6)
#read in key files
my $dsa;
my $dsapub;
my $rsa;
my $rsapub;
my $hostbuffer = "";
my $hostpub;
if (open(DSA, "/tmp/$id/ssh_host_dsa_key")) {
print "slurping dsa_key\n";
#@dsa=<DSA>;
read(DSA, $dsa, 1024);
close(DSA);
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open dsa file $!");
}
if (open(DSAPUB, "/tmp/$id/ssh_host_dsa_key.pub")) {
print "slurping dsa_pub_key\n";
#@dsapub=<DSAPUB>;
read(DSAPUB, $dsapub, 1024);
close(DSAPUB);
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open dsa.pub file $!");
}
if (open(RSA, "/tmp/$id/ssh_host_rsa_key")) {
print "slurping rsa_key\n";
#@rsa=<RSA>;
read(RSA, $rsa, 1024);
close(RSA);
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open rsa file $!");
}
if (open(RSAPUB, "/tmp/$id/ssh_host_rsa_key.pub")) {
print "slurping rsa_pub_key\n";
#@rsapub=<RSAPUB>;
read(RSAPUB, $rsapub, 1024);
close(RSAPUB);
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open rsa.pub file $!");
}
if (open(HOSTPUB, "/tmp/$id/ssh_host_key.pub")) {
print "slurping host_pub_key\n";
#@hostpub=<HOSTPUB>;
read(HOSTPUB, $hostpub, 1024);
close(HOSTPUB);
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open host.pub file $!");
}
#binary file
if (open(HOST, "/tmp/$id/ssh_host_key.pub")) {
print "slurping host_key\n";
binmode(HOST);
my $r = read(HOST, $hostbuffer, 1024);
#@hostbuffer=<HOST>;
close(HOST);
if (defined($r)) {
#print "read $r k chunks on binary file ssh_host_key.pub\n";
#notify($ERRORS{'OK'},0,"read $r k chunks on binary file ssh_host_key.pub");
#print "uploading: $dsa\n $dsapub\n$rsa\n$rsapub\n$hostbuffer\n$hostpub \n $id\n";
}
else {
#print "could not read binary file ssh_host_key.pub\n";
notify($ERRORS{'CRITICAL'}, 0, "could not read binary file ssh_host_key.pub");
}
} ## end if (open(HOST, "/tmp/$id/ssh_host_key.pub"...
else {
notify($ERRORS{'CRITICAL'}, 0, "could not open host binary file $!");
}
#print "uploading: @dsa\n @dsapub\n @rsa\n @rsapub\n $hostbuffer \n,@hostpub \n $id\n";
#upload keys to db
my $update = $dbh->prepare("UPDATE computer SET dsa=?,dsapub=?,rsa=?,rsapub=?,hostpub=? WHERE id=?") or print "could not prepare update key statement node= $node id= $id" . $dbh->errstr();
$update->execute($dsa, $dsapub, $rsa, $rsapub, $hostpub, $id) or print "Problem could not execute on update key statement node= $node id= $id: " . $dbh->errstr;
$dbh->disconnect if !defined $ENV{dbh};
} ## end sub collectsshkeys
#/////////////////////////////////////////////////////////////////////////////
=head2 restoresshkeys
Parameters : node
Returns : 0 or 1
Description : NOT COMPLETED
connects to node and replaces ssh keys with keys stored in db
=cut
sub restoresshkeys {
my $node = $_[0];
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "node is not defined") if (!(defined($node)));
if (!(defined($node))) {
return 0;
}
}
#/////////////////////////////////////////////////////////////////////////////
=head2 notifyviaIM
Parameters : IM type, IM user ID, message string
Returns : 0 or 1
Description : if Jabber enabled - send IM to user
currently only supports jabber
=cut
sub notify_via_IM {
my ($im_type, $im_id, $im_message) = @_;
notify($ERRORS{'WARNING'}, 0, "IM type is not defined") if (!(defined($im_type)));
notify($ERRORS{'WARNING'}, 0, "IM id is not defined") if (!(defined($im_id)));
notify($ERRORS{'WARNING'}, 0, "IM message is not defined") if (!(defined($im_message)));
if ($im_type eq "jabber") {
# Check if jabber functions are disabled on this management node
if ($JABBER) {
notify($ERRORS{'DEBUG'}, 0, "jabber functions are enabled on this management node");
}
else {
notify($ERRORS{'DEBUG'}, 0, "jabber functions are disabled on this management node");
return 1;
}
# Create a jabber client object
my $jabber_client = new Net::Jabber::Client();
if ($jabber_client) {
notify($ERRORS{'DEBUG'}, 0, "jabber client object created");
}
else {
notify($ERRORS{'DEBUG'}, 0, "failed to created jabber client object");
return;
}
# Attempt to connect to the jabber server
my $jabber_connect_result = $jabber_client->Connect(hostname => $jabServer, port => $jabPort);
if (!$jabber_connect_result) {
notify($ERRORS{'DEBUG'}, 0, "connected to jabber server: $jabServer, port: $jabPort, result: $jabber_connect_result");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to connect to jabber server: $jabServer, port: $jabPort, result: $jabber_connect_result");
return;
}
# Attempt to authenticate to jabber
my @jabber_auth_result = $jabber_client->AuthSend(
username => $jabUser,
password => $jabPass,
resource => $jabResource
);
# Check the jabber authentication result
if ($jabber_auth_result[0] && $jabber_auth_result[0] eq "ok") {
notify($ERRORS{'DEBUG'}, 0, "authenticated to jabber server: $jabServer, user: $jabUser, resource: $jabResource");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to authenticate to jabber server: $jabServer, user: $jabUser, resource: $jabResource");
return;
}
# Create jabber message
my $jabber_message = Net::Jabber::Message->new();
$jabber_message->SetMessage(
to => $im_id,
subject => "Notification",
type => "chat",
body => $im_message
);
# Attempt to send the jabber message
my $jabber_send_result = $jabber_client->Send($jabber_message);
if ($jabber_send_result) {
notify($ERRORS{'OK'}, 0, "jabber message sent to $im_id");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to send jabber message to $jabUser");
return;
}
} ## end if ($im_type eq "jabber" && defined $jabberready)
else {
notify($ERRORS{'WARNING'}, 0, "IM type is not supported: $im_type");
return 0;
}
return 1;
} ## end sub notify_via_IM
#/////////////////////////////////////////////////////////////////////////////
=head2 check_uptime
Parameters : $node, $IPaddress, $OSname, $type, $log
Returns : value or 0(failed) + failure message
Description : fetchs uptime of remote node
=cut
sub check_uptime {
my ($node, $IPaddress, $OSname, $type, $log) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$log = 0 if (!(defined($log)));
notify($ERRORS{'WARNING'}, $log, "node is not defined") if (!(defined($node)));
notify($ERRORS{'WARNING'}, $log, "IPaddress is not defined") if (!(defined($IPaddress)));
notify($ERRORS{'WARNING'}, $log, "OSname is not defined") if (!(defined($OSname)));
notify($ERRORS{'WARNING'}, $log, "type is not defined") if (!(defined($type)));
if ($type eq "lab") {
my $identity;
if ($OSname =~ /sun4x/) {
$identity = $IDENTITY_solaris_lab;
}
elsif ($OSname =~ /rhel/) {
$identity = $IDENTITY_linux_lab;
}
else {
return (0, "failure : OSname not match");
}
my @sshcmd = run_ssh_command($node, $identity, "uptime", "vclstaff", "24");
my $l;
foreach $l (@{$sshcmd[1]}) {
if ($l =~ /(\s*\d*:\d*:\d*\s*up\s*)(\d*)(\s*days,)/) {
return $2;
}
if ($l =~ /^(\s*\d*:\d*)(am|pm)(\s*up\s*)(\d*)(\s*day)/) {
return $4;
}
if ($l =~ /(\s*\d*:\d*:\d*\s*up)/) {
return 1;
}
if ($l =~ /password/) {
notify($ERRORS{'WARNING'}, $log, "@{ $sshcmd[1] }");
return (0, $l);
}
} ## end foreach $l (@{$sshcmd[1]})
} ## end if ($type eq "lab")
elsif ($type eq "blade") {
return 0;
}
elsif ($type eq "virtualmachine") {
return 0;
}
} ## end sub check_uptime
#/////////////////////////////////////////////////////////////////////////////
=head2 timefloor15interval
Parameters : time string(optional)
Returns : the nearest 15 minute interval 0,15,30,45 less than the current time and zero seconds
Description :
=cut
sub timefloor15interval {
my $time = $_[0];
# we got nothing set to current time
if (!defined($time)) {
$time = makedatestring;
}
#we got a null timestamp, set it to current time
if ($time =~ /0000-00-00 00:00:00/) {
$time = makedatestring;
}
#format received: year-mon-mday hr:min:sec
my ($vardate, $vartime) = split(/ /, $time);
my ($yr, $mon, $mday) = split(/-/, $vardate);
my ($hr, $min, $sec) = split(/:/, $vartime);
$sec = "0";
if ($min < 15) {
$min = 0;
}
elsif ($min < 30) {
$min = 15;
}
elsif ($min < 45) {
$min = 30;
}
elsif ($min < 60) {
$min = 45;
}
my $datestring = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $yr, $mon, $mday, $hr, $min, $sec);
return $datestring;
} ## end sub timefloor15interval
#/////////////////////////////////////////////////////////////////////////////
=head2 system_monitoring
Parameters : $nodename, $imagename, $action, $type
Returns : 0 or 1
Description : primarily used for ITM -
if windows ITM servicce exist start or stop it
=cut
sub system_monitoring {
my ($nodename, $imagename, $action, $type) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "nodename is not defined") if (!(defined($nodename)));
notify($ERRORS{'WARNING'}, 0, "imagename is not defined") if (!(defined($imagename)));
notify($ERRORS{'WARNING'}, 0, "action is not defined") if (!(defined($action)));
notify($ERRORS{'WARNING'}, 0, "type is not defined") if (!(defined($type)));
my ($identity, $imagetype, $l);
my @out;
if ($imagename =~ /^(win|vmware)/) {
$imagetype = "windows";
$identity = $IDENTITY_wxp;
}
elsif ($imagename =~ /^(rh|fc[0-9]image|esx)/) {
$imagetype = "linux";
$identity = $IDENTITY_bladerhel;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not determin OS for $imagename : $type monitoring on $nodename for $imagename");
return 0;
}
my @sshcmd;
if ($type eq "ITM" && $imagetype eq "windows") {
#check and start monitoring for ITM
my $exists = 0;
@sshcmd = run_ssh_command($nodename, $identity, "cmd /c C:\/WINDOWS\/system32\/sc qc KNTCMA_Primary", "root");
foreach $l (@{$sshcmd[1]}) {
next if ($l =~ /Warning: Permanently added/);
if ($l =~ /The specified service does not exist/) {
#not there skip and return
return 0;
}
if ($l =~ /SERVICE_NAME: KNTCMA_Primary/) {
$exists = 1;
}
} ## end foreach $l (@{$sshcmd[1]})
#preform action
if ($action =~ /start|stop/) {
undef @sshcmd;
@sshcmd = run_ssh_command($nodename, $identity, "cmd /c C:\/WINDOWS\/system32\/sc $action KNTCMA_Primary", "root");
foreach $l (@{$sshcmd[1]}) {
next if ($l =~ /Warning: Permanently added/);
if ($l =~ /SERVICE_NAME: KNTCMA_Primary/) {
return 1;
}
if ($l =~ /The service has not been started/) {
return 1 if ($action eq "stop");
}
if ($l =~ /service is already running/) {
return 1 if ($action eq "start");
}
#can run more checks to determine if it is running, stopped or start|stop pending
#
} ## end foreach $l (@{$sshcmd[1]})
} ## end if ($action =~ /start|stop/)
else {
notify($ERRORS{'CRITICAL'}, 0, "skipping start up, $action not a supported action for ITM service KNTCMA_Primary");
return 0;
}
} ## end if ($type eq "ITM" && $imagetype eq "windows")
elsif ($imagetype eq "linux") {
#TODO - insert code for Linux related monitoring agents
}
return 0;
} ## end sub system_monitoring
#/////////////////////////////////////////////////////////////////////////////
=head2 monitorloading
Parameters : $reservationid, $requestedimagename, $computerid, $nodename, $ert
Returns : 0 or 1
Description : using database loadlog table,
monitor given node for available state
=cut
sub monitorloading {
my ($reservationid, $requestedimagename, $computerid, $nodename, $ert) = @_;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'WARNING'}, 0, "reservationid is not defined") if (!(defined($reservationid)));
notify($ERRORS{'WARNING'}, 0, "requestedimagename is not defined") if (!(defined($requestedimagename)));
notify($ERRORS{'WARNING'}, 0, "computerid is not defined") if (!(defined($computerid)));
notify($ERRORS{'WARNING'}, 0, "nodename is not defined") if (!(defined($nodename)));
notify($ERRORS{'WARNING'}, 0, "ert is not defined") if (!(defined($ert)));
#get start time of this wait period
my $mystarttime = convert_to_epoch_seconds;
my $currentime = 0;
my $mydbhandle = getnewdbh();
my $selhdl = $mydbhandle->prepare(
"SELECT s.loadstatename,c.additionalinfo,c.timestamp
FROM computerloadlog c, computerloadstate s
WHERE s.id = c.loadstateid AND c.loadstateid=s.id AND c.reservationid =? AND c.computerid=?") or notify($ERRORS{'WARNING'}, 0, "could not prepare statement to monitor for available stat" . $mydbhandle->errstr());
my $selhdl2 = $mydbhandle->prepare("SELECT s.name FROM computer c,state s WHERE c.stateid=s.id AND c.id =?") or notify($ERRORS{'WARNING'}, 0, "could not prepare statement check node for available state" . $mydbhandle->errstr());
#get est reload time of image
my $available = 0;
my $stillrunnning = 1;
my $state;
my $s1 = 0;
my $s2 = 0;
my $s3 = 0;
my $s4 = 0;
my $s5 = 0;
my $s6 = 0;
my $s7 = 0;
my $s8 = 0;
my $s1time = 0;
my $s2time = 0;
my $s3time = 0;
my $s4time = 0;
my $s5time = 0;
my $s6time = 0;
my $s7time = 0;
MONITORLOADCHECKS:
$selhdl->execute($reservationid, $computerid) or notify($ERRORS{'WARNING'}, 0, "could not execute statement to monitor for available stat" . $mydbhandle->errstr());
my $rows = $selhdl->rows;
#check state of machine
$selhdl2->execute($computerid) or notify($ERRORS{'WARNING'}, 0, "could not execute statement to check state of blade " . $mydbhandle->errstr());
my $irows = $selhdl2->rows;
notify($ERRORS{'OK'}, 0, "checking if $nodename is available");
if ($irows) {
if (my @irow = $selhdl2->fetchrow_array) {
if ($irow[0] =~ /available/) {
#good machine is available
notify($ERRORS{'OK'}, 0, "good $nodename is now available");
return 1;
}
elsif ($irow[0] =~ /failed/) {
notify($ERRORS{'WARNING'}, 0, "$nodename reported failure");
return 0;
}
} ## end if (my @irow = $selhdl2->fetchrow_array)
} ## end if ($irows)
else {
notify($ERRORS{'WARNING'}, 0, "strange no records found for computerid $computerid $nodename - possible issue with query");
return 0;
}
my @row;
while (@row = $selhdl->fetchrow_array) {
if (!$s1) {
if ($row[0] =~ /loadimage|loadimagevmware/) {
notify($ERRORS{'OK'}, 0, "detected s1");
$s1 = 1;
$s1time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s2) {
if ($row[0] =~ /startload/) {
notify($ERRORS{'OK'}, 0, "detected startload state");
if ($row[1] =~ /$requestedimagename/) {
notify($ERRORS{'OK'}, 0, "good $nodename is loading $requestedimagename");
$s2 = 1;
$s2time = convert_to_epoch_seconds($row[2]);
}
else {
notify($ERRORS{'WARNING'}, 0, "$nodename is not loading desired image");
return 0;
}
} ## end if ($row[0] =~ /startload/)
} ## end if (!$s2)
if (!$s3) {
if ($row[0] =~ /rinstall|transfervm/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename");
$s3 = 1;
$s3time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s4) {
if ($row[0] =~ /xcatstage5|startvm/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename");
$s4 = 1;
$s4time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s5) {
if ($row[0] =~ /bootstate|vmstage1/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename");
$s5 = 1;
$s5time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s6) {
if ($row[0] =~ /xcatround3|vmstage5/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename");
$s6 = 1;
$s6time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s7) {
if ($row[0] =~ /xcatREADY|vmwareready/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename");
$s7 = 1;
$s7time = convert_to_epoch_seconds($row[2]);
}
}
if (!$s8) {
if ($row[0] =~ /loadimagecomplete|nodeready/) {
notify($ERRORS{'OK'}, 0, "detected $row[0] returning to calling process");
$s8 = 1;
#ready to return
return 1;
}
}
if ($row[0] =~ /failed/) {
return 0;
}
} ## end while (@row = $selhdl->fetchrow_array)
notify($ERRORS{'OK'}, 0, "current stages passed s1='$s1' s2='$s2' s3='$s3' s4='$s4' s5='$s5' s6='$s6' s7='$s7' going to sleep 15");
sleep 15;
#prevent infinite loop - check how long we've waited
$currentime = convert_to_epoch_seconds;
my $delta = $currentime - $mystarttime;
#check some state times
#if($s5){
# if(!$s6){
# #how long has it been since $s5 was set
# my $s5diff = ($currentime-$s5time);
# if($s5diff > 5*60){
# #greater than 5 minutes
# notify($ERRORS{'OK'},0,"waited over 5 minutes - $s5diff seconds for stage 6 to complete, returning");
# return 0;
# }
# }
# if(!$s7){
# #how long has it been since $s6 was set
# my $s6diff = $currentime-$s6time;
# if($s6diff > 6*60){
# #greater than 4 minutes
# notify($ERRORS{'OK'},0,"waited over 6 minutes - $s6diff seconds for stage 7 to be reached, returning");
# return 0;
# }
#
# }
# }
if ($delta > ($ert * 60)) {
notify($ERRORS{'OK'}, 0, "waited $delta seconds and we have exceeded our ert of $ert, returning");
#just return at this point - it should have been completed by now
return 0;
}
goto MONITORLOADCHECKS;
} ## end sub monitorloading
#/////////////////////////////////////////////////////////////////////////////
=head2 insertloadlog
Parameters : $resid, $computerid, $loadstatename, $additionalinfo
Returns : 0 or 1
Description : accepts info from processes to update the loadlog table
=cut
sub insertloadlog {
my ($resid, $computerid, $loadstatename, $additionalinfo) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the parameters
if (!(defined($resid))) {
notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, reservation id is not defined");
return 0;
}
elsif (!($resid)) {
notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, reservation id is 0");
return 0;
}
if (!(defined($computerid))) {
notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, computer id is not defined");
return 0;
}
elsif (!($computerid)) {
notify($ERRORS{'CRITICAL'}, 0, "unable to insert into computerloadlog, computer id is 0");
return 0;
}
if (!(defined($additionalinfo)) || !$additionalinfo) {
notify($ERRORS{'WARNING'}, 0, "additionalinfo is either not defined or 0, using 'no additional info'");
$additionalinfo = 'no additional info';
}
my $loadstateid;
if (!(defined($loadstatename)) || !$loadstatename) {
notify($ERRORS{'WARNING'}, 0, "loadstatename is either not defined or 0, using NULL");
$loadstatename = 'NULL';
$loadstateid = 'NULL';
}
else {
# loadstatename was specified as a parameter
# Check if the loadstatename exists in the computerloadstate table
my $select_statement = "
SELECT DISTINCT
computerloadstate.id
FROM
computerloadstate
WHERE
computerloadstate.loadstatename = '$loadstatename'
";
my @selected_rows = database_select($select_statement);
if ((scalar @selected_rows) == 0) {
notify($ERRORS{'WARNING'}, 0, "computerloadstate table entry does not exist: $loadstatename, using NULL");
$loadstateid = 'NULL';
$loadstatename = 'NULL';
}
else {
$loadstateid = $selected_rows[0]{id};
#notify($ERRORS{'DEBUG'}, 0, "computerloadstate id found: id=$loadstateid, name=$loadstatename");
}
} ## end else [ if (!(defined($loadstatename)) || !$loadstatename)
# Escape any single quotes in additionalinfo
$additionalinfo =~ s/\'/\\\'/g;
# Check to make sure the reservation has not been deleted
# The INSERT statement will fail if it has been deleted because of the key constraint on reservationid
if (is_reservation_deleted($resid)) {
notify($ERRORS{'OK'}, 0, "computerloadlog entry not inserted, reservation has been deleted");
return 1;
}
# Assemble the SQL statement
my $insert_loadlog_statement = "
INSERT INTO
computerloadlog
(
reservationid,
computerid,
loadstateid,
timestamp,
additionalinfo
)
VALUES
(
'$resid',
'$computerid',
'$loadstateid',
NOW(),
'$additionalinfo'
)
";
# Execute the insert statement, the return value should be the id of the computerloadlog row that was inserted
my $loadlog_id = database_execute($insert_loadlog_statement);
if ($loadlog_id) {
notify($ERRORS{'OK'}, 0, "inserted computer=$computerid, $loadstatename, $additionalinfo");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to insert entry into computerloadlog table");
return 0;
}
return 1;
} ## end sub insertloadlog
#/////////////////////////////////////////////////////////////////////////////
=head2 checkonprocess
Parameters : $state, $requestid
Returns : 0 or 1
Description : checks the process list to confirm the process for given request is actually running
in case the process dies for some reason
=cut
sub checkonprocess {
my ($request_state_name, $request_id) = @_;
notify($ERRORS{'WARNING'}, 0, "state is not defined") if (!(defined($request_state_name)));
notify($ERRORS{'WARNING'}, 0, "requestid is not defined") if (!(defined($request_id)));
return if (!(defined($request_state_name)));
return if (!(defined($request_id)));
# Use the pgrep utility to find processes matching the state and request ID
if (open(PGREP, "/bin/pgrep -fl '$request_state_name $request_id' 2>&1 |")) {
my @process_list = <PGREP>;
close(PGREP);
notify($ERRORS{'DEBUG'}, 0, "pgrep found " . scalar @process_list . " processes matching state=$request_state_name and request=$request_id");
return scalar @process_list;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to open handle for pgrep process");
return;
}
} ## end sub checkonprocess
#/////////////////////////////////////////////////////////////////////////////
=head2 kill_reservation_process
Parameters : $request_state_name, $reservation_id
Returns : 0 or 1
Description :
=cut
sub kill_reservation_process {
my ($reservation_id) = @_;
notify($ERRORS{'WARNING'}, 0, "reservation id is not defined") if (!(defined($reservation_id)));
return if (!(defined($reservation_id)));
notify($ERRORS{'OK'}, 0, "attempting to kill process for reservation $reservation_id");
# Use the pkill utility to find processes matching the reservation ID
my $pkill_command = "pkill -f ':$reservation_id ' 2>&1";
notify($ERRORS{'DEBUG'}, 0, "executing pkill command: $pkill_command");
my $pkill_output = `$pkill_command`;
my $pkill_exit_status = $?;
# Check the pgrep exit status
if ($pkill_exit_status == 0) {
notify($ERRORS{'DEBUG'}, 0, "reservation $reservation_id process was killed, returning 1");
return 1;
}
elsif ($pkill_exit_status == 1) {
notify($ERRORS{'WARNING'}, 0, "process was not found for reservation $reservation_id, returning 0");
return 0;
}
else {
notify($ERRORS{'WARNING'}, 0, "pkill error occurred, returning undefined, output:\n$pkill_output");
return;
}
} ## end sub kill_reservation_process
#/////////////////////////////////////////////////////////////////////////////
=head2 database_select
Parameters : SQL select statement
Returns : array containing hash references to rows returned
Description : gets information from the database
=cut
sub database_select {
my ($select_statement, $database) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my $dbh;
if (!($dbh = getnewdbh($database))) {
# Try again if first attempt failed
if (!($dbh = getnewdbh($database))) {
notify($ERRORS{'WARNING'}, 0, "unable to obtain database handle, " . DBI::errstr());
return ();
}
}
# Prepare the select statement handle
my $select_handle;
$select_handle = $dbh->prepare($select_statement);
# Check the select statement handle
if (!$select_handle) {
notify($ERRORS{'WARNING'}, 0, "could not prepare select statement, $select_statement, " . $dbh->errstr());
$dbh->disconnect if !defined $ENV{dbh};
return ();
}
# Execute the statement handle
if (!($select_handle->execute())) {
notify($ERRORS{'WARNING'}, 0, "could not execute statement, $select_statement, " . $dbh->errstr());
$select_handle->finish;
$dbh->disconnect if !defined $ENV{dbh};
return ();
}
# Fetch all the rows returned by the select query
# An array reference is created containing hash refs because {} is passed to fetchall_arrayref
my @return_rows = @{$select_handle->fetchall_arrayref({})};
$select_handle->finish;
$dbh->disconnect if !defined $ENV{dbh};
return @return_rows;
} ## end sub database_select
#/////////////////////////////////////////////////////////////////////////////
=head2 database_execute
Parameters : SQL statement
Returns : 1 if successful, 0 if failed
Description : Executes an SQL statement
=cut
sub database_execute {
my ($sql_statement, $database) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my $dbh;
if (!($dbh = getnewdbh($database))) {
# Try again if first attempt failed
if (!($dbh = getnewdbh($database))) {
notify($ERRORS{'WARNING'}, 0, "unable to obtain database handle, " . DBI::errstr());
return;
}
}
# Prepare the statement handle
my $statement_handle = $dbh->prepare($sql_statement);
# Check the statement handle
if (!$statement_handle) {
notify($ERRORS{'WARNING'}, 0, "could not prepare SQL statement, $sql_statement, " . $dbh->errstr());
$dbh->disconnect if !defined $ENV{dbh};
return;
}
# Execute the statement handle
if (!($statement_handle->execute())) {
notify($ERRORS{'WARNING'}, 0, "could not execute SQL statement, $sql_statement, " . $dbh->errstr());
$statement_handle->finish;
$dbh->disconnect if !defined $ENV{dbh};
return;
}
# Get the id of the last inserted record if this is an INSERT statement
if ($sql_statement =~ /insert/i) {
my $sql_insertid = $statement_handle->{'mysql_insertid'};
$statement_handle->finish;
$dbh->disconnect if !defined $ENV{dbh};
return $sql_insertid;
}
else {
$statement_handle->finish;
$dbh->disconnect if !defined $ENV{dbh};
return 1;
}
} ## end sub database_execute
#/////////////////////////////////////////////////////////////////////////////
=head2 get_request_info
Parameters : databasehandle, management node id
Returns : hash0 or 1
Description : gets all reservation related information
=cut
sub get_request_info {
my ($request_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
if (!(defined($request_id))) {
notify($ERRORS{'WARNING'}, 0, "request ID was not specified");
return 0;
}
my $select_statement = "
SELECT DISTINCT
request.id AS request_id,
request.stateid AS request_stateid,
request.userid AS request_userid,
request.laststateid AS request_laststateid,
request.logid AS request_logid,
request.forimaging AS request_forimaging,
request.test AS request_test,
request.preload AS request_preload,
request.start AS request_start,
request.end AS request_end,
request.daterequested AS request_daterequested,
request.datemodified AS request_datemodified,
requeststate.name AS requeststate_name,
requestlaststate.name AS requestlaststate_name,
reservation.id AS reservation_id,
reservation.requestid AS reservation_requestid,
reservation.computerid AS reservation_computerid,
reservation.imageid AS reservation_imageid,
reservation.imagerevisionid AS reservation_imagerevisionid,
reservation.managementnodeid AS reservation_managementnodeid,
reservation.remoteIP AS reservation_remoteIP,
reservation.lastcheck AS reservation_lastcheck,
reservation.pw AS reservation_pw,
image.id AS image_id,
image.name AS image_name,
image.prettyname AS image_prettyname,
image.ownerid AS image_ownerid,
image.deptid AS image_deptid,
image.platformid AS image_platformid,
image.OSid AS image_OSid,
image.imagemetaid AS image_imagemetaid,
image.minram AS image_minram,
image.minprocnumber AS image_minprocnumber,
image.minprocspeed AS image_minprocspeed,
image.minnetwork AS image_minnetwork,
image.maxconcurrent AS image_maxconcurrent,
image.reloadtime AS image_reloadtime,
image.deleted AS image_deleted,
image.test AS image_test,
image.lastupdate AS image_lastupdate,
image.forcheckout AS image_forcheckout,
image.maxinitialtime AS image_maxinitialtime,
image.project AS image_project,
image.size AS image_size,
image.architecture AS image_architecture,
imagerevision.id AS imagerevision_id,
imagerevision.imageid AS imagerevision_imageid,
imagerevision.revision AS imagerevision_revision,
imagerevision.userid AS imagerevision_userid,
imagerevision.datecreated AS imagerevision_datecreated,
imagerevision.deleted AS imagerevision_deleted,
imagerevision.production AS imagerevision_production,
imagerevision.comments AS imagerevision_comments,
imagerevision.imagename AS imagerevision_imagename,
imagedept.name AS imagedept_name,
imagedept.prettyname AS imagedept_prettyname,
imageplatform.name AS imageplatform_name,
OS.name AS OS_name,
OS.prettyname AS OS_prettyname,
OS.type AS OS_type,
OS.installtype AS OS_installtype,
OS.sourcepath AS OS_sourcepath,
imageOSmodule.name AS imageOSmodule_name,
imageOSmodule.prettyname AS imageOSmodule_prettyname,
imageOSmodule.description AS imageOSmodule_description,
imageOSmodule.perlpackage AS imageOSmodule_perlpackage,
user.id AS user_id,
user.uid AS user_uid,
user.unityid AS user_unityid,
user.affiliationid AS user_affiliationid,
user.firstname AS user_firstname,
user.middlename AS user_middlename,
user.lastname AS user_lastname,
user.preferredname AS user_preferredname,
user.email AS user_email,
user.emailnotices AS user_emailnotices,
user.IMtypeid AS user_IMtypeid,
user.IMid AS user_IMid,
user.adminlevelid AS user_adminlevelid,
user.width AS user_width,
user.height AS user_height,
user.bpp AS user_bpp,
user.audiomode AS user_audiomode,
user.mapdrives AS user_mapdrives,
user.mapprinters AS user_mapprinters,
user.mapserial AS user_mapserial,
user.showallgroups AS user_showallgroups,
user.lastupdated AS user_lastupdated,
adminlevel.name AS adminlevel_name,
affiliation.name AS affiliation_name,
affiliation.dataUpdateText AS affiliation_dataUpdateText,
affiliation.sitewwwaddress AS affiliation_sitewwwaddress,
affiliation.helpaddress AS affiliation_helpaddress,
IMtype.name AS IMtype_name,
computer.id AS computer_id,
computer.stateid AS computer_stateid,
computer.ownerid AS computer_ownerid,
computer.deptid AS computer_deptid,
computer.platformid AS computer_platformid,
computer.scheduleid AS computer_scheduleid,
computer.currentimageid AS computer_currentimageid,
computer.preferredimageid AS computer_preferredimageid,
computer.imagerevisionid AS computer_imagerevisionid,
computer.RAM AS computer_RAM,
computer.procnumber AS computer_procnumber,
computer.procspeed AS computer_procspeed,
computer.network AS computer_network,
computer.hostname AS computer_hostname,
computer.IPaddress AS computer_IPaddress,
computer.privateIPaddress AS computer_privateIPaddress,
computer.eth0macaddress AS computer_eth0macaddress,
computer.eth1macaddress AS computer_eth1macaddress,
computer.type AS computer_type,
computer.provisioningid AS computer_provisioningid,
computer.drivetype AS computer_drivetype,
computer.deleted AS computer_deleted,
computer.notes AS computer_notes,
computer.lastcheck AS computer_lastcheck,
computer.location AS computer_location,
computer.dsa AS computer_dsa,
computer.dsapub AS computer_dsapub,
computer.rsa AS computer_rsa,
computer.rsapub AS computer_rsapub,
computer.host AS computer_host,
computer.hostpub AS computer_hostpub,
computer.vmhostid AS computer_vmhostid,
computerdept.name AS computerdept_name,
computerdept.prettyname AS computerdept_prettyname,
computerplatform.name AS computerplatform_name,
computerstate.name AS computerstate_name,
computerschedule.name AS computerschedule_name,
computerprovisioning.name AS computerprovisioning_name,
computerprovisioning.prettyname AS computerprovisioning_prettyname,
computerprovisioning.moduleid AS computerprovisioning_moduleid,
computerprovisioningmodule.name AS computerprovisioningmodule_name,
computerprovisioningmodule.prettyname AS computerprovisioningmodule_prettyname,
computerprovisioningmodule.description AS computerprovisioningmodule_description,
computerprovisioningmodule.perlpackage AS computerprovisioningmodule_perlpackage
FROM
request,
user,
adminlevel,
affiliation,
IMtype,
reservation,
image,
dept imagedept,
platform imageplatform,
imagerevision,
OS,
module imageOSmodule,
computer,
provisioning computerprovisioning,
module computerprovisioningmodule,
dept computerdept,
platform computerplatform,
schedule computerschedule,
state requeststate,
state requestlaststate,
state computerstate
WHERE
request.id = $request_id
AND user.id = request.userid
AND adminlevel.id = user.adminlevelid
AND affiliation.id = user.affiliationid
AND reservation.requestid = request.id
AND image.id = imagerevision.imageid
AND imagedept.id = image.deptid
AND imageplatform.id = image.platformid
AND imagerevision.id = reservation.imagerevisionid
AND OS.id = image.OSid
AND imageOSmodule.id = OS.moduleid
AND computer.id = reservation.computerid
AND computerdept.id = computer.deptid
AND computerplatform.id = computer.platformid
AND computerschedule.id = computer.scheduleid
AND computerstate.id = computer.stateid
AND computerprovisioning.id = computer.provisioningid
AND computerprovisioningmodule.id = computerprovisioning.moduleid
AND requeststate.id = request.stateid
AND requestlaststate.id = request.laststateid
AND IMtype.id = user.IMtypeid
GROUP BY
reservation.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 or more rows were returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "request id $request_id information could not be retrieved");
return ();
}
# Build the hash
my %request_info;
for (@selected_rows) {
my %reservation_row = %{$_};
# Grab the reservation ID to make the code a little cleaner
my $reservation_id = $reservation_row{reservation_id};
# If this request only has 1 reservation, populate the RESERVATIONID key
# This is mainly for testing convenience
# Calling program is responsible for setting this based on which reservation it's processing
$request_info{RESERVATIONID} = $reservation_id if (scalar @selected_rows == 1);
# Check if the image associated with this reservation has meta data
# get_imagemeta_info will return default values if image_imagemetaid is undefined
my %imagemeta_info = get_imagemeta_info($reservation_row{image_imagemetaid});
# Make sure metadata was located if imagemetaid was specified for the image
if (!%imagemeta_info) {
notify($ERRORS{'WARNING'}, 0, "imagemetaid=" . $reservation_row{image_imagemetaid} . " was specified for image id=" . $reservation_row{image_id} . " but imagemeta could not be found");
}
else {
# Image meta data found, add it to the hash
$request_info{reservation}{$reservation_id}{image}{imagemeta} = \%imagemeta_info;
}
# Check if the computer associated with this reservation has a vmhostid set
if ($reservation_row{computer_vmhostid}) {
my %vmhost_info = get_vmhost_info($reservation_row{computer_vmhostid});
# Make sure vmhost was located if vmhostid was specified for the image
if (!%vmhost_info) {
notify($ERRORS{'WARNING'}, 0, "vmhostid=" . $reservation_row{computer_vmhostid} . " was specified for computer id=" . $reservation_row{computer_id} . " but vmhost could not be found");
}
else {
# Image meta data found, add it to the hash
$request_info{reservation}{$reservation_id}{computer}{vmhost} = \%vmhost_info;
}
} ## end if ($reservation_row{computer_vmhostid})
# Get the computer's current image information
if ($reservation_row{computer_currentimageid}) {
my %computer_currentimage_info;
if (%computer_currentimage_info = get_image_info($reservation_row{computer_currentimageid})) {
$request_info{reservation}{$reservation_id}{computer}{currentimage} = \%computer_currentimage_info;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to get current image info for computer");
}
}
else {
# currentimageid wasn't set for the computer
notify($ERRORS{'WARNING'}, 0, "currentimageid is not set for computer id=" . $reservation_row{computer_id});
}
# Get the computer's preferred image information
if ($reservation_row{computer_preferredimageid}) {
my %computer_preferredimage_info;
if (%computer_preferredimage_info = get_image_info($reservation_row{computer_preferredimageid})) {
$request_info{reservation}{$reservation_id}{computer}{preferredimage} = \%computer_preferredimage_info;
# For preferred imageid get the production imagerevision info
my %preferred_imagerevision_info;
if (%preferred_imagerevision_info = get_production_imagerevision_info($reservation_row{computer_preferredimageid})) {
$request_info{reservation}{$reservation_id}{computer}{preferredimagerevision} = \%preferred_imagerevision_info;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to get preferred image revision info for computer, image revision ID is not set, tried to get production image for image ID " . $reservation_row{computer_preferredimageid});
}
} ## end if (%computer_preferredimage_info = get_image_info...
else {
notify($ERRORS{'WARNING'}, 0, "unable to get preferredimage image info for computer");
}
} ## end if ($reservation_row{computer_preferredimageid...
else {
# currentimageid wasn't set for the computer
notify($ERRORS{'WARNING'}, 0, "preferredimageid is not set for computer id=" . $reservation_row{computer_id});
}
# Get the computer's current imagemeta information
my %computer_currentimagerevision_info;
if ($reservation_row{computer_imagerevisionid} > 0) {
# imagerevisionid is set for computer, get the info for that specific revision
if (%computer_currentimagerevision_info = get_imagerevision_info($reservation_row{computer_imagerevisionid})) {
$request_info{reservation}{$reservation_id}{computer}{currentimagerevision} = \%computer_currentimagerevision_info;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to get current image revision info for computer, image revision ID is set to " . $reservation_row{computer_imagerevisionid});
}
}
else {
# imagerevisionid is not set for computer, get the info for the production revision of currentimageid
if (%computer_currentimagerevision_info = get_production_imagerevision_info($reservation_row{computer_currentimageid})) {
$request_info{reservation}{$reservation_id}{computer}{currentimagerevision} = \%computer_currentimagerevision_info;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to get current image revision info for computer, image revision ID is not set, tried to get production image for image ID " . $reservation_row{computer_currentimageid});
}
}
# Loop through all the columns returned for the reservation
foreach my $key (keys %reservation_row) {
my $value = $reservation_row{$key};
# Create another variable by stripping off the column_ part of each key
# This variable stores the original (correct) column name
(my $original_key = $key) =~ s/^.+_//;
if ($key =~ /request_/) {
# Set the top-level key if not already set
$request_info{$original_key} = $value if (!$request_info{$original_key});
}
elsif ($key =~ /requeststate_/) {
$request_info{state}{$original_key} = $value if (!$request_info{state}{$original_key});
}
elsif ($key =~ /requestlaststate_/) {
$request_info{laststate}{$original_key} = $value if (!$request_info{laststate}{$original_key});
}
elsif ($key =~ /user_/) {
$request_info{user}{$original_key} = $value;
}
elsif ($key =~ /reservation_/) {
$request_info{reservation}{$reservation_id}{$original_key} = $value;
}
elsif ($key =~ /image_/) {
$request_info{reservation}{$reservation_id}{image}{$original_key} = $value;
}
elsif ($key =~ /imagedept_/) {
$request_info{reservation}{$reservation_id}{image}{dept}{$original_key} = $value;
}
elsif ($key =~ /imageplatform_/) {
$request_info{reservation}{$reservation_id}{image}{platform}{$original_key} = $value;
}
elsif ($key =~ /imagerevision_/) {
$request_info{reservation}{$reservation_id}{imagerevision}{$original_key} = $value;
}
elsif ($key =~ /OS_/) {
$request_info{reservation}{$reservation_id}{image}{OS}{$original_key} = $value;
}
elsif ($key =~ /imageOSmodule_/) {
$request_info{reservation}{$reservation_id}{image}{OS}{module}{$original_key} = $value;
}
elsif ($key =~ /adminlevel_/) {
$request_info{user}{adminlevel}{$original_key} = $value;
}
elsif ($key =~ /affiliation_/) {
$request_info{user}{affiliation}{$original_key} = $value;
}
elsif ($key =~ /IMtype_/) {
$request_info{user}{IMtype}{$original_key} = $value;
}
elsif ($key =~ /computer_/) {
$request_info{reservation}{$reservation_id}{computer}{$original_key} = $value;
}
elsif ($key =~ /computerdept_/) {
$request_info{reservation}{$reservation_id}{computer}{dept}{$original_key} = $value;
}
elsif ($key =~ /computerplatform_/) {
$request_info{reservation}{$reservation_id}{computer}{platform}{$original_key} = $value;
}
elsif ($key =~ /computerschedule_/) {
$request_info{reservation}{$reservation_id}{computer}{schedule}{$original_key} = $value;
}
elsif ($key =~ /computerstate_/) {
$request_info{reservation}{$reservation_id}{computer}{state}{$original_key} = $value;
}
elsif ($key =~ /computerprovisioning_/) {
$request_info{reservation}{$reservation_id}{computer}{provisioning}{$original_key} = $value;
}
elsif ($key =~ /computerprovisioningmodule_/) {
$request_info{reservation}{$reservation_id}{computer}{provisioning}{module}{$original_key} = $value;
}
else {
notify($ERRORS{'WARNING'}, 0, "unknown key found in SQL data: $key");
}
} # Close foreach key in reservation row
} # Close loop through selected rows
# Set some default non-database values for the entire request
# All data ever added to the hash should be initialized here
$request_info{PID} = '';
$request_info{PPID} = '';
$request_info{PARENTIMAGE} = '';
$request_info{PRELOADONLY} = '0';
$request_info{SUBIMAGE} = '';
$request_info{user}{STANDALONE} = '0';
$request_info{CHECKTIME} = '';
$request_info{NOTICEINTERVAL} = '';
$request_info{RESERVATIONCOUNT} = scalar keys %{$request_info{reservation}};
$request_info{UPDATED} = '0';
# Each selected row represents a reservation associated with this request
# Fix some of the data
# Set the user's preferred name to the first name if it isn't defined
if (!defined($request_info{user}{preferredname}) || !$request_info{user}{preferredname}) {
$request_info{user}{preferredname} = $request_info{user}{firstname};
}
# Set the user's uid to -1 if it's NULL
if (!defined($request_info{user}{uid}) || !$request_info{user}{uid}) {
$request_info{user}{uid} = -1;
}
# Set the user's IMid to '' if it's NULL
if (!defined($request_info{user}{IMid}) || !$request_info{user}{IMid}) {
$request_info{user}{IMid} = '';
}
# Fix the unityid if non-NCSU account
if ($request_info{user}{uid} >= 1000000) {
my ($correct_unity_id, $user_domain) = split /@/, $request_info{user}{unityid};
notify($ERRORS{'OK'}, 0, "non-NCSU user found: $request_info{user}{unityid}, $correct_unity_id from $user_domain");
$request_info{user}{unityid} = $correct_unity_id;
$request_info{user}{STANDALONE} = 1;
}
# Affiliation specific changes
if ($request_info{user}{affiliation}{name} ne "NCSU") {
notify($ERRORS{'OK'}, 0, "non-NCSU user affiliation found: $request_info{user}{affiliation}{name}");
$request_info{user}{STANDALONE} = 1;
}
# For test account only
if ($request_info{user}{unityid} =~ /vcladmin/) {
$request_info{user}{STANDALONE} = 1;
}
# Set the user's affiliation sitewwwaddress and help address if not defined or blank
if (!defined($request_info{user}{affiliation}{sitewwwaddress}) || !$request_info{user}{affiliation}{sitewwwaddress}) {
$request_info{user}{affiliation}{sitewwwaddress} = 'http://vcl.ncsu.edu';
}
if (!defined($request_info{user}{affiliation}{helpaddress}) || !$request_info{user}{affiliation}{helpaddress}) {
$request_info{user}{affiliation}{helpaddress} = 'vcl_help@ncsu.edu';
}
# Loop through all the reservations
foreach my $reservation_id (keys %{$request_info{reservation}}) {
# Confirm lastcheck time is not NULL
if (!defined($request_info{reservation}{$reservation_id}{lastcheck})) {
$request_info{reservation}{$reservation_id}{lastcheck} = 0;
}
# Set the reservation remote IP to 0 if it's NULL
if (!defined($request_info{reservation}{$reservation_id}{remoteIP})) {
$request_info{reservation}{$reservation_id}{remoteIP} = 0;
}
# Set the short name of the computer based on the hostname
my $computer_hostname = $request_info{reservation}{$reservation_id}{computer}{hostname};
$computer_hostname =~ /([-_a-zA-Z0-9]*)(\.?)/;
my $computer_shortname = $1;
$request_info{reservation}{$reservation_id}{computer}{SHORTNAME} = $computer_shortname;
# Add the managementnode info to the hash
my $management_node_id = $request_info{reservation}{$reservation_id}{managementnodeid};
my $management_node_info = get_management_node_info($management_node_id);
if (!$management_node_info) {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve management node info");
$request_info{reservation}{$reservation_id}{managementnode} = 0;
}
else {
$request_info{reservation}{$reservation_id}{managementnode} = $management_node_info;
}
# Set the node name based on the type of computer
my $computer_type = $request_info{reservation}{$reservation_id}{computer}{type};
# Figure out the nodename based on the type of computer
my $computer_nodename;
if ($computer_type eq "blade") {
$computer_nodename = $computer_shortname;
}
elsif ($computer_type eq "lab") {
$computer_nodename = $computer_hostname;
}
elsif ($computer_type eq "virtualmachine") {
$computer_nodename = $computer_shortname;
}
else {
my $computer_id = $request_info{reservation}{$reservation_id}{computer}{id};
notify($ERRORS{'WARNING'}, 0, "computer=$computer_id is of an unknown or unusual type=$computer_type");
}
$request_info{reservation}{$reservation_id}{computer}{NODENAME} = $computer_nodename;
# Set the image identity file path
my $imagerevision_imagename = $request_info{reservation}{$reservation_id}{imagerevision}{imagename};
my $identity_file_path;
if ($imagerevision_imagename =~ /^(win|vmwarewin|vmwareesxwin)/) {
$identity_file_path = $IDENTITY_wxp;
}
elsif ($imagerevision_imagename =~ /^(rh|fc|esx)/) {
$identity_file_path = $IDENTITY_bladerhel;
}
#elsif ($imagerevision_imagename =~ /vmimage|vmwarewin|vmwareesxwin/) {
# $identity_file_path = $IDENTITY_wxp;
#}
elsif ($imagerevision_imagename =~ /realmrh|i386_linux26/) {
$identity_file_path = $IDENTITY_linux_lab;
}
elsif ($imagerevision_imagename =~ /sun/) {
$identity_file_path = $IDENTITY_solaris_lab;
}
elsif ($imagerevision_imagename =~ /^mpls/) {
notify($ERRORS{'OK'}, 0, "MPLS reservation: $request_id:$reservation_id");
}
else {
notify($ERRORS{'WARNING'}, 0, "unsupported image type: $imagerevision_imagename");
}
$request_info{reservation}{$reservation_id}{image}{IDENTITY} = $identity_file_path;
# Set some non-database defaults
# All data ever added to the hash should be initialized here
$request_info{reservation}{$reservation_id}{READY} = '0';
$request_info{reservation}{$reservation_id}{image}{SETTESTFLAG} = '';
$request_info{reservation}{$reservation_id}{image}{UPDATEIMAGENAME} = '';
# If machine type is virtual machine - build out a vmclient subhash
# Allows for ease of use with existing vm subroutines
if ($request_info{reservation}{$reservation_id}{computer}{type} eq "virtualmachine") {
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"drivetype"} = $request_info{reservation}{$reservation_id}{computer}{drivetype};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"shortname"} = $request_info{reservation}{$reservation_id}{computer}{SHORTNAME};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"hostname"} = $request_info{reservation}{$reservation_id}{computer}{hostname};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"eth0MAC"} = $request_info{reservation}{$reservation_id}{computer}{eth0macaddress};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"eth1MAC"} = $request_info{reservation}{$reservation_id}{computer}{eth1macaddress};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"publicIPaddress"} = $request_info{reservation}{$reservation_id}{computer}{IPaddress};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"privateIPaddress"} = $request_info{reservation}{$reservation_id}{computer}{privateIPaddress};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"imageminram"} = $request_info{reservation}{$reservation_id}{image}{minram};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"requestedimagename"} = $request_info{reservation}{$reservation_id}{imagerevision}{imagename};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"imageid"} = $request_info{reservation}{$reservation_id}{image}{id};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"reloadtime"} = $request_info{reservation}{$reservation_id}{image}{reloadtime};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"project"} = $request_info{reservation}{$reservation_id}{image}{project};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"OSname"} = $request_info{reservation}{$reservation_id}{image}{OS}{name};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"forimaging"} = $request_info{forimaging};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"persistent"} = $request_info{forimaging};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"currentimageid"} = $request_info{reservation}{$reservation_id}{computer}{currentimageid};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"reservationid"} = $reservation_id;
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"computerid"} = $request_info{reservation}{$reservation_id}{computer}{id};
$request_info{reservation}{$reservation_id}{computer}{"vmclient"}{"state"} = $request_info{state}{name};
} ## end if ($request_info{reservation}{$reservation_id...
} ## end foreach my $reservation_id (keys %{$request_info...
return %request_info;
} ## end sub get_request_info
#/////////////////////////////////////////////////////////////////////////////
=head2 get_requests
Parameters : management node id
Returns : hash
Description : gets request information for a particular management node
=cut
sub get_management_node_requests {
my ($management_node_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
if (!(defined($management_node_id))) {
notify($ERRORS{'WARNING'}, 0, "management node ID was not specified");
return ();
}
my $select_statement = "
SELECT DISTINCT
request.id AS request_id,
request.stateid AS request_stateid,
request.reservationid AS request_reservationid,
request.laststateid AS request_laststateid,
request.logid AS request_logid,
request.start AS request_start,
request.end AS request_end,
request.daterequested AS request_daterequested,
request.datemodified AS request_datemodified,
request.preload AS request_preload,
requeststate.name AS requeststate_name,
requestlaststate.name AS requestlaststate_name,
reservation.id AS reservation_id,
reservation.requestid AS reservation_requestid,
reservation.managementnodeid AS reservation_managementnodeid,
reservation.lastcheck AS reservation_lastcheck
FROM
request,
reservation,
state requeststate,
state requestlaststate
WHERE
reservation.managementnodeid = $management_node_id
AND reservation.requestid = request.id
AND requeststate.id = request.stateid
AND requestlaststate.id = request.laststateid
GROUP BY
reservation.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 or more rows were returned
if (scalar @selected_rows == 0) {
return ();
}
# Build the hash
my %requests;
for (@selected_rows) {
my %reservation_row = %{$_};
# Grab the request and reservation IDs to make the code a little cleaner
my $request_id = $reservation_row{request_id};
my $reservation_id = $reservation_row{reservation_id};
# Loop through all the columns returned for the reservation
foreach my $key (keys %reservation_row) {
my $value = $reservation_row{$key};
# Create another variable by stripping off the column_ part of each key
# This variable stores the original (correct) column name
(my $original_key = $key) =~ s/^.+_//;
if ($key =~ /request_/) {
# Set the top-level key if not already set
$requests{$request_id}{$original_key} = $value if (!$requests{$request_id}{$original_key});
}
elsif ($key =~ /requeststate_/) {
$requests{$request_id}{state}{$original_key} = $value if (!$requests{$request_id}{state}{$original_key});
}
elsif ($key =~ /requestlaststate_/) {
$requests{$request_id}{laststate}{$original_key} = $value if (!$requests{$request_id}{laststate}{$original_key});
}
elsif ($key =~ /reservation_/) {
$requests{$request_id}{reservation}{$reservation_id}{$original_key} = $value;
}
else {
notify($ERRORS{'WARNING'}, 0, "unknown key found in SQL data: $key");
}
} # Close foreach key in reservation row
} # Close loop through selected rows
# Each selected row represents a reservation associated with this request
return %requests;
} ## end sub get_management_node_requests
#/////////////////////////////////////////////////////////////////////////////
=head2 get_image_info
Parameters : Image ID
Returns : Hash containing image data
Description : collects data from database on supplied image_id
=cut
sub get_image_info {
my ($image_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($image_id))) {
notify($ERRORS{'WARNING'}, 0, "image ID was not specified");
return ();
}
# If imagemetaid isnt' NULL, perform another query to get the meta info
my $select_statement = "
SELECT
image.*
FROM
image
WHERE
image.id = '$image_id'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "image id $image_id does not exist in the database, 0 rows were returned");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# A single row was returned (good)
# Return the hash
return %{$selected_rows[0]};
} ## end sub get_image_info
#/////////////////////////////////////////////////////////////////////////////
=head2 get_imagerevision_info
Parameters : Imagerevision ID
Returns : Hash containing image data
Description : collects data from database on supplied $imagerevision_id
=cut
sub get_imagerevision_info {
my ($imagerevision_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($imagerevision_id))) {
notify($ERRORS{'WARNING'}, 0, "imagerevision ID was not specified");
return ();
}
# If imagemetaid isnt' NULL, perform another query to get the meta info
my $select_statement = "
SELECT
imagerevision.*
FROM
imagerevision
WHERE
imagerevision.id = '$imagerevision_id'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "imagerevision id $imagerevision_id was not found in the database, 0 rows were returned");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# A single row was returned (good)
# Return the hash
return %{$selected_rows[0]};
} ## end sub get_imagerevision_info
#/////////////////////////////////////////////////////////////////////////////
=head2 get_production_imagerevision_info
Parameters : $image_id
Returns : Hash containing imagerevision data for the production revision of an image
Description :
=cut
sub get_production_imagerevision_info {
my ($image_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($image_id))) {
notify($ERRORS{'WARNING'}, 0, "image ID was not specified");
return ();
}
# If imagemetaid isnt' NULL, perform another query to get the meta info
my $select_statement = "
SELECT
imagerevision.*
FROM
imagerevision
WHERE
imagerevision.imageid = '$image_id'
AND imagerevision.production = '1'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "production imagerevision for image id $image_id was not found in the database, 0 rows were returned");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# A single row was returned (good)
# Return the hash
return %{$selected_rows[0]};
} ## end sub get_production_imagerevision_info
#/////////////////////////////////////////////////////////////////////////////
=head2 get_imagemeta_info
Parameters : Imagemata ID
Returns : Hash containing imagemeta columns
Description :
=cut
sub get_imagemeta_info {
my ($imagemeta_id) = @_;
# Create a hash with the default values in case imagemeta data can't be found
my %default_usergroupmembers = ();
my %default_imagemeta = ('id' => '',
'checkuser' => '1',
'subimages' => '0',
'usergroupid' => '',
'sysprep' => '1',
'postoption' => '',
'USERGROUPMEMBERS' => \%default_usergroupmembers,
'USERGROUPMEMBERCOUNT' => 0);
# Return defaults if nothing was passed as the imagemeta id
if (!defined($imagemeta_id) || $imagemeta_id eq '') {
#notify($ERRORS{'DEBUG'}, 0, "imagemeta data does not exist for image, default values will be used");
return %default_imagemeta;
}
# If imagemetaid isnt' NULL, perform another query to get the meta info
my $select_statement = "
SELECT
imagemeta.*
FROM
imagemeta
WHERE
imagemeta.id = '$imagemeta_id'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "imagemeta data does not exist for image, using default values", \%default_imagemeta);
return %default_imagemeta;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select, using default values", \%default_imagemeta);
return %default_imagemeta;
}
my %imagemeta = %{$selected_rows[0]};
# Collect additional information
if (defined($imagemeta{usergroupid})) {
my @userlist = getusergroupmembers($imagemeta{usergroupid});
if (scalar @userlist > 0) {
foreach my $userstring (@userlist) {
my ($username, $uid) = split(/:/, $userstring);
$imagemeta{"usergrpmembers"}{$uid}{"username"} = $username;
$imagemeta{"usergrpmembers"}{$uid}{"uid"} = $uid;
$imagemeta{USERGROUPMEMBERS}{$uid} = $username;
}
}
else {
notify($ERRORS{'WARNING'}, 0, "imagemeta data has usergroupid set $imagemeta{usergroupid} - user group was not found");
}
} ## end if (defined($imagemeta{usergroupid}))
# Set values to 0 if database values are null to avoid DataStructure warnings and concat errors
$imagemeta{usergroupid} = 0 if !defined($imagemeta{usergroupid});
$imagemeta{postoption} = 0 if !defined($imagemeta{postoption});
$imagemeta{architecture} = 0 if !defined($imagemeta{architecture});
# Populate the count of user group members
$imagemeta{USERGROUPMEMBERCOUNT} = scalar(keys(%{$imagemeta{USERGROUPMEMBERS}}));
# Return the hash
return %imagemeta;
} ## end sub get_imagemeta_info
#/////////////////////////////////////////////////////////////////////////////
=head2 get_vmhost_info
Parameters : vmhost ID
Returns : Hash containing vmhost, vmprofile, and vmtype data
Description :
=cut
sub get_vmhost_info {
my ($vmhost_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($vmhost_id))) {
notify($ERRORS{'WARNING'}, 0, "vmhost ID was not specified");
return ();
}
# If imagemetaid isnt' NULL, perform another query to get the meta info
my $select_statement = "
SELECT
vmhost.id AS vmhost_id,
vmhost.computerid AS vmhost_computerid,
vmhost.vmprofileid AS vmhost_vmprofileid,
vmhost.vmlimit AS vmhost_vmlimit,
vmhost.vmkernalnic AS vmhost_vmkernalnic,
vmprofile.id AS vmprofile_id,
vmprofile.profilename AS vmprofile_profilename,
vmprofile.vmtypeid AS vmprofile_vmtypeid,
vmprofile.nasshare AS vmprofile_nasshare,
vmprofile.datastorepath AS vmprofile_datastorepath,
vmprofile.vmpath AS vmprofile_vmpath,
vmprofile.virtualswitch0 AS vmprofile_virtualswitch0,
vmprofile.virtualswitch1 AS vmprofile_virtualswitch1,
vmprofile.vmdisk AS vmprofile_vmdisk,
vmtype.id AS vmtype_id,
vmtype.name AS vmtype_name,
state.name AS vmhost_state,
image.name AS vmhost_imagename,
computer.RAM AS vmhost_RAM,
computer.hostname AS vmhost_hostname,
computer.type AS vmhost_type
FROM
vmhost,
vmprofile,
vmtype,
computer,
state,
image
WHERE
vmhost.id = '$vmhost_id'
AND vmprofile.id = vmhost.vmprofileid
AND vmtype.id = vmprofile.vmtypeid
AND computer.id = vmhost.computerid
AND state.id = computer.stateid
AND image.id = computer.currentimageid
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# Get the single returned row
my %vmhost_row = %{$selected_rows[0]};
# Create a hash
my %vmhost_info;
# Loop through all the columns returned for the reservation
foreach my $key (keys %vmhost_row) {
my $value = $vmhost_row{$key};
# Create another variable by stripping off the column_ part of each key
# This variable stores the original (correct) column name
(my $original_key = $key) =~ s/^.+_//;
#notify($ERRORS{'OK'}, 0, "key=$key original_key=$original_key value=$value");
if ($key =~ /vmhost_/) {
$vmhost_info{$original_key} = $value;
}
elsif ($key =~ /vmprofile_/) {
#$vmhost_info{vmprofile}{$original_key} = $value;
$vmhost_info{"vmprofile"}{$original_key} = $value;
}
elsif ($key =~ /vmtype_/) {
$vmhost_info{"vmprofile"}{"vmtype"}{$original_key} = $value;
}
else {
notify($ERRORS{'WARNING'}, 0, "unknown key found in SQL data: $key");
}
} # Close loop through hash keys (columns)
$vmhost_info{vmprofile}{"datastorepath4vmx"} = $vmhost_info{vmprofile}{datastorepath};
$vmhost_info{vmprofile}{"vmpath"} = $vmhost_info{vmprofile}{datastorepath} if (!(defined($vmhost_info{vmprofile}{vmpath})));
#$vmhost_info{vmprofile}{datastorepath} =~ s/(\s+)/\\\\ /g; #detect/handle any spaces;
#$vmhost_info{vmprofile}{vmpath} =~ s/(\s+)/\\\\ /g; #detect/handle any spaces;
$vmhost_info{vmprofile}{datastorepath} =~ s/(\s+)/\\ /g; #detect/handle any spaces;
$vmhost_info{vmprofile}{vmpath} =~ s/(\s+)/\\ /g; #detect/handle any spaces;
#for legacy datastructure
#$vmhost_info{"datastorepath4vmx"} = $vmhost_info{vmhost}{datastorepath};
#$vmhost_info{"vmpath"} = $vmhost_info{datastorepath} if(!(defined($vmhost_info{vmpath})));
#$vmhost_info{datastorepath} =~ s/(\s+)/\\\\ /g; #detect/handle any spaces;
#$vmhost_info{vmpath} =~ s/(\s+)/\\\\ /g; #detect/handle any spaces;
#$vmhost_info{datastorepath} =~ s/(\s+)/\\ /g; #detect/handle any spaces;
#$vmhost_info{vmpath} =~ s/(\s+)/\\ /g; #detect/handle any spaces;
return %vmhost_info;
} ## end sub get_vmhost_info
#/////////////////////////////////////////////////////////////////////////////
=head2 run_ssh_command
Parameters : $node, $identity_path, $command, $user, $port
Returns : If ssh command completed successfully, an array containing
the exit status and a reference to an array containing the
lines of output of the command specified is returned.
$array[0] = the exit status of the command
$array[1] = reference to array containing lines of output
generated by the command
If the ssh command fails, an empty array is returned. You can
therefore use "if (run_ssh_command())", true means the command
executed, false means it failed.
Description : Runs an SSH command on the specified node.
=cut
sub run_ssh_command {
my ($node, $identity_paths, $command, $user, $port, $no_output) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the arguments
if (!defined($node) || !$node) {
notify($ERRORS{'WARNING'}, 0, "computer node was not specified");
return 0;
}
if (!defined($command) || !$command) {
notify($ERRORS{'WARNING'}, 0, "command was not specified");
return 0;
}
# Set default values if not passed as an argument
$user = "root" if (!defined($user) || !$user);
$port = 22 if (!defined($port) || !$port);
# TODO: Add ssh path to config file and set global variable
# Locate the path to the ssh binary
my $ssh_path;
if (-f '/usr/bin/ssh') {
$ssh_path = '/usr/bin/ssh';
}
elsif (-f 'C:/cygwin/bin/ssh.exe') {
$ssh_path = 'C:/cygwin/bin/ssh.exe';
}
elsif (-f 'D:/cygwin/bin/ssh.exe') {
$ssh_path = 'D:/cygwin/bin/ssh.exe';
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to locate the SSH executable in the usual places");
return 0;
}
# Format the identity path string
if ($identity_paths) {
$identity_paths =~ s/^\s*/-i /;
$identity_paths =~ s/\s*,\s*/ -i /g;
$identity_paths .= ' ';
}
#notify($ERRORS{'DEBUG'}, 0, "node: $node, identity file path: $identity_path, user: $user, port: $port");
#notify($ERRORS{'DEBUG'}, 0, "command: $command");
# Assemble the SSH command
# -i <identity_file>, Selects the file from which the identity (private key) for RSA authentication is read.
# -l <login_name>, Specifies the user to log in as on the remote machine.
# -p <port>, Port to connect to on the remote host.
# -x, Disables X11 forwarding.
# Dont use: -q, Quiet mode. Causes all warning and diagnostic messages to be suppressed.
my $ssh_command = "$ssh_path $identity_paths -l $user -p $port -x $node '$command'";
# Redirect standard output and error output so all messages are captured
$ssh_command .= ' 2>&1';
# Execute the command
my $ssh_output;
my $ssh_output_formatted;
my $attempts = 0;
my $max_attempts = 3;
my $exit_status = 255;
# Make multiple attempts if failure occurs
while ($attempts < $max_attempts) {
$attempts++;
## Add -v (verbose) argument to command if this is the 2nd attempt
#$ssh_command =~ s/$ssh_path/$ssh_path -v/ if $attempts == 2;
# Print the SSH command, only display the attempt # if > 1
if ($attempts == 1) {
notify($ERRORS{'DEBUG'}, 0, "executing SSH command on $node: $command");
}
else {
notify($ERRORS{'DEBUG'}, 0, "attempt $attempts/$max_attempts: executing SSH command on $node: $ssh_command");
}
# Execute the command
$ssh_output = `$ssh_command`;
# Bits 0-7 of $? are set to the signal the child process received that caused it to die
my $signal_number = $? & 127;
# Bit 8 of $? will be true if a core dump occurred
my $core_dump = $? & 128;
# Bits 9-16 of $? contain the child process exit status
$exit_status = $? >> 8;
notify($ERRORS{'DEBUG'}, 0, "\$?: $?, signal: $signal_number, core dump: $core_dump, exit status: $exit_status");
## For some reason the SSH exit status is sometimes right-padded with 8 0's
## Shift right 8 bits to get the real value if it's > 255
#if ($ssh_exit_status > 255) {
# $ssh_exit_status = ($ssh_exit_status >> 8);
#}
# Strip out the key warning message
$ssh_output =~ s/\@{10,}.*man-in-the-middle attacks\.//igs;
$ssh_output =~ s/^\s+|\s+$//g;
chomp $ssh_output;
# Set the output string to none if no output was produced
$ssh_output = 'none' if !$ssh_output;
# Replace line breaks in the output with \n$pid| SSH output:
my $pid = $$;
$ssh_output_formatted = $ssh_output;
# Get a slice of the SSH output if there are many lines
my @ssh_output_formatted_lines = split("\n", $ssh_output_formatted);
my $ssh_output_formatted_line_count = scalar @ssh_output_formatted_lines;
if ($ssh_output_formatted_line_count > 50) {
@ssh_output_formatted_lines = @ssh_output_formatted_lines[0 .. 49];
push(@ssh_output_formatted_lines, "displayed first 50 of $ssh_output_formatted_line_count SSH output lines");
$ssh_output_formatted = join("\n", @ssh_output_formatted_lines);
}
my $command_prefix = substr($command, 0, 10);
$command_prefix .= "..." if (length($command) > 10);
$ssh_output_formatted =~ s/\r//g;
$ssh_output_formatted =~ s/^/ssh output ($command_prefix): /g;
$ssh_output_formatted =~ s/\n/\nssh output ($command_prefix): /g;
# Check the exit status
# ssh exits with the exit status of the remote command or with 255 if an error occurred.
if ($exit_status == 255 || $ssh_output_formatted =~ /lost connection|reset by peer|no route to host|connection refused|connection timed out/i) {
notify($ERRORS{'WARNING'}, 0, "attempt $attempts/$max_attempts: failed to execute SSH command on $node: $command, exit status: $exit_status, SSH exits with the exit status of the remote command or with 255 if an error occurred, output:\n$ssh_output_formatted");
next;
}
else {
# SSH command was executed successfully, actual command on node may have succeeded or failed
# Split the output up into an array of lines
my @output_lines = split(/\n/, $ssh_output);
# Print the output unless no_output is set
notify($ERRORS{'DEBUG'}, 0, "run_ssh_command output: $ssh_output") unless $no_output;
# Print the command and exit status
notify($ERRORS{'OK'}, 0, "SSH command executed on $node: $command, returning ($exit_status, output)");
# Return the exit status and output
return ($exit_status, \@output_lines);
}
} ## end while ($attempts < $max_attempts)
# Failure, SSH command did not run at all
notify($ERRORS{'WARNING'}, 0, "failed to run SSH command after $attempts attempts, command: $ssh_command, exit status: $exit_status, output:\n$ssh_output_formatted");
return ();
} ## end sub run_ssh_command
#/////////////////////////////////////////////////////////////////////////////
=head2 run_scp_command
Parameters : $path1, $path2, $identity_path, $port, $options
Returns : 1 success
Description : assumes path1 or path2 contains the src and target
example: copy from remote node to local file
path1 = $user\@$node:<filename>
path2 = <localfilename>
example: copy local file to remote node
path1 = <localfilename>
path2 = $user\@$node:<filename>
=cut
sub run_scp_command {
my ($path1, $path2, $identity_paths, $port, $options) = @_;
my ($package, $filename, $line, $sub) = caller(0);
if (!defined($path1) || !$path1) {
notify($ERRORS{'WARNING'}, 0, "path1 was not specified");
return 0;
}
if (!defined($path2) || !$path2) {
notify($ERRORS{'WARNING'}, 0, "path2 was not specified");
return 0;
}
# Format the identity path string
if ($identity_paths) {
$identity_paths =~ s/^\s*/-i /;
$identity_paths =~ s/\s*,\s*/ -i /g;
$identity_paths .= ' ';
}
else {
$identity_paths = '';
}
# Set default values if not passed as an argument
$port = 22 if (!defined($port));
# TODO: Add SCP path to config file and set global variable
# Locate the path to the SCP binary
my $scp_path;
if (-f '/usr/bin/scp') {
$scp_path = '/usr/bin/scp';
}
elsif (-f 'C:/cygwin/bin/scp.exe') {
$scp_path = 'C:/cygwin/bin/scp.exe';
}
elsif (-f 'D:/cygwin/bin/scp.exe') {
$scp_path = 'D:/cygwin/bin/scp.exe';
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to locate the SCP executable in the usual places");
return 0;
}
# could be hazardous not confirming optional input flags
if (defined($options)) {
$scp_path .= " $options ";
}
# Print the configuration if $VERBOSE
if ($VERBOSE) {
#notify($ERRORS{'OK'}, 0, "path1: $path1, path2: $path2 identity file path: $identity_path, port: $port");
#notify($ERRORS{'OK'}, 0, "node: $node, identity file path: $identity_path, user: $user, port: $port");
#notify($ERRORS{'OK'}, 0, "source path: $source_path");
#notify($ERRORS{'OK'}, 0, "destination path: $destination_path");
}
# Assemble the SCP command
# -B, Selects batch mode (prevents asking for passwords or passphrases).
# -i <identity_file>, Selects the file from which the identity (private key) for RSA authentication is read.
# -P <port>, Specifies the port to connect to on the remote host.
# -p, Preserves modification times, access times, and modes from the original file.
# -r, Recursively copy entire directories.
# -v, Verbose mode. Causes scp and ssh to print debugging messages about their progress.
# Don't use -q, Disables the progress meter. Error messages are more descriptive without it
my $scp_command = "$scp_path -B $identity_paths-P $port -p -r $path1 $path2";
# Redirect standard output and error output so all messages are captured
$scp_command .= ' 2>&1';
# Execute the command
my $scp_output;
my $attempts = 0;
my $max_attempts = 3;
my $scp_exit_status = 0;
# Make multiple attempts if failure occurs
while ($attempts < $max_attempts) {
$attempts++;
## Add -v (verbose) argument to command if this is the 2nd attempt
#$scp_command =~ s/$scp_path/$scp_path -v/ if $attempts == 2;
notify($ERRORS{'DEBUG'}, 0, "attempt $attempts/$max_attempts: executing SCP command: $scp_command");
$scp_output = `$scp_command`;
# Save the exit status
$scp_exit_status = $?;
# Strip out the key warning message
$scp_output =~ s/\@{10,}.*man-in-the-middle attacks\.//igs;
$scp_output =~ s/^\s+|\s+$//g;
if ($scp_output && length($scp_output) > 0) {
# Add a newline to the beginning of the output if something was generated
# This is to make multi-line output more readable
$scp_output = "\n" . $scp_output;
}
else {
# Indicate there was no output if it is blank
$scp_output = 'none';
}
# Get a slice of the SCP output if there are many lines
my @scp_output_formatted_lines = split("\n", $scp_output);
my $scp_output_formatted_line_count = scalar @scp_output_formatted_lines;
if ($scp_output_formatted_line_count > 50) {
@scp_output_formatted_lines = @scp_output_formatted_lines[0 .. 49];
push(@scp_output_formatted_lines, "displayed first 50 of $scp_output_formatted_line_count SCP output lines");
$scp_output = join("\n", @scp_output_formatted_lines);
}
# Check the output for known error messages
# Check the exit status
# scp exits with 0 on success or >0 if an error occurred
if ($scp_exit_status > 0 || $scp_output =~ /lost connection|failed|reset by peer|no route to host/i) {
notify($ERRORS{'WARNING'}, 0, "scp error occurred: attempt $attempts/$max_attempts, command: $scp_command, exit status: $scp_exit_status, output: $scp_output");
next;
}
else {
notify($ERRORS{'OK'}, 0, "scp successful: attempt $attempts/$max_attempts, exit status: $scp_exit_status, output: $scp_output");
return 1;
}
} ## end while ($attempts < $max_attempts)
# Failure
notify($ERRORS{'WARNING'}, 0, "failed to copy files using scp after $attempts attempts, command: $scp_command, exit status: $scp_exit_status, output: $scp_output");
return 0;
} ## end sub run_scp_command
#/////////////////////////////////////////////////////////////////////////////
=head2 write_currentimage_txt
Parameters : hash of hashes hash{image} contains image info
Returns : 0 failed or 1 successful
Description : runs an ssh command on the specified node and returns the output
=cut
sub write_currentimage_txt {
my ($data) = @_;
# Store some hash variables into local variables
my $computer_node_name = $data->get_computer_node_name();
my $computer_host_name = $data->get_computer_host_name();
my $computer_id = $data->get_computer_id();
my $image_identity = $data->get_image_identity();
my $image_id = $data->get_image_id();
my $image_name = $data->get_image_name();
my $image_prettyname = $data->get_image_prettyname();
my $imagerevision_id = $data->get_imagerevision_id();
my $imagerevision_date_created = $data->get_imagerevision_date_created();
my @current_image_lines;
push @current_image_lines, "$image_name";
push @current_image_lines, "id=$image_id";
push @current_image_lines, "prettyname=$image_prettyname";
push @current_image_lines, "imagerevision_id=$imagerevision_id";
push @current_image_lines, "imagerevision_datecreated=$imagerevision_date_created";
push @current_image_lines, "computer_id=$computer_id";
push @current_image_lines, "computer_hostname=$computer_host_name";
my $current_image_contents = join('\\r\\n', @current_image_lines);
my $command = 'echo -e "' . $current_image_contents . '" > currentimage.txt & cat currentimage.txt';
# Copy the temp file to the node as currentimage.txt
my ($ssh_exit_status, $ssh_output) = run_ssh_command($computer_node_name, $image_identity, $command);
if (defined($ssh_exit_status) && $ssh_exit_status == 0) {
notify($ERRORS{'OK'}, 0, "created currentimage.txt file on $computer_node_name:\n" . join "\n", @{$ssh_output});
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to create currentimage.txt file on $computer_node_name:\n" . join "\n", @{$ssh_output});
return;
}
} ## end sub write_currentimage_txt
#/////////////////////////////////////////////////////////////////////////////
=head2 vmwareclone
Parameters : $hostnode, $identity, $srcDisk, $dstDisk, $dstDir
Returns : 1 if successful, 0 if error occurred
Description : using vm tools clone srcdisk to dstdisk
currently using builtin vmkfstools
=cut
=pod
sub vmwareclone {
my ($hostnode, $identity, $srcDisk, $dstDisk, $dstDir) = @_;
my ($package, $filename, $line, $sub) = caller(0);
#TODO - add checks for VI toolkit - then use vmclone.pl instead
#vmclone.pl would need additional parameters
my @list = run_ssh_command($hostnode, $identity, "ls -1 $srcDisk", "root");
my $srcDiskexist = 0;
foreach my $l (@{ $list[1] }) {
$srcDiskexist = 1 if ($l =~ /($srcDisk)$/);
$srcDiskexist = 0 if ($l =~ /No such file or directory/);
notify($ERRORS{'OK'}, 0, "$l");
}
my @ssh;
if ($srcDiskexist) {
#make dir for dstdisk
my @mkdir = run_ssh_command($hostnode, $identity, "mkdir -m 755 $dstDir", "root");
notify($ERRORS{'OK'}, 0, "srcDisk is exists $srcDisk ");
notify($ERRORS{'OK'}, 0, "starting clone process vmkfstools -d thin -i $srcDisk $dstDisk");
if (open(SSH, "/usr/bin/ssh -x -q -i $identity -l root $hostnode \"vmkfstools -i $srcDisk -d thin $dstDisk\" 2>&1 |")) {
#@ssh=<SSH>;
#close(SSH);
#foreach my $l (@ssh) {
# notify($ERRORS{'OK'},0,"$l");
#}
while (<SSH>) {
notify($ERRORS{'OK'}, 0, "started $_") if ($_ =~ /Destination/);
notify($ERRORS{'OK'}, 0, "started $_") if ($_ =~ /Cloning disk/);
notify($ERRORS{'OK'}, 0, "status $_") if ($_ =~ /Clone:/);
}
close(SSH);
} ## end if (open(SSH, "/usr/bin/ssh -x -q -i $identity -l root $hostnode \"vmkfstools -i $srcDisk -d thin $dstDisk\" 2>&1 |"...
} ## end if ($srcDiskexist)
else {
notify($ERRORS{'OK'}, 0, "srcDisk $srcDisk does not exists");
}
#confirm
@list = 0;
@list = run_ssh_command($hostnode, $identity, "ls -1 $dstDisk", "root");
my $dstDiskexist = 0;
foreach my $l (@{ $list[1] }) {
$dstDiskexist = 1 if ($l =~ /($dstDisk)$/);
$dstDiskexist = 0 if ($l =~ /No such file or directory/);
}
if ($dstDiskexist) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "clone process failed dstDisk $dstDisk does not exist");
return 0;
}
} ## end sub vmwareclone
=cut
#/////////////////////////////////////////////////////////////////////////////
=head2 get_management_predictive_info
Parameters : Either a management node hostname or database ID
Returns : Hash containing data contained in the managementnode table
Description :
=cut
sub get_management_predictive_info {
my ($management_node_identifier) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($management_node_identifier))) {
# If nothing was passed, assume management node is this machine
# Try to get the hostname of this machine
unless ($management_node_identifier = (hostname())[0]) {
notify($ERRORS{'WARNING'}, 0, "management node hostname or ID was not specified and hostname could not be determined");
return ();
}
}
my $select_statement = "
SELECT
managementnode.*,
predictivemodule.name AS predictive_name,
predictivemodule.prettyname AS predictive_prettyname,
predictivemodule.description AS predictive_description,
predictivemodule.perlpackage AS predictive_perlpackage,
state.name AS statename
FROM
managementnode,
module predictivemodule,
state
WHERE
managementnode.predictivemoduleid = predictivemodule.id
AND managementnode.stateid = state.id
AND
";
# Figure out if the ID or hostname was passed as the identifier and complete the SQL statement
# Check if it only contains digits
chomp $management_node_identifier;
if ($management_node_identifier =~ /^\d+$/) {
$select_statement .= "managementnode.id = $management_node_identifier";
}
else {
$select_statement .= "managementnode.hostname like \'$management_node_identifier%\'";
}
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# Get the single returned row
# It contains a hash
my $management_node_info = $selected_rows[0];
notify($ERRORS{'DEBUG'}, 0, "management node info retrieved from database ");
return $management_node_info;
}
#/////////////////////////////////////////////////////////////////////////////
=head2 get_management_node_id
Parameters : Either a management node hostname or database ID
Returns : Hash containing data contained in the managementnode table
Description :
=cut
sub get_management_node_info {
my ($management_node_identifier) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($management_node_identifier))) {
# If nothing was passed, assume management node is this machine
# Try to get the hostname of this machine
unless ($management_node_identifier = (hostname())[0]) {
notify($ERRORS{'WARNING'}, 0, "management node hostname or ID was not specified and hostname could not be determined");
return ();
}
}
my $select_statement = "
SELECT
managementnode.*,
predictivemodule.name AS predictive_name,
predictivemodule.prettyname AS predictive_prettyname,
predictivemodule.description AS predictive_description,
predictivemodule.perlpackage AS predictive_perlpackage,
state.name AS statename
FROM
managementnode,
module predictivemodule,
state
WHERE
managementnode.predictivemoduleid = predictivemodule.id
AND managementnode.stateid = state.id
AND
";
# Figure out if the ID or hostname was passed as the identifier and complete the SQL statement
# Check if it only contains digits
chomp $management_node_identifier;
if ($management_node_identifier =~ /^\d+$/) {
$select_statement .= "managementnode.id = $management_node_identifier";
}
else {
$select_statement .= "managementnode.hostname like \'$management_node_identifier%\'";
}
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# Get the single returned row
# It contains a hash
my $management_node_info = $selected_rows[0];
# Move the state name to a subkey to match get_request_info
$management_node_info->{state}{name} = $management_node_info->{statename};
delete $management_node_info->{statename};
$management_node_info->{hostname} =~ /([-_a-zA-Z0-9]*)(\.?)/;
my $shortname = $1;
$management_node_info->{SHORTNAME} = $shortname;
# Get the image library partner info if imagelibenable=1 and imagelibgroupid>0
my $imagelib_enable = $management_node_info->{imagelibenable};
my $imagelib_group_id = $management_node_info->{imagelibgroupid};
my $management_node_id = $management_node_info->{id};
if ($imagelib_enable && defined($imagelib_group_id) && $imagelib_group_id) {
my $imagelib_statement = "
SELECT DISTINCT
managementnode.IPAddress
FROM
managementnode,
resource,
resourcegroup,
resourcegroupmembers
WHERE
resourcegroup.id = $imagelib_group_id
AND resourcegroupmembers.resourcegroupid = resourcegroup.id
AND resource.id = resourcegroupmembers.resourceid
AND resource.subid = managementnode.id
AND managementnode.id != $management_node_id
";
# Call the database select subroutine
my @imagelib_rows = database_select($imagelib_statement);
# Check to make sure 1 row was returned
if (scalar @imagelib_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select, image library functions will be disabled");
$management_node_info->{imagelibenable} = 0;
}
else {
#notify($ERRORS{'DEBUG'}, 0, "imagelib partners found: " . scalar @imagelib_rows);
# Loop through the rows, assemble a string separated by commas
my $imagelib_ipaddress_string;
for my $imagelib_row (@imagelib_rows) {
$imagelib_ipaddress_string .= "$imagelib_row->{IPAddress},";
}
# Remove the trailing comma
$imagelib_ipaddress_string =~ s/,$//;
#notify($ERRORS{'DEBUG'}, 0, "image library partner IP address string: $imagelib_ipaddress_string");
$management_node_info->{IMAGELIBPARTNERS} = $imagelib_ipaddress_string;
} ## end else [ if (scalar @imagelib_rows == 0)
} ## end if ($imagelib_enable && defined($imagelib_group_id...
else {
$management_node_info->{IMAGELIBPARTNERS} = 0;
#notify($ERRORS{'DEBUG'}, 0, "image library sharing functions are disabled");
}
# Get the OS name
my $os_name = lc($^O);
$management_node_info->{OSNAME} = $os_name;
notify($ERRORS{'DEBUG'}, 0, "management node info retrieved from database for $shortname");
return $management_node_info;
} ## end sub get_management_node_info
#/////////////////////////////////////////////////////////////////////////////
=head2 update_currentimage
Parameters : $computerid, $imageid, $imagerevisionid, $preferredimagid(optional)
Returns : 0 failed or 1 success
Description : Updates currentimage on a node, preferredimageid = optional
=cut
sub update_currentimage {
my ($computerid, $imageid, $imagerevisionid, $preferredimagid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameters
if (!(defined($computerid))) {
notify($ERRORS{'WARNING'}, 0, "computer ID was not specified");
return ();
}
if (!(defined($imageid))) {
notify($ERRORS{'WARNING'}, 0, "image ID was not specified");
return ();
}
if (!(defined($imagerevisionid))) {
notify($ERRORS{'WARNING'}, 0, "image revision ID was not specified");
return ();
}
notify($ERRORS{'OK'}, 0, "updating computer $computerid: image=$imageid, imagerevision=$imagerevisionid");
# Construct the update statement
# If $preferredimageid defined and set build slightly different statement
my $update_statement = "
UPDATE
computer c, image i
SET
c.currentimageid = $imageid,
c.imagerevisionid= $imagerevisionid
WHERE
c.id = $computerid
";
if (defined($preferredimagid) && ($preferredimagid)) {
$update_statement = "
UPDATE
computer c, image i
SET
c.currentimageid = $imageid,
c.preferredimageid = $imageid,
c.imagerevisionid= $imagerevisionid
WHERE
c.id = $computerid
";
} ## end if (defined($preferredimagid) && ($preferredimagid...
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful, return timestamp
notify($ERRORS{'OK'}, 0, "updated currentimageid and imagerevision id for computer id $computerid");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update database, computerid $computerid currentimageid $imageid");
return 0;
}
} ## end sub update_currentimage
#/////////////////////////////////////////////////////////////////////////////
=head2 is_inblockrequest
Parameters : Updates currentimage on a node
Returns : 1 if successful, 0 otherwise
Description : checks blockComputers table for supplied computerid
=cut
sub is_inblockrequest {
my ($computerid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameters
if (!(defined($computerid))) {
notify($ERRORS{'WARNING'}, 0, "computer ID was not specified");
return ();
}
# Construct the select statement
my $select_statement = "
SELECT
b.blockRequestid,c.blockTimeid
FROM blockTimes b, blockComputers c
WHERE
c.blockTimeid=b.id AND c.computerid = $computerid
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check on what we return
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "zero rows were returned from database select");
return 0;
}
elsif (scalar @selected_rows => 1) {
notify($ERRORS{'OK'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return 1;
}
} ## end sub is_inblockrequest
#/////////////////////////////////////////////////////////////////////////////
=head2 update_lastcheckin
Parameters : $management_node_id
Returns : 0 or 1
Description : Updates lastcheckin for a management node
=cut
sub update_lastcheckin {
my ($management_node_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($management_node_id))) {
notify($ERRORS{'WARNING'}, 0, "management node ID was not specified");
return ();
}
# Get current timestamp
my $timestamp = makedatestring();
# Construct the update statement
my $update_statement = "
UPDATE
managementnode
SET
lastcheckin = \'$timestamp\'
WHERE
id = $management_node_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful, return timestamp
return $timestamp;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update database, management node id $management_node_id");
return 0;
}
} ## end sub update_lastcheckin
#/////////////////////////////////////////////////////////////////////////////
=head2 update_computer_ipaddress
Parameters : $computer_id, $IPaddress
Returns : 0 failed or 1 success
Description : Updates computer's ipaddress - used in dynamic dhcp setup
=cut
sub update_computer_address {
my ($computer_id, $IPaddress) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($computer_id))) {
notify($ERRORS{'WARNING'}, 0, "computer ID was not specified");
return ();
}
# Check the passed parameter
if (!(defined($IPaddress))) {
notify($ERRORS{'WARNING'}, 0, "IPaddress was not specified");
return ();
}
# Construct the update statement
my $update_statement = "
UPDATE
computer
SET
IPaddress = \'$IPaddress\'
WHERE
id = $computer_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
# Update successful, return timestamp
notify($ERRORS{'OK'}, $LOGFILE, "computer $computer_id IP address $IPaddress updated in database");
return 1;
}
else {
notify($ERRORS{'CRITICAL'}, 0, "unable to update database, computer IPaddress $computer_id,$IPaddress");
return 0;
}
} ## end sub update_computer_address
#/////////////////////////////////////////////////////////////////////////////
=head2 get_request_end
Parameters : $request_id
Returns : Scalar containing end value for given request ID
Description :
=cut
sub get_request_end {
my ($request_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($request_id))) {
notify($ERRORS{'WARNING'}, 0, "request ID was not specified");
return ();
}
# Create the select statement
my $select_statement = "
SELECT
request.end AS end
FROM
request
WHERE
request.id = $request_id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# Get the single returned row
# It contains a hash
my $end;
# Make sure we return undef if the column wasn't found
if (defined $selected_rows[0]{end}) {
$end = $selected_rows[0]{end};
return $end;
}
else {
return undef;
}
} ## end sub get_request_end
#/////////////////////////////////////////////////////////////////////////////
=head2 get_request_by_computerid
Parameters : $computer_id
Returns : hash containing values of assigned request/reservation
Description :
=cut
sub get_request_by_computerid {
my ($computer_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($computer_id))) {
notify($ERRORS{'WARNING'}, 0, "computer ID was not specified");
return ();
}
# Create the select statement
my $select_statement = "
SELECT DISTINCT
res.id AS reservationid,
s.name AS currentstate,
ls.name AS laststate,
req.id AS requestid,
req.start AS requeststart
FROM
request req,reservation res,state s,state ls
WHERE
req.stateid=s.id AND
req.laststateid = ls.id AND
req.id=res.requestid AND
res.computerid = $computer_id
ORDER BY
res.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select $computer_id");
return ();
}
my %returnhash;
# It contains a hash
for (@selected_rows) {
my %reservation_row = %{$_};
# Grab the reservation ID to make the code a little cleaner
my $reservation_id = $reservation_row{reservationid};
$returnhash{$reservation_id}{"reservationid"} = $reservation_id;
$returnhash{$reservation_id}{"currentstate"} = $reservation_row{currentstate};
$returnhash{$reservation_id}{"laststate"} = $reservation_row{laststate};
$returnhash{$reservation_id}{"requestid"} = $reservation_row{requestid};
$returnhash{$reservation_id}{"requeststart"} = $reservation_row{requeststart};
} ## end for (@selected_rows)
return %returnhash;
} ## end sub get_request_by_computerid
#/////////////////////////////////////////////////////////////////////////////
=head2 get_computer_current_state_name
Parameters : $computer_id
Returns : String containing state name for a particular computer
Description :
=cut
sub get_computer_current_state_name {
my ($computer_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($computer_id))) {
notify($ERRORS{'WARNING'}, 0, "computer ID was not specified");
return ();
}
# Create the select statement
my $select_statement = "
SELECT DISTINCT
state.name AS name
FROM
state,
computer
WHERE
computer.stateid = state.id
AND computer.id = $computer_id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return ();
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# Make sure we return undef if the column wasn't found
if (defined $selected_rows[0]{name}) {
return $selected_rows[0]{name};
}
else {
return undef;
}
} ## end sub get_computer_current_state_name
#/////////////////////////////////////////////////////////////////////////////
=head2 construct_image_name
Parameters : $image_name, $specified_version
Returns : String containing a new image name.
If no number is specified, version is incremented by 1.
If number is specified, version is set to that number
Description :
=cut
sub construct_image_name {
my ($image_name, $specified_version, $os_name) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($image_name))) {
notify($ERRORS{'WARNING'}, 0, "image name was not specified");
return 0;
}
# If version was specified, check to make sure it's just numerical digits
if (defined($specified_version) && $specified_version !~ /^\d+$/) {
notify($ERRORS{'WARNING'}, 0, "specified version is not in the correct format: $specified_version");
return 0;
}
# Image Name Format: osname-longnameid-v#
# Example: winxp-Thisistheimagename23-v0
# Split the image name by dashes
my @name_sections = split(/-/, $image_name);
my $section_count = scalar @name_sections;
# Check to make sure at least 3 sections were found (separated by "-")
if ($section_count < 3) {
notify($ERRORS{'WARNING'}, 0, "image name is in the wrong format, cannot construct: $image_name");
return 0;
}
# The OS should be the first section
my $os_section = $name_sections[0];
# If an OS name was passed as an argument use it, otherwise use the OS name from the previous image name
if (defined $os_name && $os_name ne '') {
$os_section = $os_name;
}
# The version should be the last section
my $version_section = $name_sections[$section_count - 1];
# Everything in between should be the image name and version
my $name_section = join('-', @name_sections[1 .. ($section_count - 2)]);
# Check to make sure the version number is valid
if ($version_section =~ /^([v|V])([0-9]+)/) {
my $v = $1;
my $version_number = $2;
# Increment version number or use the specified version if it was passed
if (defined($specified_version)) {
$version_number = $specified_version;
}
else {
$version_number++;
}
return $os_section . "-" . "$name_section" . "-" . $v . $version_number;
} ## end if ($version_section =~ /^([v|V])([0-9]+)/)
else {
notify($ERRORS{'WARNING'}, 0, "could not detect version number from image name: $image_name");
return 0;
}
} ## end sub construct_image_name
#/////////////////////////////////////////////////////////////////////////////
=head2 get_reservation_remote_ip
Parameters : $reservation_id
Returns : String containing remoteIP value for specified reservation ID, 0 if reservation was not found
Description :
=cut
sub get_reservation_remote_ip {
my ($reservation_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($reservation_id))) {
notify($ERRORS{'WARNING'}, 0, "reservation ID was not specified");
return 0;
}
# Create the select statement
my $select_statement = "
SELECT
remoteIP
FROM
reservation
WHERE
id = $reservation_id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "zero rows were returned from database select");
return 0;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return 0;
}
# Get the single returned row
# It contains a hash
my $remote_ip;
# Make sure we return undef if the column wasn't found
if (defined $selected_rows[0]{remoteIP}) {
$remote_ip = $selected_rows[0]{remoteIP};
}
else {
return undef;
}
# Make sure we return undef if remote IP is blank
if ($remote_ip eq '') {
return undef;
}
else {
return $remote_ip;
}
} ## end sub get_reservation_remote_ip
#/////////////////////////////////////////////////////////////////////////////
=head2 update_log_ending
Parameters : $log_id, $ending
Returns : 0 or 1
Description : Updates the finalend and ending fields
in the log table for the specified log ID
=cut
sub update_log_ending {
my ($log_id, $ending) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($log_id))) {
notify($ERRORS{'WARNING'}, 0, "$0: log ID was not specified");
return ();
}
# Check the passed parameter
if (!(defined($ending))) {
notify($ERRORS{'WARNING'}, 0, "$0: ending string was not specified");
return ();
}
my $datestring = makedatestring();
# Construct the update statement
my $update_statement = "
UPDATE
log
SET
finalend = \'$datestring\',
ending = \'$ending\'
WHERE
id = $log_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update database, log id $log_id");
return 0;
}
} ## end sub update_log_ending
#/////////////////////////////////////////////////////////////////////////////
=head2 update_reservation_lastcheck
Parameters : Updates the finalend and ending fields in the log table for the specified log ID
Returns : date string if successful, 0 if failed
Description :
=cut
sub update_reservation_lastcheck {
my ($reservation_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($reservation_id))) {
notify($ERRORS{'WARNING'}, 0, "reservation ID was not specified");
return ();
}
my $datestring = makedatestring();
# Construct the update statement
my $update_statement = "
UPDATE
reservation
SET
lastcheck = \'$datestring\'
WHERE
id = $reservation_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return $datestring;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update database, reservation id $reservation_id");
return 0;
}
} ## end sub update_reservation_lastcheck
#/////////////////////////////////////////////////////////////////////////////
=head2 update_log_loaded_time
Parameters : $request_logid
Returns : 0 or 1
Description : Updates the finalend and ending fields in the log table for the specified log ID
=cut
sub update_log_loaded_time {
my ($request_logid) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($request_logid))) {
notify($ERRORS{'WARNING'}, 0, "request log ID was not specified");
return ();
}
# Construct the update statement
# Use an IF clause to only update log.loaded if it is NULL
# It should only be updated once to capture the time the image load was done
my $update_statement = "
UPDATE
log
SET
log.loaded = IF(log.loaded IS NULL, NOW(), log.loaded)
WHERE
id = $request_logid
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update database, request log ID $request_logid");
return 0;
}
} ## end sub update_log_loaded_time
#/////////////////////////////////////////////////////////////////////////////
=head2 update_image_name
Parameters : $image_id,$imagerevision_revision_id,$new_image_name
Returns : 0 or 1
Description : Updates the name in the image and imagerevision table
=cut
sub update_image_name {
my ($image_id, $imagerevision_revision_id, $new_image_name) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($image_id))) {
notify($ERRORS{'WARNING'}, 0, "image ID was not specified");
return ();
}
# Construct the update statement
my $update_statement = "
UPDATE
image,
imagerevision
SET
name = \'$new_image_name\',
imagename = \'$new_image_name\'
WHERE
image.id = $image_id AND
imagerevision.id = $imagerevision_revision_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update database, imageID = $image_id imagerevisionID = $imagerevision_revision_id");
return 0;
}
} ## end sub update_image_name
#/////////////////////////////////////////////////////////////////////////////
=head2 windowsroutetable
Parameters : $node, $identity, $privateIP, $clearallPersistent
Returns : 0 or 1
Description : scan route table and remove inactive persistent routes
if clearallPersistent 1 remove all persistent routes
=cut
sub windowsroutetable {
my ($node, $identity, $privateIP, $clearallPersistent) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$clearallPersistent = 0 if (!defined($clearallPersistent));
my ($myadapter, $publicgateway);
my %ip;
my $id = 0;
my ($privateadapter, $publicadapter);
my @ssh = run_ssh_command($node, $identity, "ipconfig", "root");
foreach my $a (@{$ssh[1]}) {
if ($a =~ /Ethernet adapter (.*):/) {
$myadapter = $1;
$ip{$myadapter}{"id"} = $id;
$ip{$myadapter}{"private"} = 0;
}
if ($a =~ /IP Address([\s.]*): $privateIP/) {
$ip{$myadapter}{"private"} = 1;
print "privateadapter $a\n";
}
if ($a =~ /Default Gateway([\s.]*): ([.0-9]*)/) {
$ip{$myadapter}{"gateway"} = $2;
}
$id++;
} ## end foreach my $a (@{$ssh[1]})
#get public gateway
foreach my $key (keys %ip) {
if (!($ip{$key}{private})) {
if (defined($ip{$key}{gateway})) {
$publicgateway = $ip{$key}{gateway};
notify($ERRORS{'OK'}, 0, "setting publicgateway= $publicgateway");
}
else {
notify($ERRORS{'WARNING'}, 0, "warning no gateway for $key");
return 0;
}
} ## end if (!($ip{$key}{private}))
} ## end foreach my $key (keys %ip)
my @proutes;
my @rte = run_ssh_command($node, $identity, "route print", "root");
my $inproute = 0;
foreach my $r (@{$rte[1]}) {
$inproute = 1 if ($r =~ /Persistent Routes:/);
if ($inproute) {
if ($r =~ /\s+(0.0.0.0)\s+(0.0.0.0)\s+([0-9\..]*)\s+([0-9]+)/) {
if (($3 != $publicgateway) || ($clearallPersistent)) {
my $cmd = "route -p DELETE $1 MASK $2 $3 METRIC $4";
my @rtedel = run_ssh_command($node, $identity, "$cmd", "root");
notify($ERRORS{'OK'}, 0, "found inactive persistent route deleting $3");
foreach my $line (@{$rtedel[1]}) {
if ($line =~ /A matching persistent route was deleted/) {
notify($ERRORS{'OK'}, 0, "$3 was successfully deleted");
return 1;
}
if ($line =~ /The route specified was not found/) {
notify($ERRORS{'OK'}, 0, "no route was found $cmd");
return 0;
}
} ## end foreach my $line (@{$rtedel[1]})
} ## end if (($3 != $publicgateway) || ($clearallPersistent...
} ## end if ($r =~ /\s+(0.0.0.0)\s+(0.0.0.0)\s+([0-9\..]*)\s+([0-9]+)/)
} ## end if ($inproute)
} ## end foreach my $r (@{$rte[1]})
notify($ERRORS{'OK'}, 0, "no inactive persistent routes found");
return 1;
} ## end sub windowsroutetable
#/////////////////////////////////////////////////////////////////////////////
=head2 delete_computerloadlog_reservation
Parameters : $reservation_id, optional loadstatename
Returns : 0 failed or 1 success
Description : Deletes rows from the computerloadlog table
=cut
sub delete_computerloadlog_reservation {
my ($reservation_id, $loadstatename) = @_;
# Check the passed parameter
if (!(defined($reservation_id))) {
notify($ERRORS{'WARNING'}, 0, "reservation ID was not specified");
return ();
}
# Construct the SQL statement
my $sql_statement;
# Check if loadstateid was specified
# If so, only delete rows matching the loadstateid
if ($loadstatename) {
$sql_statement = "
DELETE
computerloadlog
FROM
computerloadlog,
computerloadstate
WHERE
computerloadlog.reservationid = $reservation_id
AND computerloadlog.loadstateid = computerloadstate.id
AND computerloadstate.loadstatename = \'$loadstatename\'
";
}
else {
$loadstatename = 'all';
$sql_statement = "
DELETE
computerloadlog
FROM
computerloadlog
WHERE
computerloadlog.reservationid = $reservation_id
";
}
# Call the database execute subroutine
if (database_execute($sql_statement)) {
notify($ERRORS{'OK'}, 0, "deleted rows from computerloadlog table where reservation id=$reservation_id, loadstatename=$loadstatename");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to delete from computerloadlog table where reservation id=$reservation_id, loadstatename=$loadstatename");
return 0;
}
} ## end sub delete_computerloadlog_reservation
#/////////////////////////////////////////////////////////////////////////////
=head2 delete_request
Parameters : $request_id
Returns : 0 or 1
Description : Deletes request and all associated reservations for a given request
ID. This also deletes all computerloadlog rows associated with any
of the reservations.
=cut
sub delete_request {
my ($request_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($request_id))) {
notify($ERRORS{'WARNING'}, 0, "request ID was not specified");
return 0;
}
# Construct the SQL statement
my $sql_computerloadlog_delete = "
DELETE
computerloadlog.*
FROM
request,
reservation,
computerloadlog
WHERE
request.id = $request_id
AND reservation.requestid = request.id
AND computerloadlog.reservationid = reservation.id
";
# Construct the SQL statement
my $sql_request_delete = "
DELETE
request.*,
reservation.*
FROM
request,
reservation
WHERE
request.id = $request_id
AND reservation.requestid = request.id
";
# Try to delete any associated entries in the computerloadlog table
# There may not be any entries, but database_execute should still return 1
if (!database_execute($sql_computerloadlog_delete)) {
notify($ERRORS{'WARNING'}, 0, "unable to delete from computerloadlog table where request id=$request_id");
}
# Try to delete any associated entries in the request and reservation tables
if (database_execute($sql_request_delete)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to delete from request and reservation tables where request id=$request_id");
return 0;
}
} ## end sub delete_request
#/////////////////////////////////////////////////////////////////////////////
=head2 clearfromblockrequest
Parameters : $computer_id
Returns : 0 or 1
Description : removes provided computerid and blcok request id from blockcomputer table
=cut
sub clearfromblockrequest {
my ($computer_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($computer_id))) {
notify($ERRORS{'WARNING'}, 0, "computer_id was not specified");
return 0;
}
# Construct the SQL statement
my $sql_statement = "
DELETE
blockComputers
FROM
blockComputers
WHERE
computerid = $computer_id
";
# Call the database execute subroutine
if (database_execute($sql_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to delete from computerloadlog table where computerid = $computer_id");
return 0;
}
} ## end sub clearfromblockrequest
#/////////////////////////////////////////////////////////////////////////////
=head2 update_sublog_ipaddress
Parameters : $computer_id
Returns : 0 or 1
Description : updates log table with IPaddress of node
when dynamic dhcp is enabled there is no way to track which IP was used
=cut
sub update_sublog_ipaddress {
my ($logid, $computer_ip_address) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($computer_ip_address))) {
notify($ERRORS{'WARNING'}, 0, "computer_ip_address was not specified");
return 0;
}
if (!(defined($logid))) {
notify($ERRORS{'WARNING'}, 0, "logid was not specified");
return 0;
}
# Construct the SQL statement
my $sql_statement = "UPDATE sublog SET IPaddress = \'$computer_ip_address\' WHERE logid=$logid";
# Call the database execute subroutine
if (database_execute($sql_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update sublog table logid = $logid with ipaddress $computer_ip_address");
return 0;
}
} ## end sub update_sublog_ipaddress
#/////////////////////////////////////////////////////////////////////////////
=head2 set_hash_process_id
Parameters : Reference to a hash
Returns : 0 or 1
Description : Sets the process ID of the current process and parent process ID
in a hash, to which a reference was passed.
$hash{PID} = process ID
$hash{PPID} = parent process ID
=cut
sub set_hash_process_id {
my ($hash_ref) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($hash_ref))) {
notify($ERRORS{'WARNING'}, 0, "hash reference was not specified");
return 0;
}
# Make sure it's a hash reference
if (ref($hash_ref) ne "HASH") {
notify($ERRORS{'WARNING'}, 0, "passed parameter is not a hash reference");
return 0;
}
# Get the parent PID and this process's PID
# getppid() doesn't work under Windows so just set it to 0
my $ppid = 0;
$ppid = getppid() if ($^O !~ /win/i);
$hash_ref->{PPID} = $ppid;
my $pid = $$;
$hash_ref->{PID} = $pid;
return 1;
} ## end sub set_hash_process_id
#/////////////////////////////////////////////////////////////////////////////
=head2 rename_vcld_process
Parameters : hash - Reference to hash containing request data
Returns : 0 or 1
Description : Renames running process based on request information. Appends the state
name, request ID, and reservation ID to the process name.
Sets PARENTIMAGE and SUBIMAGE in the hash depending on whether or
reservation ID is the lowest for a request.
=cut
sub rename_vcld_process {
my ($input_data, $process_name) = @_;
my ($package, $filename, $line, $sub) = caller(0);
$filename =~ s/.*\///;
# IMPORTANT: if you change the process name, check the checkonprocess subroutine
# It looks for running reservation processes based on the process name
# Check the argument
my $data_structure;
if (defined($input_data) && (ref $input_data) =~ /HASH/) {
# Get a new data structure object
eval {
$data_structure = new VCL::DataStructure({request_data => $input_data, reservation_id => $input_data->{RESERVATIONID}});
notify($ERRORS{'OK'}, 0, "created DataStructure object from passed hash");
};
if (my $e = Exception::Class::Base->caught()) {
notify($ERRORS{'WARNING'}, 0, "hash was passed but could not be turned into a DataStructure, " . $e->message);
$data_structure = undef;
}
} ## end if (defined($input_data) && (ref $input_data...
elsif (defined($input_data) && (ref $input_data) !~ /DataStructure/) {
notify($ERRORS{'WARNING'}, 0, "passed parameter (" . ref($input_data) . ") is not a reference to a hash or DataStructure, it will be ignored");
$data_structure = undef;
}
else {
$data_structure = $input_data;
}
# Begin assembling a new process name
my $new_process_name = "$PROCESSNAME";
# Append the class name or file name to the process name
if (defined($ENV{class_name})) {
$new_process_name .= (" " . $ENV{class_name});
}
elsif ($filename) {
$new_process_name .= " $filename";
}
# Check if DataStructure, assemble process name with additional information
if (defined $data_structure) {
my $state_name = $data_structure->get_state_name();
if ($state_name ne 'blockrequest') {
my $request_id = $data_structure->get_request_id();
my $request_state_name = $data_structure->get_request_state_name();
my $reservation_id = $data_structure->get_reservation_id();
my $request_forimaging = $data_structure->get_request_forimaging();
my $reservation_count = $data_structure->get_reservation_count();
my $reservation_is_parent = $data_structure->is_parent_reservation();
# Append the request and reservation IDs if they are set
$new_process_name .= " $request_id:$reservation_id";
$new_process_name .= " $request_state_name" if $request_state_name;
$new_process_name .= " imaging" if $request_forimaging;
# Append cluster if there are multiple reservations for this request
notify($ERRORS{'OK'}, 0, "reservation count: $reservation_count");
if ($reservation_count > 1) {
if ($reservation_is_parent) {
$data_structure->get_request_data->{PARENTIMAGE} = 1;
$data_structure->get_request_data->{SUBIMAGE} = 0;
$new_process_name .= " cluster=parent";
}
else {
$data_structure->get_request_data->{PARENTIMAGE} = 0;
$data_structure->get_request_data->{SUBIMAGE} = 1;
$new_process_name .= " cluster=child";
}
} ## end if ($reservation_count > 1)
else {
$data_structure->get_request_data->{PARENTIMAGE} = 1;
$data_structure->get_request_data->{SUBIMAGE} = 0;
}
notify($ERRORS{'OK'}, 0, "PARENTIMAGE: " . $data_structure->get_request_data->{PARENTIMAGE});
notify($ERRORS{'OK'}, 0, "SUBIMAGE: " . $data_structure->get_request_data->{SUBIMAGE});
} ## end if ($state_name ne 'blockrequest')
else {
my $blockrequest_id = $data_structure->get_blockrequest_id();
my $blockrequest_name = $data_structure->get_blockrequest_name();
my $blocktime_id = $data_structure->get_blocktime_id();
# Append the IDs if they are set
$new_process_name .= " $blockrequest_id:$blocktime_id";
$new_process_name .= " '$blockrequest_name'";
}
} ## end if (defined $data_structure)
else {
#notify($ERRORS{'DEBUG'}, 0, "DataStructure object is NOT defined");
}
# Rename this process
$0 = $new_process_name;
notify($ERRORS{'OK'}, 0, "renamed process to \'$0\'");
} ## end sub rename_vcld_process
#/////////////////////////////////////////////////////////////////////////////
=head2 round
Parameters : number
Returns : rounded number
Description : rounds to the nearest whole number
=cut
sub round {
my ($number) = @_;
if ($number >= 0) {
return int($number + .5);
}
else {
return int($number - .5);
}
}
#/////////////////////////////////////////////////////////////////////////////
=head2 set_logfile_path
Parameters : file path
Returns : 0 or 1
Description : This subroutine is for testing purposes. It sets vcld's logfile
path to the parameter passed. It is useful when running automated
tests to isoloate logfile output.
=cut
sub set_logfile_path {
my ($package, $filename, $line, $sub) = caller(0);
($LOGFILE) = @_;
print STDOUT "log file path changed to \'$LOGFILE\'\n";
}
#/////////////////////////////////////////////////////////////////////////////
=head2 get_highest_imagerevision_info
Parameters : $image_id
Returns : Hash containing image revision data
Description :
=cut
sub get_highest_imagerevision_info {
my ($image_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!(defined($image_id))) {
notify($ERRORS{'WARNING'}, 0, "image ID was not specified");
return ();
}
# Select the highest image revision id for the specified image id
my $select_statement = "
SELECT
MAX(imagerevision.id) AS id
FROM
imagerevision
WHERE
imagerevision.imageid = '$image_id'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @selected_rows == 0) {
notify($ERRORS{'OK'}, 0, "image revision data for image id $image_id was not found in the database, 0 rows were returned");
return -1;
}
elsif (scalar @selected_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "" . scalar @selected_rows . " rows were returned from database select");
return ();
}
# A single row was returned (good)
my $imagerevision_id = $selected_rows[0]{id};
return get_imagerevision_info($imagerevision_id);
} ## end sub get_highest_imagerevision_info
#/////////////////////////////////////////////////////////////////////////////
=head2 switch_state
Parameters : $request_data, $request_state_name_new, $computer_state_name_new, $request_log_ending, $exit
Returns : 0 if something goes wrong, exits if successful
Description : Changes the state of this request to the state specified
terminates. The vcld process will then pick up the switched
request. It is important that this process sets the request
laststate to the original state and that vcld does not alter it.
=cut
#/////////////////////////////////////////////////////////////////////////////
sub switch_state {
my ($request_data, $request_state_name_new, $computer_state_name_new, $request_log_ending, $exit) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my ($caller_package, $caller_filename, $caller_line, $caller_sub) = caller(1);
my $caller_info = "$caller_sub($line)";
my $caller = scalar caller;
notify($ERRORS{'OK'}, 0, "called from $caller_info");
# Check the arguments
if (!defined($request_data)) {
notify($ERRORS{'CRITICAL'}, 0, "request data hash reference is undefined");
return 0;
}
elsif (!ref($request_data) eq "HASH") {
notify($ERRORS{'CRITICAL'}, 0, "1st argument is not a hash reference to the request data");
return 0;
}
# Set the default value for exit
$exit = 0 if (!defined($exit));
# Store some hash variables into local variables
my $request_id = $request_data->{id};
my $request_logid = $request_data->{logid};
my $reservation_id = $request_data->{RESERVATIONID};
my $request_state_name_old = $request_data->{state}{name};
my $request_laststate_name_old = $request_data->{laststate}{name};
my $computer_id = $request_data->{reservation}{$reservation_id}{computer}{id};
my $computer_type = $request_data->{reservation}{$reservation_id}{computer}{type};
my $computer_state_name_old = $request_data->{reservation}{$reservation_id}{computer}{state}{name};
my $computer_shortname = $request_data->{reservation}{$reservation_id}{computer}{SHORTNAME};
# Figure out if this is the parent reservation
my @reservation_ids = sort keys %{$request_data->{reservation}};
# The parent reservation has the lowest ID
my $parent_reservation_id = min @reservation_ids;
my $is_parent_reservation;
if ($reservation_id == $parent_reservation_id) {
notify($ERRORS{'DEBUG'}, 0, "parent: parent reservation ID for this request: $parent_reservation_id");
$is_parent_reservation = 1;
}
else {
notify($ERRORS{'DEBUG'}, 0, "child: parent reservation ID for this request: $parent_reservation_id");
$is_parent_reservation = 0;
}
# Update the notify prefix now that we have request info
my $notify_prefix = "req=$request_id:";
# Check if new request state was passed
if (!$request_state_name_new) {
notify($ERRORS{'DEBUG'}, 0, "$notify_prefix request state was not specified, state not changed");
}
elsif (!$is_parent_reservation) {
notify($ERRORS{'DEBUG'}, 0, "$notify_prefix child reservation, request state not changed");
}
else {
# Add an entry to the loadlog
insertloadlog($reservation_id, $computer_id, "info", "$caller: switching request state to $request_state_name_new");
# Update the request state to $request_state_name_new and set laststate to current state
if (update_request_state($request_id, $request_state_name_new, $request_state_name_old)) {
notify($ERRORS{'OK'}, 0, "$notify_prefix request state changed: $request_state_name_old->$request_state_name_new, laststate: $request_laststate_name_old->$request_state_name_old");
insertloadlog($reservation_id, $computer_id, "info", "$caller: request state changed to $request_state_name_new, laststate to $request_state_name_old");
}
else {
notify($ERRORS{'WARNING'}, 0, "$notify_prefix request state could not be changed: $request_state_name_old --> $request_state_name_new, laststate: $request_laststate_name_old->$request_state_name_old");
insertloadlog($reservation_id, $computer_id, "info", "$caller: unable to change request state to $request_state_name_new, laststate to $request_state_name_old");
}
} ## end else [ if (!$request_state_name_new) [elsif (!$is_parent_reservation)
# Update the computer state
if (!$computer_state_name_new) {
notify($ERRORS{'DEBUG'}, 0, "$notify_prefix computer state not specified, $computer_shortname state not changed");
}
else {
# Add an entry to the loadlog
insertloadlog($reservation_id, $computer_id, "info", "$caller: switching computer state to $computer_state_name_new");
# Update the computer state
if (update_computer_state($computer_id, $computer_state_name_new)) {
notify($ERRORS{'OK'}, 0, "$notify_prefix computer $computer_shortname state changed: $computer_state_name_old->$computer_state_name_new");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "$notify_prefix unable to computer $computer_shortname state: $computer_state_name_old->$computer_state_name_new");
}
} ## end else [ if (!$computer_state_name_new)
# Update log table for this request
# Ending can be deleted, released, failed, noack, nologin, timeout, EOR, none
if (!$request_log_ending) {
notify($ERRORS{'DEBUG'}, 0, "$notify_prefix log table id=$request_logid will not be updated");
}
elsif (!$is_parent_reservation) {
notify($ERRORS{'DEBUG'}, 0, "$notify_prefix child reservation, log table id=$request_logid will not be updated");
}
elsif (update_log_ending($request_logid, $request_log_ending)) {
notify($ERRORS{'OK'}, 0, "$notify_prefix log table id=$request_logid, ending set to $request_log_ending");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "$notify_prefix unable to set log table id=$request_logid, ending to $request_log_ending");
}
# Call exit if the state changed, return otherwise
if ($exit) {
insertloadlog($reservation_id, $computer_id, "info", "$caller: process exiting");
notify($ERRORS{'OK'}, 0, "$notify_prefix process exiting");
exit;
}
else {
notify($ERRORS{'OK'}, 0, "$notify_prefix returning");
return;
}
} ## end sub switch_state
#/////////////////////////////////////////////////////////////////////////////
=head2 get_ip_address_from_hosts
Parameters : $host_name
Returns : IP address of specified node if successful, 0 if failed
Description : Searches the local hosts file for a line containing the host
name specified. Returns the corresponding IP address.
=cut
sub get_ip_address_from_hosts {
my ($host_name) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the argument
if (!defined($host_name) || !$host_name) {
notify($ERRORS{'WARNING'}, 0, "computer host name was not specified");
return 0;
}
# Check the OS of the machine running this, set the hosts file accordingly
my $hosts_file_path;
if (lc($^O) =~ /win/i) {
$hosts_file_path = $ENV{SystemRoot} . '\\system32\\drivers\\etc\\hosts';
}
else {
$hosts_file_path = '/etc/hosts';
}
# Retrieve the node's private IP address from the hosts file
# Try to open the hosts file
if (open(HOSTS, $hosts_file_path)) {
notify($ERRORS{'OK'}, 0, "opened hosts file: $hosts_file_path") if $VERBOSE;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to open the hosts file: $hosts_file_path");
return 0;
}
# Find all lines in the hosts file containing the host name
# Make sure the host name has a space in front of it so that host1 != xhost1
# If host name being searched for is followed by a space or period, ignore rest of line
# This accounts for full DNS host names, host1.unity...
# If host name isn't followed by space or period, make sure the end of sting is immediately following
# This accounts for host1 != host1x
# This also accounts for the end of file immediately following the host name
my @hosts_matching_lines = grep(/\s$host_name([\s\.].*)*$/i, <HOSTS>);
# Close the HOSTS file
close HOSTS;
# Make sure only 1 line was returned
if (scalar @hosts_matching_lines == 0) {
notify($ERRORS{'WARNING'}, 0, "unable to find line containing $host_name in hosts file");
return 0;
}
elsif (scalar @hosts_matching_lines > 1) {
notify($ERRORS{'OK'}, 0, "found " . scalar @hosts_matching_lines . " lines containing $host_name in hosts file, first valid match will be used");
}
# Find the IP address
my $ip_address;
for (@hosts_matching_lines) {
my $line = $_;
chomp $line;
# Check for IPv4 address pattern
if ($line =~ /^\s*(([0-9]{1,3}\.{0,1}){4})\s/) {
$ip_address = $1;
notify($ERRORS{'OK'}, 0, "found IPv4 address: $ip_address") if $VERBOSE;
}
# Check for IPv6 address pattern
elsif ($line =~ /^\s*(([0-9a-f]{0,4}:{0,2}){1,8})\s/i) {
$ip_address = $1;
notify($ERRORS{'OK'}, 0, "found IPv6 address: $ip_address") if $VERBOSE;
}
else {
notify($ERRORS{'WARNING'}, 0, "hosts file line does not contain a valid IP address: $line");
next;
}
# Check if the line is a comment
if ($line =~ /^\s*#/) {
notify($ERRORS{'OK'}, 0, "host name found in commented line: $line");
# Proceed to try other matches, hoping for a non-commented match
next;
}
else {
# Line is not commented, return the IP address
return $ip_address;
}
} ## end for (@hosts_matching_lines)
# Check if an IP address was found
if ($ip_address) {
# This should only happen if the host name was found in a commented line
return $ip_address;
}
else {
# Address was not found
notify($ERRORS{'WARNING'}, 0, "unable to find any valid matching address in hosts file");
return 0;
}
} ## end sub get_ip_address_from_hosts
#/////////////////////////////////////////////////////////////////////////////
=head2 firewall_compare_update
Parameters : $node,$reote_IP, $identity, $type
Returns : 0 or 1 (nochange or updated)
Description : compares and updates the firewall for rdp port, specfically for windows
Currently only handles windows and allows two seperate scopes
=cut
sub firewall_compare_update {
my ($node, $remote_IP, $identity, $type) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the arguments
if (!defined($node)) {
notify($ERRORS{'WARNING'}, 0, "node was not specified");
return 0;
}
if (!defined($remote_IP)) {
notify($ERRORS{'WARNING'}, 0, "remote_IP was not specified");
return 0;
}
if (!defined($identity)) {
notify($ERRORS{'WARNING'}, 0, "$identity was not specified");
return 0;
}
if (!defined($type)) {
notify($ERRORS{'WARNING'}, 0, "$type was not specified");
return 0;
}
# Collect settings on node
if ($type =~ /windows/) {
my $cmd = "netsh firewall show portopening enable";
my @sshcmd = run_ssh_command($node, $identity, $cmd, "root");
my $update_scope = 0;
my $scopelook = 0;
foreach my $l (@{$sshcmd[1]}) {
if ($l =~ /^3389\s*TCP/) {
$scopelook = 1;
#print "$l\n";
next;
}
if ($scopelook) {
$scopelook = 0;
if ($l =~ /(\s*Scope:\s*)([.0-9]*)(\/)([.0-9]*)/) {
# addresses into their quads
# current scope
my ($a1q1, $a1q2, $a1q3, $a1q4) = split(/[.]/, $2);
my ($a2q1, $a2q2, $a2q3, $a2q4) = split(/[.]/, $remote_IP);
#start comparing
if ($a1q1 ne $a2q1) {
$update_scope = 1;
notify($ERRORS{'DEBUG'}, 0, "update_scope required addressquad1= $a1q1 addressquad2= $a2q1");
}
if ($a1q2 ne $a2q2) {
$update_scope = 1;
notify($ERRORS{'DEBUG'}, 0, "update_scope required address1uad2= $a1q2 address2quad2= $a2q2");
}
if ($update_scope) {
my $scopeaddress = "$a1q1.$a1q2.0.0/255.255.0.0,$a2q1.$a2q2.0.0/255.255.0.0";
my $netshcmd = "netsh firewall set portopening TCP 3389 RDP enable CUSTOM $scopeaddress";
my @sshcmd1 = run_ssh_command($node, $identity, $netshcmd, "root");
foreach my $line (@{$sshcmd1[1]}) {
if ($line =~ /Ok./) {
notify($ERRORS{'OK'}, 0, "firewall_compare_update: firewall updated with $scopeaddress");
return 1;
}
else {
notify($ERRORS{'DEBUG'}, 0, "firewall_compare_update netsh output $line ");
}
}
} ## end if ($update_scope)
else {
notify($ERRORS{'DEBUG'}, 0, "firewall_compare_update scope of ipaddess matches no change needed");
}
} ## end if ($l =~ /(\s*Scope:\s*)([.0-9]*)(\/)([.0-9]*)/)
} ## end if ($scopelook)
} ## end foreach my $l (@{$sshcmd[1]})
} ## end if ($type =~ /windows/)
else {
#other types go here
return 0;
}
} ## end sub firewall_compare_update
#/////////////////////////////////////////////////////////////////////////////
=head2 update_log_ending
Parameters : $blockrequest_id, $processing
Returns : 0 or 1
Description : Updates the finalend and ending fields in the log table for the specified log ID
=cut
sub update_blockrequest_processing {
my ($blockrequest_id, $processing) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the arguments
if (!defined($blockrequest_id)) {
notify($ERRORS{'WARNING'}, 0, "blockrequest ID was not specified");
return 0;
}
if (!defined($processing)) {
notify($ERRORS{'WARNING'}, 0, "processing was not specified");
return 0;
}
# Construct the update statement
my $update_statement = "
UPDATE
blockRequest
SET
blockRequest.processing = $processing
WHERE
blockRequest.id = $blockrequest_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update blockRequest table, id=$blockrequest_id, processing=$processing");
return 0;
}
} ## end sub update_blockrequest_processing
#/////////////////////////////////////////////////////////////////////////////
=head2 get_management_node_blockrequests
Parameters : $managementnode_id
Returns : hash containing block request info
Description :
=cut
sub get_management_node_blockrequests {
my ($managementnode_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
# Check the passed parameter
if (!defined($managementnode_id)) {
notify($ERRORS{'WARNING'}, 0, "management node ID was not specified");
return;
}
# Create the select statement
my $select_statement = "
SELECT
blockRequest.id AS blockRequest_id,
blockRequest.name AS blockRequest_name,
blockRequest.imageid AS blockRequest_imageid,
blockRequest.numMachines AS blockRequest_numMachines,
blockRequest.groupid AS blockRequest_groupid,
blockRequest.repeating AS blockRequest_repeating,
blockRequest.ownerid AS blockRequest_ownerid,
blockRequest.admingroupid AS blockRequest_admingroupid,
blockRequest.managementnodeid AS blockRequest_managementnodeid,
blockRequest.expireTime AS blockRequest_expireTime,
blockRequest.processing AS blockRequest_processing,
blockTimes.id AS blockTimes_id,
blockTimes.blockRequestid AS blockTimes_blockRequestid,
blockTimes.start AS blockTimes_start,
blockTimes.end AS blockTimes_end,
blockTimes.processed AS blockTimes_processed
FROM
blockRequest
LEFT JOIN
blockTimes ON (
blockRequest.id = blockTimes.blockRequestid
)
WHERE
blockRequest.managementnodeid = $managementnode_id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @selected_rows = database_select($select_statement);
# Check to make sure 1 or more rows were returned
if (scalar @selected_rows == 0) {
return 0;
}
# Build the hash
my %blockrequests;
for (@selected_rows) {
my %blockrequest_row = %{$_};
# Get the blockRequest id and blockTimes id
my $blockrequest_id = $blockrequest_row{blockRequest_id};
my $blocktimes_id = $blockrequest_row{blockTimes_id};
$blocktimes_id = -1 if !$blocktimes_id;
# Loop through all the columns returned for the blockrequest
foreach my $key (keys %blockrequest_row) {
my $value = $blockrequest_row{$key};
# Create another variable by stripping off the column_ part of each key
# This variable stores the original (correct) column name
(my $original_key = $key) =~ s/^.+_//;
$value = '-1' if (!defined($value));
if ($key =~ /blockRequest_/) {
$blockrequests{$blockrequest_id}{$original_key} = $value;
}
elsif ($key =~ /blockTimes_/) {
$blockrequests{$blockrequest_id}{blockTimes}{$blocktimes_id}{$original_key} = $value;
}
else {
notify($ERRORS{'WARNING'}, 0, "unknown key found in SQL data: $key");
}
} ## end foreach my $key (keys %blockrequest_row)
} ## end for (@selected_rows)
return \%blockrequests;
} ## end sub get_management_node_blockrequests
#/////////////////////////////////////////////////////////////////////////////
=head2 insert_request
Parameters : $managementnode_id, $request_state_name, $request_laststate_name, $end_minutes_in_future, $user_unityid, $computer_id, $image_id, $imagerevision_id
Returns : 1 if successful, 0 if failed
Description :
=cut
sub insert_request {
my ($managementnode_id, $request_state_name, $request_laststate_name, $request_logid, $user_unityid, $computer_id, $image_id, $imagerevision_id, $start_minutes_in_future, $end_minutes_in_future) = @_;
if (!$request_state_name) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory request key: state_name");
return 0;
}
if (!$request_laststate_name) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory request key: laststate_name");
return 0;
}
if (!$user_unityid) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory request key: user_unityid");
return 0;
}
if (!$computer_id) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory reservation key: computer_id");
return 0;
}
if (!$image_id) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory reservation key: image_id");
return 0;
}
if (!$imagerevision_id) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory reservation key: imagerevision_id");
return 0;
}
if (!$managementnode_id) {
notify($ERRORS{'WARNING'}, 0, "missing mandatory reservation key: managementnode_id");
return 0;
}
my $insert_request_statment = "
INSERT INTO
request
(
request.stateid,
request.laststateid,
request.userid,
request.logid,
request.forimaging,
request.test,
request.preload,
request.start,
request.end,
request.daterequested
)
VALUES
(
(SELECT id FROM state WHERE state.name = '$request_state_name'),
(SELECT id FROM state WHERE state.name = '$request_laststate_name'),
(SELECT id FROM user WHERE user.unityid = '$user_unityid'),
'$request_logid',
'0',
'0',
'0',
TIMESTAMPADD(MINUTE, $start_minutes_in_future, NOW()),
TIMESTAMPADD(MINUTE, $end_minutes_in_future, NOW()),
NOW()
)
";
# Execute the request insert statement
# If successful, the id of the newly inserted row is returned
my $request_id = database_execute($insert_request_statment);
if ($request_id) {
notify($ERRORS{'OK'}, 0, "inserted new reload request into request table, request id=$request_id");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "failed to insert new reload request into request table");
return 0;
}
my $insert_reservation_statment = "
INSERT INTO
reservation
(
reservation.requestid,
reservation.computerid,
reservation.imageid,
reservation.imagerevisionid,
reservation.managementnodeid
)
VALUES
(
'$request_id',
'$computer_id',
'$image_id',
'$imagerevision_id',
'$managementnode_id'
)
";
# Execute the reservation insert statement
# If successful, the id of the newly inserted row is returned
my $reservation_id = database_execute($insert_reservation_statment);
if ($reservation_id) {
notify($ERRORS{'OK'}, 0, "inserted new reload request into reservation table, reservation id=$reservation_id");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "failed to insert new reload request into reservation table");
return 0;
}
return ($request_id, $reservation_id);
} ## end sub insert_request
#/////////////////////////////////////////////////////////////////////////////
=head2 insert_reload_request
Parameters : $request_data_hash_reference
Returns : nothing, always calls exit
Description : Changes this request to a reload request then
terminates. The vcld process will then pick up the reload
request. It is important that this process sets the request
laststate to 'reclaim' and that vcld does not alter it.
=cut
sub insert_reload_request {
my ($request_data) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my ($calling_package, $calling_filename, $calling_line, $calling_sub) = caller(0);
# Store some hash variables into local variables
my $request_id = $request_data->{id};
my $request_state_name = $request_data->{state}{name};
my $request_laststate_name = $request_data->{laststate}{name};
my $reservation_id = $request_data->{RESERVATIONID};
my $computer_id = $request_data->{reservation}{$reservation_id}{computer}{id};
my $computer_type = $request_data->{reservation}{$reservation_id}{computer}{type};
my $managementnode_id = $request_data->{reservation}{$reservation_id}{managementnode}{id};
my $request_logid = $request_data->{logid};
my $user_unityid = $request_data->{user}{unityid};
my $image_id = $request_data->{reservation}{$reservation_id}{imageid};
my $imagerevision_id = $request_data->{reservation}{$reservation_id}{imagerevisionid};
# Assemble a consistent prefix for notify messages
my $notify_prefix = "req=$request_id:";
# Add an entry to the loadlog
if ($computer_type eq "blade") {
insertloadlog($reservation_id, $computer_id, "loadimageblade", "$calling_sub: switching request state to reload");
}
elsif ($computer_type eq "virtualmachine") {
insertloadlog($reservation_id, $computer_id, "loadimagevmware", "$calling_sub: switching request state to reload");
}
else {
insertloadlog($reservation_id, $computer_id, "info", "$calling_sub: switching request state to reload");
}
# Check to make sure computer state is not currently reload or reloading
# It's possible for reclaimed cluster reservations to attempt to insert multiple reloads for child reservations
# because only the parent can update the request state
my $current_computer_state_name = get_computer_current_state_name($computer_id);
if ($current_computer_state_name =~ /reload/) {
notify($ERRORS{'WARNING'}, 0, "$notify_prefix current computer state is $current_computer_state_name, reload request will not be inserted");
return 0;
}
# Modify computer state so reload will process
if (update_computer_state($computer_id, "reload")) {
notify($ERRORS{'OK'}, 0, "$notify_prefix setting computerid $computer_id into reload state");
}
else {
notify($ERRORS{'WARNING'}, 0, "$notify_prefix unable to set computerid $computer_id reload state");
}
# Attempt to create a new reload request
my $request_id_reload;
if ($request_id_reload = insert_request($managementnode_id, 'reload', $request_laststate_name, $request_logid, 'vclreload', $computer_id, $image_id, $imagerevision_id, '0', '30')) {
notify($ERRORS{'OK'}, 0, "$notify_prefix inserted new reload request, id=$request_id_reload nodeid=$computer_id, imageid=$image_id, imagerevision_id=$imagerevision_id");
insertloadlog($reservation_id, $computer_id, "info", "$calling_sub: created new reload request");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "$notify_prefix failed to insert new reload request");
return 0;
}
return 1;
} ## end sub insert_reload_request
#/////////////////////////////////////////////////////////////////////////////
=head2 update_cluster_info
Parameters :data hash
Returns : 0 or 1
Description :
=cut
sub update_cluster_info {
my ($request_data) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my ($calling_package, $calling_filename, $calling_line, $calling_sub) = caller(0);
my $reservation_id = $request_data->{RESERVATIONID};
my $computer_short_name = $request_data->{reservation}{$reservation_id}{computer}{SHORTNAME};
my $image_OS_type = $request_data->{reservation}{$reservation_id}{image}{OS}{type};
my $cluster_info = "/tmp/$computer_short_name.cluster_info";
my @cluster_string = "";
foreach my $rid (keys %{$request_data->{reservation}}) {
if ($rid == $reservation_id) {
push(@cluster_string, "parent= $request_data->{reservation}{$rid}{computer}{IPaddress}" . "\n");
}
else {
push(@cluster_string, "child= $request_data->{reservation}{$rid}{computer}{IPaddress}" . "\n");
}
}
if (open(CLUSTERFILE, ">$cluster_info")) {
print CLUSTERFILE @cluster_string;
close(CLUSTERFILE);
}
else {
notify($ERRORS{'OK'}, 0, "could not write to $cluster_info");
}
my $identity;
#scp cluster file to each node
my $targetpath;
foreach my $rid (keys %{$request_data->{reservation}}) {
$identity = $request_data->{reservation}{$rid}{image}{IDENTITY};
my $node_name = $request_data->{reservation}{$rid}{computer}{SHORTNAME};
if ($image_OS_type =~ /linux/i) {
$targetpath = "$node_name:/etc/cluster_info";
}
elsif ($image_OS_type =~ /windows/i) {
$targetpath = "$node_name:C:\/cluster_info";
}
else {
$targetpath = "$node_name:/etc/cluster_info";
}
if (run_scp_command($cluster_info, $targetpath, $identity)) {
notify($ERRORS{'OK'}, 0, " successfully copied cluster_info file to $node_name");
}
} ## end foreach my $rid (keys %{$request_data->{reservation...
unlink $cluster_info;
return 1;
} ## end sub update_cluster_info
#/////////////////////////////////////////////////////////////////////////////
=head2 format_data
Parameters :
Returns : 0 or 1
Description :
=cut
sub format_data {
my $return_string;
my $level = 0;
$level = $_[scalar(@_) - 2] if (scalar(@_) > 2 && !ref($_[scalar(@_) - 2]));
my $name = '';
$name = $_[scalar(@_) - 1] if (scalar(@_) > 1 && !ref($_[scalar(@_) - 1]));
my $type;
my $data;
if (ref($_[0]) eq "HASH") {
$data = $_[0];
$type = '%';
}
elsif (ref($_[0]) eq "ARRAY") {
my $index = 0;
for (@{$_[0]}) {
$data->{$index} = $_;
$index++;
}
$type = '@';
}
elsif (ref($_[0]) eq "SCALAR") {
$data = $_[0];
$type = '$';
}
else {
$data = \$_[0];
$type = '$';
$return_string .= "ref: " . ref($_[0]) . "\n";
$return_string .= "data: " . $_[0] . "\n";
return $return_string;
}
$data = 'NULL' if (!defined $data);
$return_string .= "$type$name\n";
# Loop through values
foreach my $key (sort {lc($a) cmp lc($b)} keys(%{$data})) {
my $value = $data->{$key};
$value = 'NULL' if (!defined $value);
for (my $count = 0; $count < $level; $count++) {
$return_string .= " " if ($count < $level);
}
$return_string .= "|--";
if (ref($value) eq 'SCALAR') {
$value = "\\'$$value'";
}
elsif (!ref($value) && $value ne 'NULL') {
$value = "'$value'";
}
if (!ref($value)) {
if ($type eq '@') {
$return_string .= "[$key] = $value\n";
}
elsif ($type eq '%') {
$return_string .= "{$key} = $value\n";
}
}
else {
if ($type eq '@') {
#$return_string .= "\[$key\]\n";
$return_string .= format_data($value, $level + 1, "$name\[$key\]");
}
elsif ($type eq '%') {
#$return_string .= "\{$key\} $name\n";
$return_string .= format_data($value, $level + 1, "$name\{$key\}");
}
} ## end else [ if (!ref($value))
} ## end foreach my $key (sort {lc($a) cmp lc($b)} keys(...
return $return_string;
} ## end sub format_data
#/////////////////////////////////////////////////////////////////////////////
=head2 get_caller_trace
Parameters : $level_limit - number of previous calls to return
Returns : multi-line string containing subroutine caller information
Description :
=cut
sub get_caller_trace {
my ($level_limit, $brief_output) = @_;
$level_limit = 4 if !$level_limit;
# Add one to make the argument usage more intuitive
# One of the levels is the subroutine which called this
$level_limit++;
my $caller_trace = "";
for (1 .. $level_limit) {
my $caller_index = $_;
if (caller($caller_index)) {
my ($package_last, $filename_last, $line_last, $sub_last) = caller($caller_index - 1);
my ($package, $filename, $line, $sub) = caller($caller_index);
$filename_last =~ s/.*\///;
$sub =~ s/.*:://;
if ($brief_output) {
$caller_trace .= (($caller_index - 1) * -1) . ":$filename_last:$sub:$line_last;";
}
else {
$caller_trace .= "(" . sprintf("% d", (($caller_index - 1) * -1)) . ") $filename_last, $sub (line: $line_last)\n";
}
} ## end if (caller($caller_index))
else {
last;
}
} ## end for (1 .. $level_limit)
# Remove the trailing semicolon if brief output is used
$caller_trace =~ s/;$//;
# Chomp the trailing newline if brief output isn't used
chomp $caller_trace;
return $caller_trace;
} ## end sub get_caller_trace
#/////////////////////////////////////////////////////////////////////////////
=head2 get_management_node_id
Parameters :
Returns :
Description :
=cut
sub get_management_node_id {
my $management_node_id;
# Check the management_node_id environment variable
if ($ENV{management_node_id}) {
notify($ERRORS{'DEBUG'}, 0, "environment variable: $ENV{management_node_id}");
return $ENV{management_node_id};
}
else {
notify($ERRORS{'DEBUG'}, 0, "management_node_id environment variable not set");
}
# If $management_node_id wasn't set using the env variable, try the subroutine
my $management_node_info = get_management_node_info();
if ($management_node_info && ($management_node_id = $management_node_info->{id})) {
notify($ERRORS{'DEBUG'}, 0, "get_managementnode_info(): $management_node_id");
$ENV{management_node_id} = $management_node_id;
return $management_node_id;
}
else {
notify($ERRORS{'DEBUG'}, 0, "get_management_node_info() failed");
}
notify($ERRORS{'WARNING'}, 0, "management node ID could not be determined");
return 0;
} ## end sub get_management_node_id
#/////////////////////////////////////////////////////////////////////////////
sub get_database_table_columns {
my $database = 'information_schema';
my $select_all_table_columns = "
SELECT DISTINCT
TABLES.TABLE_NAME,
COLUMNS.COLUMN_NAME
FROM
TABLES,
COLUMNS
WHERE
COLUMNS.TABLE_SCHEMA = \'$DATABASE\'
AND
TABLES.TABLE_NAME = COLUMNS.TABLE_NAME
";
# Call the database select subroutine
my @rows = database_select($select_all_table_columns, $database);
# Check to make sure 1 row was returned
if (scalar @rows == 0) {
notify($ERRORS{'WARNING'}, 0, "unable to get database table columns, 0 rows were returned from database select");
return 0;
}
# Use the map function to populate a hash of arrays
# The hash keys are the table names
# The hash values are arrays of column names
my %return_hash;
map({push @{$return_hash{$_->{TABLE_NAME}}}, $_->{COLUMN_NAME}} @rows);
return \%return_hash;
} ## end sub get_database_table_columns
#/////////////////////////////////////////////////////////////////////////////
sub switch_vmhost_id {
my ($computer_id, $host_id) = @_;
my ($package, $filename, $line, $sub) = caller(0);
my ($caller_package, $caller_filename, $caller_line, $caller_sub) = caller(1);
my $caller_info = "$caller_sub($line)";
my $caller = scalar caller;
notify($ERRORS{'OK'}, 0, "called from $caller_info");
# Check the arguments
if (!defined($computer_id)) {
notify($ERRORS{'CRITICAL'}, 0, "computer_id is undefined");
return 0;
}
if (!(defined($host_id)) || !$host_id) {
notify($ERRORS{'WARNING'}, 0, "$host_id is either not defined or 0, using NULL");
$host_id = 'NULL';
}
# Construct the update statement
my $update_statement = "
UPDATE
computer
SET
vmhostid = $host_id
WHERE
computer.id = $computer_id
";
# Call the database execute subroutine
if (database_execute($update_statement)) {
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to update computer table, id=$computer_id, vmhostid=$host_id");
return 0;
}
} ## end sub switch_vmhost_id
#/////////////////////////////////////////////////////////////////////////////
=head2 reservations_ready
Parameters : request ID
Returns : 1 if all reservations are ready, 0 if any are not ready, undefined if any failed
Description :
=cut
sub reservations_ready {
my ($request_id) = @_;
# Make sure request ID was passed
if (!$request_id) {
notify($ERRORS{'WARNING'}, 0, "request ID argument was not passed");
return;
}
my $select_statement = "
SELECT
reservation.id AS reservation_id,
computerloadstate.loadstatename
FROM
request,
reservation
LEFT JOIN
computerloadlog
ON (
computerloadlog.reservationid = reservation.id
)
LEFT JOIN
computerloadstate
ON (
computerloadstate.id = computerloadlog.loadstateid
)
WHERE
request.id = $request_id
AND reservation.requestid = request.id
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @computerloadlog_rows = database_select($select_statement);
# Check to make sure 1 row was returned
if (scalar @computerloadlog_rows == 0) {
notify($ERRORS{'WARNING'}, 0, "reservations associated with request $request_id could not be retrieved from the database, 0 rows were returned");
return;
}
my %reservation_status;
# Loop through the rows, check the loadstate
for my $computerloadlog_row (@computerloadlog_rows) {
my $reservation_id = $computerloadlog_row->{reservation_id};
my $computerloadstate_name = $computerloadlog_row->{loadstatename};
# Initialize the hash key for the reservation if it isn't defined
if (!defined($reservation_status{$reservation_id})) {
$reservation_status{$reservation_id} = 'not ready';
}
# Skip if loadstatename is undefined, means no computerloadlog rows exist for the reservation
if (!defined($computerloadstate_name)) {
next;
}
# Only populate hash keys with loadstatnames we care about
# Ignore 'info' and other entries
if ($computerloadstate_name =~ /loadimagecomplete|nodeready|failed/i) {
# Update the reservation hash key, don't overwrite 'failed'
if ($reservation_status{$reservation_id} !~ /failed/) {
$reservation_status{$reservation_id} = $computerloadstate_name;
}
}
} ## end for my $computerloadlog_row (@computerloadlog_rows)
# Assemble a string of all of the statuses
my $status_string = '';
my $failed = 0;
my $ready = 1;
foreach my $reservation_check_id (sort keys(%reservation_status)) {
my $reservation_check_status = $reservation_status{$reservation_check_id};
$status_string .= "reservation $request_id:$reservation_check_id: $reservation_check_status\n";
# Set the failed flag to 1 if any reservations failed
if ($reservation_check_status =~ /failed/i) {
$failed = 1;
}
# Set the ready flag to 0 if any reservations are set to 0 (matching state wasn't found)
if ($reservation_check_status =~ /not ready/) {
$ready = 0;
}
} ## end foreach my $reservation_check_id (sort keys(%reservation_status...
if ($failed) {
notify($ERRORS{'WARNING'}, 0, "request $request_id has failed reservations, returning undefined:\n$status_string");
return;
}
if ($ready) {
notify($ERRORS{'OK'}, 0, "all reservations for request $request_id are ready, returning $ready:\n$status_string");
}
else {
notify($ERRORS{'OK'}, 0, "not all reservations for request $request_id are ready, returning $ready:\n$status_string");
}
return $ready;
} ## end sub reservations_ready
##/////////////////////////////////////////////////////////////////////////////
#
#=head2 reservations_ready
#
# Parameters : request ID
# Returns : 1 if all reservations are ready, 0 if any are not ready, undefined if any failed
# Description :
#
#=cut
#
#sub reservations_ready {
# my ($request_id) = @_;
#
# # Make sure request ID was passed
# if (!$request_id) {
# notify($ERRORS{'WARNING'}, 0, "request ID argument was not passed");
# return;
# }
#
# my $select_statement = "
# SELECT
# requeststate.name AS request_state,
# reservation.id AS reservation_id,
# computerloadstate.loadstatename,
# computerstate.name AS computer_state
#
# FROM
# request,
# state requeststate,
# reservation
#
# LEFT JOIN
# computerloadlog
# ON (
# computerloadlog.reservationid = reservation.id
# )
#
# LEFT JOIN
# computerloadstate
# ON (
# computerloadstate.id = computerloadlog.loadstateid
# ),
#
# computer,
# state computerstate
#
# WHERE
# request.id = $request_id
# AND reservation.requestid = request.id
# AND computer.id = reservation.computerid
# AND computerstate.id = computer.stateid
# AND requeststate.id = request.stateid
# ";
#
# # Call the database select subroutine
# # This will return an array of one or more rows based on the select statement
# my @computerloadlog_rows = database_select($select_statement);
#
# # Check to make sure 1 row was returned
# if (scalar @computerloadlog_rows == 0) {
# notify($ERRORS{'WARNING'}, 0, "reservations associated with request $request_id could not be retrieved from the database, 0 rows were returned");
# return;
# }
#
# my %reservation_status;
#
# # Loop through the rows, check the loadstate and computer state
# for my $computerloadlog_row (@computerloadlog_rows) {
# my $reservation_id = $computerloadlog_row->{reservation_id};
# my $request_state_name = $computerloadlog_row->{request_state};
# my $computerloadstate_name = $computerloadlog_row->{loadstatename};
# my $computer_state_name = $computerloadlog_row->{computer_state};
#
# # If request state has been changed to reserved or inuse, assume all reservations are ready
# if ($request_state_name =~ /^(reserved|inuse)$/i) {
# notify($ERRORS{'OK'}, 0, "assuming all reservations are ready, request state is $request_state_name");
# return 1;
# }
#
# # If request state has been changed to failed or maintenance, return fail
# if ($request_state_name =~ /^(failed|maintenance)$/i) {
# notify($ERRORS{'WARNING'}, 0, "unable to determine if all reservations are ready, request state = $request_state_name");
# return;
# }
#
# # If request been deleted, return 0
# if ($request_state_name =~ /^(deleted)$/i) {
# notify($ERRORS{'OK'}, 0, "request state = $request_state_name");
# return 0;
# }
#
#
# # Check for computerloadstate = failed
# if ($computerloadstate_name =~ /failed/i) {
# $reservation_status{$reservation_id} = "failed: computerloadstate = $computerloadstate_name";
# next;
# }
#
# # Check for bad computer states
# if ($computer_state_name =~ /^(failed|maintenance|deleted)$/i) {
# $reservation_status{$reservation_id} = "failed: computer state = $computer_state_name";
# next
# }
#
#
# # Skip if loadstatename is undefined, means no computerloadlog rows exist for the reservation
# if (!defined($computerloadstate_name)) {
# $reservation_status{$reservation_id} = 'not ready: no computerloadlog entries exist';
# next;
# }
#
# # Check for loadstatnames we care about
# if ($computerloadstate_name =~ /^(loadimagecomplete|nodeready|reserved)$/i) {
# $reservation_status{$reservation_id} = "ready: computerloadstate $computerloadstate_name";
# next;
# }
#
#
# # Check if computer state indicates it isn't ready
# if ($computer_state_name =~ /^(reload|reloading|available)$/i) {
# $reservation_status{$reservation_id} = "not ready: computer state = $computer_state_name";
# next;
# }
#
# notify($ERRORS{'WARNING'}, 0, "unexpected situation: reservation $reservation_id, request state: $request_state_name, computer state: $computer_state_name, computerloadstate: $computerloadstate_name");
# $reservation_status{$reservation_id} = "not ready: unexpected situation";
#
# } ## end for my $computerloadlog_row (@computerloadlog_rows)
#
#
# # Assemble a string of all of the statuses
# my $status_string = '';
# my $failed = 0;
# my $ready = 1;
# foreach my $reservation_check_id (sort keys(%reservation_status)) {
# my $reservation_check_status = $reservation_status{$reservation_check_id};
# $status_string .= "reservation $request_id:$reservation_check_id: $reservation_check_status\n";
#
# # Set the failed flag to 1 if any reservations failed
# if ($reservation_check_status =~ /failed/i) {
# $failed = 1;
# }
#
# # Set the ready flag to 0 if any reservations are set to 0 (matching state wasn't found)
# if ($reservation_check_status =~ /not ready/) {
# $ready = 0;
# }
# } ## end foreach my $reservation_check_id (sort keys(%reservation_status...
#
# if ($failed) {
# notify($ERRORS{'WARNING'}, 0, "request $request_id has failed reservations, returning undefined:\n$status_string");
# return;
# }
#
# if ($ready) {
# notify($ERRORS{'OK'}, 0, "all reservations for request $request_id are ready, returning $ready:\n$status_string");
# }
# else {
# notify($ERRORS{'OK'}, 0, "not all reservations for request $request_id are ready, returning $ready:\n$status_string");
# }
#
# return $ready;
#
#} ## end sub reservations_ready
#/////////////////////////////////////////////////////////////////////////////
=head2 reservation_being_processed
Parameters : reservation ID
Returns : true if reservation is avtively being processed, false otherwise
Description : Checks the computerloadlog table for rows matching the
reservation ID and loadstate = begin. Returns true if any
matching rows exist, false otherwise.
=cut
sub reservation_being_processed {
my ($reservation_id) = @_;
# Make sure reservation ID was passed
if (!$reservation_id) {
notify($ERRORS{'WARNING'}, 0, "reservation ID argument was not passed");
return;
}
my $select_statement = "
SELECT
computerloadlog.*
FROM
computerloadlog,
computerloadstate
WHERE
computerloadlog.reservationid = $reservation_id
AND computerloadlog.loadstateid = computerloadstate.id
AND computerloadstate.loadstatename = \'begin\'
";
# Call the database select subroutine
# This will return an array of one or more rows based on the select statement
my @computerloadlog_rows = database_select($select_statement);
# Check if at least 1 row was returned
if (scalar @computerloadlog_rows == 1) {
notify($ERRORS{'DEBUG'}, 0, "computerloadlog 'begin' entry exists for reservation");
return 1;
}
elsif (scalar @computerloadlog_rows > 1) {
notify($ERRORS{'WARNING'}, 0, "multiple computerloadlog 'begin' entries exist for reservation");
return 1;
}
else {
notify($ERRORS{'DEBUG'}, 0, "computerloadlog 'begin' entry does NOT exist for reservation $reservation_id");
0
}
## Check for any running processes
#my $pgrep_command = "pgrep -fl 'VCL::.*:$reservation_id '";
#$pgrep_command .= ' 2>&1';
#notify($ERRORS{'DEBUG'}, 0, "searching for process via: $pgrep_command");
#
#my $pgrep_output = `$pgrep_command`;
#my $pgrep_exit_status = $?;
#notify($ERRORS{'DEBUG'}, 0, "pgrep exit status=$pgrep_exit_status, output: $pgrep_output");
#
#if ($pgrep_exit_status == 0) {
# notify($ERRORS{'DEBUG'}, 0, "reservation is being processed by:\n$pgrep_output");
# return 1;
#}
#elsif ($pgrep_exit_status == 1) {
# notify($ERRORS{'DEBUG'}, 0, "did not find any running processes for reservation, returning 0");
# return 0;
#}
#else {
# notify($ERRORS{'WARNING'}, 0, "error occurred running command: $pgrep_command, exit status: $pgrep_exit_status"); #, output: $pgrep_output");
# return 0;
#}
}
#/////////////////////////////////////////////////////////////////////////////
=head2 string_to_ascii
Parameters : string
Returns : string with special ASCII characters replaced with character
names
Description : Takes the string passed, checks each character, and replaces
special ASCII characters with the character name. For
example, "This is a\r\nstring." would return
"This[SP]is[SP]a[CR][LF]string."
=cut
sub string_to_ascii {
my $string = shift;
my %ascii_codes = (
0 => 'NUL',
1 => 'SOH',
2 => 'STX',
3 => 'ETX',
4 => 'EOT',
5 => 'ENQ',
6 => 'ACK',
7 => 'BEL',
8 => 'BS',
9 => 'HT',
10 => 'LF',
11 => 'VT',
12 => 'FF',
13 => 'CR',
14 => 'SO',
15 => 'SI',
16 => 'DLE',
17 => 'DC1',
18 => 'DC2',
19 => 'DC3',
20 => 'DC4',
21 => 'NAK',
22 => 'SYN',
23 => 'ETB',
24 => 'CAN',
25 => 'EM',
26 => 'SUB',
27 => 'ESC',
28 => 'FS',
29 => 'GS',
30 => 'RS',
31 => 'US',
32 => 'SP',
127 => 'DEL',
);
my $ascii_value_string;
foreach my $ascii_code (unpack("C*", $string)) {
if (defined($ascii_codes{$ascii_code})) {
$ascii_value_string .= "[$ascii_codes{$ascii_code}]";
}
else {
$ascii_value_string .= pack("C*", $ascii_code);
}
}
return $ascii_value_string;
}
#/////////////////////////////////////////////////////////////////////////////
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