| #!/usr/bin/perl -w |
| ############################################################################### |
| # $Id$ |
| ############################################################################### |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| ############################################################################### |
| |
| =head1 NAME |
| |
| VCL::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 HTTP::Headers; |
| use RPC::XML::Client; |
| use Scalar::Util 'blessed'; |
| use Data::Dumper; |
| |
| #use Date::Calc qw(Delta_DHMS Time_to_Date Date_to_Time); |
| |
| require Exporter; |
| our @ISA = qw(Exporter); |
| |
| our @EXPORT = qw( |
| _checknstartservice |
| _getcurrentimage |
| _machine_os |
| _pingnode |
| _sshd_status |
| changelinuxpassword |
| 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 |
| create_management_node_directory |
| database_execute |
| database_select |
| delete_computerloadlog_reservation |
| delete_request |
| disablesshd |
| escape_file_path |
| firewall_compare_update |
| format_data |
| format_number |
| get_affiliation_info |
| get_block_request_image_info |
| get_caller_trace |
| get_computer_current_state_name |
| get_computer_grp_members |
| get_computer_ids |
| get_computer_info |
| get_computers_controlled_by_MN |
| get_current_file_name |
| get_current_package_name |
| get_current_subroutine_name |
| get_group_name |
| get_highest_imagerevision_info |
| get_image_info |
| get_imagemeta_info |
| get_imagerevision_info |
| get_management_node_blockrequests |
| get_management_node_id |
| get_management_node_info |
| get_management_node_requests |
| get_management_predictive_info |
| get_module_info |
| get_next_image_default |
| get_os_info |
| get_production_imagerevision_info |
| get_request_by_computerid |
| get_request_end |
| get_request_info |
| get_resource_groups |
| get_managable_resource_groups |
| get_user_info |
| get_vmhost_info |
| getdynamicaddress |
| getimagesize |
| getnewdbh |
| getpw |
| getusergroupmembers |
| help |
| hostname |
| insert_reload_request |
| insert_request |
| insertloadlog |
| is_management_node_process_running |
| is_inblockrequest |
| is_public_ip_address |
| is_request_deleted |
| is_request_imaging |
| is_valid_dns_host_name |
| is_valid_ip_address |
| isconnected |
| isfilelocked |
| kill_reservation_process |
| known_hosts |
| lockfile |
| mail |
| makedatestring |
| monitorloading |
| nmap_port |
| normalize_file_path |
| notify |
| notify_via_IM |
| notify_via_msg |
| notify_via_wall |
| parent_directory_path |
| preplogfile |
| read_file_to_array |
| rename_vcld_process |
| reservation_being_processed |
| reservations_ready |
| restoresshkeys |
| round |
| run_command |
| run_scp_command |
| run_ssh_command |
| set_hash_process_id |
| set_logfile_path |
| set_managementnode_state |
| setimageid |
| setnextimage |
| setstaticaddress |
| setup_confirm |
| setup_get_array_choice |
| setup_get_hash_choice |
| setup_get_input_string |
| setup_print_wrap |
| string_to_ascii |
| switch_state |
| switch_vmhost_id |
| time_exceeded |
| timefloor15interval |
| unlockfile |
| update_blockrequest_processing |
| update_cluster_info |
| update_computer_address |
| update_computer_state |
| update_computer_lastcheck |
| update_currentimage |
| update_computer_imagename |
| 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 |
| write_currentimage_txt |
| xmlrpc_call |
| |
| $CONF_FILE_PATH |
| $DAEMON_MODE |
| $DATABASE |
| $DEFAULTHELPEMAIL |
| $GATEWAY |
| $FQDN |
| $jabPass |
| $jabPort |
| $jabResource |
| $jabServer |
| $jabUser |
| $LOGFILE |
| $MYSQL_SSL |
| $MYSQL_SSL_CERT |
| $PIDFILE |
| $PROCESSNAME |
| $WINDOWS_ROOT_PASSWORD |
| $SERVER |
| $SETUP_MODE |
| $TOOLS |
| $VERBOSE |
| $WRTPASS |
| $WRTUSER |
| $XMLRPC_USER |
| $XMLRPC_PASS |
| $XMLRPC_URL |
| %ERRORS |
| %OPTIONS |
| |
| ); |
| |
| #our %ERRORS=('DEPENDENT'=>4,'UNKNOWN'=>3,'OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'MAILMASTERS'=>5); |
| |
| INIT { |
| # Parse config file and set globals |
| our ($JABBER, $jabServer, $jabUser, $jabPass, $jabResource, $jabPort) = 0; |
| our ($LOGFILE, $PIDFILE, $PROCESSNAME); |
| our ($DATABASE, $SERVER, $WRTUSER, $WRTPASS, $LockerRdUser, $rdPass) = 0; |
| our ($DEFAULTHELPEMAIL, $RETURNPATH) = 0; |
| our ($XCATROOT) = 0; |
| our ($FQDN) = 0; |
| our ($MYSQL_SSL, $MYSQL_SSL_CERT); |
| our ($WINDOWS_ROOT_PASSWORD); |
| our ($XMLRPC_USER, $XMLRPC_PASS, $XMLRPC_URL); |
| |
| # 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 SETUP_MODE flag to 0 by default |
| our $SETUP_MODE = 0; |
| |
| # Set the SETUP_MODE flag to 1 by default |
| our $DAEMON_MODE = 1; |
| |
| # Use the default configuration file path if -conf isn't specified on the command line |
| our $BIN_PATH = $FindBin::Bin; |
| |
| # Set a default config file path |
| 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 hash |
| our %OPTIONS; |
| GetOptions(\%OPTIONS, |
| 'config=s' => \$CONF_FILE_PATH, |
| 'daemon!' => \$DAEMON_MODE, |
| 'logfile=s' => \$LOGFILE, |
| 'help' => \&help, |
| 'setup!' => \$SETUP_MODE, |
| 'verbose!' => \$VERBOSE, |
| ); |
| |
| # Make sure the config file exists |
| if (!-f $CONF_FILE_PATH) { |
| print STDOUT "ERROR: config file being does not exist: $CONF_FILE_PATH\n"; |
| help(); |
| } |
| |
| 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))) { |
| chomp($l); |
| $LOGFILE = $1; |
| } |
| #pidfile |
| if ($l =~ /^pidfile=(.*)/) { |
| chomp($l); |
| $PIDFILE = $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=(.*)/) { |
| $DATABASE = $1; |
| } |
| #name of database server |
| if ($l =~ /^server=([-.a-zA-Z0-9]*)/) { |
| $SERVER = $1; |
| } |
| #write user name |
| if ($l =~ /^LockerWrtUser=(.*)/) { |
| $WRTUSER = $1; |
| } |
| |
| #write user password |
| if ($l =~ /^wrtPass=(.*)/) { |
| $WRTPASS = $1; |
| } |
| |
| #read user name |
| if ($l =~ /^LockerRdUser=(.*)/) { |
| $LockerRdUser = $1; |
| } |
| |
| #read user password |
| if ($l =~ /^rdPass=(.*)/) { |
| $rdPass = $1; |
| } |
| |
| #xmlrpc_username |
| if ($l =~ /^xmlrpc_username=(.*)/) { |
| $XMLRPC_USER = $1; |
| } |
| |
| #xmlrpc_username password |
| if ($l =~ /^xmlrpc_pass=(.*)/) { |
| $XMLRPC_PASS = $1; |
| } |
| |
| #xmlrpc_url |
| if ($l =~ /^xmlrpc_url=(.*)/) { |
| $XMLRPC_URL = $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; |
| } |
| |
| #Sendmail Envelope Sender |
| if ($l =~ /^RETURNPATH=([,-.\@a-zA-Z0-9_]*)/) { |
| $RETURNPATH = $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=(.*)/) { |
| $jabUser = $1; |
| } |
| if ($l =~ /^jabPass=(.*)/) { |
| $jabPass = $1; |
| } |
| if ($l =~ /^jabResource=(.*)/) { |
| $jabResource = $1; |
| } |
| |
| #process name |
| if ($l =~ /^processname=([-_a-zA-Z0-9]*)/) { |
| $PROCESSNAME = $1; |
| } |
| |
| |
| if ($l =~ /^windows_root_password=(.*)/i) { |
| $WINDOWS_ROOT_PASSWORD = $1; |
| } |
| |
| if ($l =~ /^verbose=(.*)/i && !$VERBOSE) { |
| $VERBOSE = $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 (!$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 (!($RETURNPATH)){ |
| $RETURNPATH=""; |
| } |
| |
| 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); |
| } |
| |
| # Can't be both daemon mode and setup mode, use setup if both are set |
| $DAEMON_MODE = 0 if ($DAEMON_MODE && $SETUP_MODE); |
| |
| } ## end INIT |
| |
| |
| 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, $RETURNPATH); |
| our ($LOGFILE, $PIDFILE, $VCLDRPCQUERYKEY); |
| our ($SERVER, $DATABASE, $WRTUSER, $WRTPASS); |
| our ($MYSQL_SSL, $MYSQL_SSL_CERT); |
| our ($FQDN); |
| our $XCATROOT = "/opt/xcat"; |
| our $TOOLS = "$FindBin::Bin/../tools"; |
| our $VMWARE_MAC_GENERATED; |
| our $VERBOSE; |
| our $CONF_FILE_PATH; |
| our $WINDOWS_ROOT_PASSWORD; |
| our ($XMLRPC_USER, $XMLRPC_PASS, $XMLRPC_URL); |
| our $DAEMON_MODE; |
| our $SETUP_MODE; |
| our $BIN_PATH; |
| |
| our $DEFAULTHELPEMAIL = "vcl_help\@example.org"; # default value if affiliation helpaddress is not set |
| |
| sub makedatestring; |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 help |
| |
| Parameters : None |
| Returns : Nothing, terminates program |
| Description : Displays a help message and exits. |
| |
| =cut |
| |
| sub help { |
| my $message = <<"END"; |
| ============================================================================ |
| Please read the README and INSTALLATION files in the source directory. |
| Documentation is available at http://cwiki.apache.org/VCL. |
| |
| Command line options: |
| -setup | Run management node setup |
| -conf=<path> | Specify vcld configuration file |
| -verbose | Run vcld in verbose mode |
| -debug | Run vcld in non-daemon mode |
| -help | Display this help information |
| ============================================================================ |
| END |
| |
| print $message; |
| exit; |
| } ## end sub help |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 preplogfile |
| |
| Parameters : nothing |
| Returns : nothing |
| Description : writes header to global log file |
| |
| =cut |
| |
| sub preplogfile { |
| my $currenttime = makedatestring(); |
| |
| #Print the vcld process info |
| my $process_info = <<EOF; |
| ============================================================================ |
| VCL Management Node Daemon (vcld) | $currenttime |
| ============================================================================ |
| bin path: $BIN_PATH |
| config file: $CONF_FILE_PATH |
| log file: $LOGFILE |
| pid file: $PIDFILE |
| daemon mode: $DAEMON_MODE |
| setup mode: $SETUP_MODE |
| verbose mode: $VERBOSE |
| ============================================================================ |
| EOF |
| |
| if ($LOGFILE) { |
| if (!open(LOGFILE, ">>$LOGFILE")) { |
| die "Failed to open log file: $LOGFILE"; |
| } |
| print LOGFILE $process_info; |
| close(LOGFILE); |
| } |
| |
| print STDOUT $process_info; |
| } |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =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); |
| |
| # Confirm sysadmin address exists |
| my $sysadmin = 0; |
| if(defined($ENV{management_node_info}{SYSADMIN_EMAIL}) && $ENV{management_node_info}{SYSADMIN_EMAIL}){ |
| $sysadmin = $ENV{management_node_info}{SYSADMIN_EMAIL}; |
| } |
| |
| # Confirm shared mail box exists |
| my $shared_mail_box = 0; |
| if(defined($ENV{management_node_info}{SHARED_EMAIL_BOX}) && $ENV{management_node_info}{SHARED_EMAIL_BOX}){ |
| my $shared_mail_box = $ENV{management_node_info}{SHARED_EMAIL_BOX}; |
| } |
| |
| # Get the current time |
| my $currenttime = makedatestring(); |
| |
| # Open the log file for writing if passed as an argument or set globally |
| # If not, print to STDOUT |
| $log = $LOGFILE 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//gs; |
| |
| ## 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+)|(\s+$)//gs; |
| |
| # Remove any spaces from the beginning or end of the each line |
| $string =~ s/\s*\n\s*/\n/gs; |
| |
| # 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 |
| my $body; |
| if ($error == 2) { |
| # 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` if $log; |
| 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) |
| |
| |
| # 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_mail_box) { |
| my $to = $shared_mail_box; |
| my $from = "root\@$FQDN"; |
| my $subject = "Informational -- $filename"; |
| |
| # Assemble the e-mail message body |
| $body = <<"END"; |
| $string |
| |
| Time: $currenttime |
| PID: $PID |
| Caller: $caller_info |
| |
| END |
| |
| 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; |
| |
| # Check if the logfile path has been set and not running in daemon mode and redirect output to log file |
| # No need to redirect in daemon mode because STDOUT is redirected by vcld |
| if (!$DAEMON_MODE && $log) { |
| open(OUTPUT, ">>$log"); |
| print OUTPUT "$log_message\n"; |
| close OUTPUT; |
| } |
| else { |
| open(STDOUT, ">>$log"); |
| 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"); |
| |
| # if 30min to 6 hrs in advance: start assigning resources |
| if ($start_delta_minutes >= (30) && $start_delta_minutes <= (6 * 60)) { |
| # 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 |
| |
| #Start time is fairly old - something is off |
| #send warning to log for tracking purposes |
| if ($start_diff_minutes < -17) { |
| notify($ERRORS{'WARNING'}, 0, "reservation start time was in the past 17 minutes ($start_diff_minutes)"); |
| } |
| |
| return "start"; |
| |
| } ## 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 = $DEFAULTHELPEMAIL; |
| } |
| my $localreturnpath = "-f $RETURNPATH"; |
| my $mailer = Mail::Mailer->new("sendmail", $localreturnpath); |
| |
| my $shared_mail_box = 0; |
| if(defined($ENV{management_node_info}{SHARED_EMAIL_BOX}) && $ENV{management_node_info}{SHARED_EMAIL_BOX}){ |
| $shared_mail_box = $ENV{management_node_info}{SHARED_EMAIL_BOX}; |
| } |
| |
| if ($shared_mail_box) { |
| my $bcc = $shared_mail_box; |
| 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_mail_box) |
| 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_mail_box) |
| } ## 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, $image_os_type) = @_; |
| 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)); |
| |
| my $subnetmask = $ENV{management_node_info}{PUBLIC_SUBNET_MASK}; |
| my $default_gateway = $ENV{management_node_info}{PUBLIC_DEFAULT_GATEWAY}; |
| my $dns_server = $ENV{management_node_info}{PUBLIC_DNS_SERVER}; |
| |
| #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 = $ENV{management_node_info}{keys}; |
| my @sshcmd; |
| if ($image_os_type =~ /linux/i) { |
| #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=$subnetmask\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 eth1", "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-eth1", $identity)) { |
| |
| #confirm it got there |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($node, $identity, "cat /etc/sysconfig/network-scripts/ifcfg-eth1", "root"); |
| my $success = 0; |
| foreach my $i (@{$sshcmd[1]}) { |
| if ($i =~ /$IPaddress/) { |
| notify($ERRORS{'OK'}, 0, "SUCCESS - copied ifcfg_eth1\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-eth1 did get updated with $IPaddress "); |
| return 0; |
| } |
| } ## end if (run_scp_command($tmpfile, "$node:/etc/sysconfig/network-scripts/ifcfg-eth1"... |
| |
| #bring device up |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($node, $identity, "/etc/sysconfig/network-scripts/ifup eth1", "root"); |
| #should be empty |
| foreach my $l (@{$sshcmd[1]}) { |
| if ($l) { |
| #potential problem |
| notify($ERRORS{'OK'}, 0, "possible problem with ifup eth1 $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 $default_gateway metric 0 eth1", "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 $default_gateway metric 0 eth1"); |
| } |
| if ($l =~ /No such process/) { |
| notify($ERRORS{'CRITICAL'}, 0, "problem with $node $l add default gw $default_gateway metric 0 eth1 "); |
| 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 ( $dns_server =~ /,/) { |
| ($s1, $s2, $s3) = split(/,/, $dns_server); |
| } |
| else { |
| $s1 = $dns_server; |
| } |
| 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 |
| |
| } ## end sub setstaticaddress |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 getdynamicaddress |
| |
| Parameters : $node, $osname |
| Returns : assigned ipaddress |
| Description : collects the dynamically assigned ipaddress |
| =cut |
| |
| sub getdynamicaddress { |
| my ($node, $osname, $image_os_type) = @_; |
| 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{'OK'}, 0, "image_os_type not set") if (!defined($image_os_type)); |
| |
| #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 =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\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_keys = $ENV{management_node_info}{keys}; |
| my $dynaIPaddress = 0; |
| my $ip_address; |
| if ($image_os_type =~ /windows/i) { |
| |
| @sshcmd = run_ssh_command($node, $identity_keys, "ipconfig", "root"); |
| for my $l (@{$sshcmd[1]}) { |
| # skip class a,b,c private addresses |
| next if ($l !~ /IP(.*)?Address[\s\.:]*([\d\.]*)/); |
| my $ip_address_found = $2; |
| next if ($ip_address_found =~ /^(10|127|192\.168|172\.(1[6-9]|2[0-9]|3[0-1]))\./); |
| next if ($ip_address_found =~ /$privateIP/); |
| $ip_address = $ip_address_found; |
| } |
| $dynaIPaddress = $ip_address; |
| |
| } ## end if ($osname =~ /windows/) |
| elsif ($image_os_type =~ /linux/) { |
| #$identity = $ENV{management_node_info}{keys}; |
| undef @sshcmd; |
| @sshcmd = run_ssh_command($node, $identity_keys, "/sbin/ifconfig \|grep inet", "root"); |
| for my $l (@{$sshcmd[1]}) { |
| # skip class a,b,c private addresses |
| next if ($l !~ /inet addr:([\d\.]*)/); |
| my $ip_address_found = $1; |
| next if ($ip_address_found =~ /^(10|127|192\.168|172\.(1[6-9]|2[0-9]|3[0-1]))\./); |
| next if ($ip_address_found =~ /$privateIP/); |
| $ip_address = $ip_address_found; |
| } |
| $dynaIPaddress = $ip_address; |
| |
| } ## end elsif ($image_os_type =~ /linux/) [ if ($image_os_type =~ /windows/) |
| else { |
| notify($ERRORS{'WARNING'}, 0, "OStype $image_os_type not supported "); |
| return 0; |
| } |
| |
| notify($ERRORS{'OK'}, 0, "dynamic IP address for $node collected: $dynaIPaddress"); |
| return $dynaIPaddress; |
| |
| } ## end sub getdynamicaddress |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =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,$image_os_type) = @_; |
| 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)); |
| notify($ERRORS{'OK'}, 0, "image_os_type not set") if (!defined($image_os_type)); |
| |
| my $start_time = time(); |
| my $time_exceeded = 0; |
| my $break = 0; |
| my $ret_val = "no"; |
| |
| $dbh = getnewdbh() if !$dbh; |
| my $identity_keys = $ENV{management_node_info}{keys}; |
| |
| # 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 ($image_os_type =~ /windows/i) { |
| undef @SSHCMD; |
| @SSHCMD = run_ssh_command($shortnodename, $identity_keys, "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 ($image_os_type =~ /linux/i) { |
| #run two checks |
| # 1:check connected IP address |
| # 2:simply check who ouput |
| my @lines; |
| undef @SSHCMD; |
| @SSHCMD = run_ssh_command($shortnodename, $identity_keys, "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_keys, "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 ($image_os_type =~ /linux/) [ if ($osname =~ /windows/) |
| } ## end if ($type =~ /blade|virtualmachine/) |
| elsif ($type eq "lab") { |
| undef @SSHCMD; |
| @SSHCMD = run_ssh_command($nodename, $identity_keys, "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, $image_os_type) = @_; |
| 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, "image_os_type not set") if (!defined($image_os_type)); |
| notify($ERRORS{'OK'}, 0, "ipaddress not set") if (!defined($ipaddress)); |
| |
| my $identity= $ENV{management_node_info}{keys}; |
| |
| 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 ($image_os_type =~ /windows/i) { |
| #notify($ERRORS{'OK'},0,"checking $nodename $ipaddress"); |
| undef @SSHCMD; |
| @SSHCMD = run_ssh_command($shortname, $identity, "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 ($image_os_type =~ /linux/i) { |
| undef @SSHCMD; |
| @SSHCMD = run_ssh_command($nodename, $identity, "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]}) |
| } |
| return 0; |
| } ## end if ($type =~ /blade|virtualmachine/) |
| elsif ($type eq "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_computer_lastcheck |
| |
| Parameters : $computer_id, $datestring, $log |
| Returns : 1 success 0 failure |
| Description : update computer state |
| |
| =cut |
| |
| sub update_computer_lastcheck { |
| my ($computer_id, $datestring, $log) = @_; |
| |
| my ($package, $filename, $line, $sub) = caller(0); |
| $log = 0 unless (defined $log); |
| |
| notify($ERRORS{'WARNING'}, $log, "computer id is not defined") unless (defined($computer_id)); |
| notify($ERRORS{'WARNING'}, $log, "$datestring is not defined") unless (defined($datestring)); |
| return 0 unless (defined $computer_id); |
| |
| unless (defined($datestring) ) { |
| $datestring = makedatestring; |
| } |
| |
| my $update_statement = " |
| UPDATE |
| computer |
| SET |
| computer.lastcheck = '$datestring' |
| WHERE |
| computer.id = $computer_id |
| "; |
| |
| # Call the database execute subroutine |
| if (database_execute($update_statement)) { |
| # Update successful |
| notify($ERRORS{'DEBUG'}, $log, "computer $computer_id lastcheck updated to: $datestring"); |
| return 1; |
| } |
| else { |
| notify($ERRORS{'CRITICAL'}, $log, "unable to update datestring for computer $computer_id"); |
| return 0; |
| } |
| } ## end |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =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 'image' if request state or laststate is set to image |
| return 'forimaging' if forimaging is set to 1, and neither request state nor laststate is set to image |
| return 0 if forimaging is set to 0, and neither request state nor laststate is set to image |
| return undefined if an error occurred |
| Description : checks if request is in imaging mode and if forimaging has been set |
| |
| =cut |
| |
| sub is_request_imaging { |
| |
| my ($request_id) = @_; |
| |
| # 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.forimaging AS forimaging, |
| 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 != 1) { |
| notify($ERRORS{'WARNING'}, 0, scalar @selected_rows . " rows were returned from database select"); |
| return; |
| } |
| |
| my $forimaging = $selected_rows[0]{forimaging}; |
| my $state_name = $selected_rows[0]{currentstate_name}; |
| my $laststate_name = $selected_rows[0]{laststate_name}; |
| |
| notify($ERRORS{'DEBUG'}, 0, "forimaging=$forimaging, currentstate=$state_name, laststate=$laststate_name"); |
| |
| # If request state or laststate has been changed to image, return 1 |
| # If forimaging is set, return 0 |
| # If neither state is image and forimaging is not set, return undefined |
| if ($state_name eq 'image' || $laststate_name eq 'image') { |
| return 'image'; |
| } |
| elsif ($forimaging) { |
| return 'forimaging'; |
| } |
| else { |
| 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 next 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 next image information |
| my $select_nextimage = " |
| SELECT DISTINCT |
| imagerevision.imagename AS imagename, |
| imagerevision.id AS imagerevisionid, |
| image.id AS imageid |
| FROM |
| image, |
| computer, |
| imagerevision |
| WHERE |
| imagerevision.imageid = computer.nextimageid |
| AND imagerevision.production = 1 |
| AND computer.nextimageid = 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 @next_selected_rows = database_select($select_nextimage); |
| |
| # Check to make sure at least 1 row were returned |
| if (scalar @next_selected_rows == 0) { |
| notify($ERRORS{'WARNING'}, 0, "get_next_image_default failed to fetch next image for computerid $computerid"); |
| return 0; |
| } |
| elsif (scalar @next_selected_rows > 1) { |
| notify($ERRORS{'WARNING'}, 0, "" . scalar @next_selected_rows . " rows were returned from database select"); |
| return 0; |
| } |
| notify($ERRORS{'OK'}, 0, "get_next_image_default : returning next image=$next_selected_rows[0]{imagename} imageid=$next_selected_rows[0]{imageid}"); |
| push(@ret_array, $next_selected_rows[0]{imagename}, $next_selected_rows[0]{imageid}, $next_selected_rows[0]{imagerevisionid}); |
| return @ret_array; |
| |
| } ## end sub get_next_image |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =head2 setnextimage |
| |
| Parameters : $computerid, $image |
| Returns : 1 success, 0 failed |
| Description : updates nextimageid on provided computerid |
| =cut |
| |
| sub setnextimage { |
| 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 nextimageid = $imageid WHERE id = $computerid "; |
| |
| # Call the database execute subroutine |
| if (database_execute($update_statement)) { |
| return 1; |
| } |
| else { |
| notify($ERRORS{'WARNING'}, 0, "unable to update nextimageid"); |
| return 0; |
| } |
| } ## end sub setnextimage |
| |
| #///////////////////////////////////////////////////////////////////////////// |
| |
| =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 = $ENV{management_node_info}{keys}; |
| 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|cent)/) { |
| 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,$image_os_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))); |
| |
| if (!nmap_port($node, 22)) { |
| return "off"; |
| } |
| |
| my $identity = $ENV{management_node_info}{keys}; |
| |
| my @sshcmd = run_ssh_command($node, $identity, "uname -s", "root"); |
| |
| return "off" if (!defined($sshcmd[0]) || !defined($sshcmd[1]) || $sshcmd[0] == 1); |
| 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 = $ENV{management_node_info}{keys}; |
| 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 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) = @_; |
| |
| if (!$hostname) { |
| notify($ERRORS{'WARNING'}, 0, "hostname argument was not specified"); |
| return; |
| } |
| if (!defined($port)) { |
| notify($ERRORS{'WARNING'}, 0, "port argument was not specified"); |
| return; |
| } |
| |
| my $command = "/usr/bin/nmap $hostname -P0 -p $port -T Aggressive"; |
| my ($exit_status, $output) = run_command($command, 1); |
| |
| if (!defined($output)) { |
| notify($ERRORS{'WARNING'}, 0, "failed to run nmap command on management node: '$command'"); |
| return; |
| } |
| |
| if (grep(/open/i, @$output)) { |
| notify($ERRORS{'DEBUG'}, 0, "port $port is open on $hostname"); |
| return 1; |
| } |
| elsif (grep(/(nmap:|warning)/i, @$output)) { |
| notify($ERRORS{'WARNING'}, 0, "error occurred running nmap command: '$command', output:\n" . join("\n", @$output)); |
| return; |
| } |
| else { |
| notify($ERRORS{'DEBUG'}, 0, "port $port is closed on $hostname"); |
| 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]; |
| if (!$hostname) { |
| notify($ERRORS{'WARNING'}, 0, "hostname argument was not supplied"); |
| return; |
| } |
| |
| 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 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 ($ENV{dbh} && $ENV{dbh}->ping && $ENV{dbh}->{Name} =~ /^$database:/) { |
| #notify($ERRORS{'DEBUG'}, 0, "using database handle stored in \$ENV{dbh}"); |
| return $ENV{dbh}; |
| } |
| elsif ($ENV{dbh} && $ENV{dbh}->ping) { |
| my ($stored_database_name) = $ENV{dbh}->{Name} =~ /^([^:]*)/; |
| notify($ERRORS{'DEBUG'}, 0, "database requested ($database) does not match handle stored in \$ENV{dbh} (" . $ENV{dbh}->{Name} . ")"); |
| } |
| 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}"); |
| } |
| |
| 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 $!"); |
| } |
| my $identity_keys = $ENV{management_node_info}{keys}; |
| if ($type eq "blade") { |
| #this is only going to be rhel |
| if (run_scp_command("/tmp/wall.$hostname", "$hostname:/root/wall.txt", $identity_keys)) { |
| unlink "/tmp/wall.$hostname"; |
| if (run_ssh_command($hostname, $identity_keys, " 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 (run_scp_command("/tmp/wall.$hostname", "vclstaff\@$hostname:/home/vclstaff/wall.txt", $identity_keys, 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_keys, "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_keys, "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, $ENV{management_node_info}{keys}, $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 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); |
| |
| @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 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 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 = $ENV{management_node_info}{keys}; |
| |
| #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 = $ENV{management_node_info}{keys}; |
| |
| 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 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] =~ /nodeready/) { |
| notify($ERRORS{'OK'}, 0, "detected $row[0] for $nodename, 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) = @_; |
| |
| # Sanity check, make sure reservation id is valid |
| if (!$reservation_id) { |
| notify($ERRORS{'WARNING'}, 0, "reservation id is not defined"); |
| return; |
| } |
| if ($reservation_id !~ /^\d+$/) { |
| notify($ERRORS{'WARNING'}, 0, "reservation id is not valid: $reservation_id"); |
| return; |
| } |
| |
| notify($ERRORS{'OK'}, 0, "attempting to kill process for reservation $reservation_id"); |
| |
| # Use the pkill utility to find processes matching the reservation ID |
| # Do not use -9 or else DESTROY won't run |
| 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 = $? >> 8; |
| |
| # Check the pgrep exit status |
| if ($pkill_exit_status == 0) { |
| notify($ERRORS{'OK'}, 0, "reservation $reservation_id process was killed, returning 1"); |
| return 1; |
| } |
| elsif ($? == -1) { |
| notify($ERRORS{'OK'}, 0, "\$? is set to -1, Perl bug likely encountered, assuming reservation $reservation_id process was killed, returning 1"); |
| return 1; |
| } |
| elsif ($pkill_exit_status == 1) { |
| notify($ERRORS{'OK'}, 0, "process was not found for reservation $reservation_id, returning 1"); |
| return 1; |
| } |
| 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, |
| request.checkuser AS request_checkuser, |
| |
| 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.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, |
| |
| 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, |
| OS.moduleid AS OS_moduleid, |
| |
| 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.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.platformid AS computer_platformid, |
| computer.scheduleid AS computer_scheduleid, |
| computer.currentimageid AS computer_currentimageid, |
| computer.nextimageid AS computer_nextimageid, |
| 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, |
| |
| 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, |
| platform imageplatform, |
| imagerevision, |
| OS, |
| module imageOSmodule, |
| computer, |
| provisioning computerprovisioning, |
| module computerprovisioningmodule, |
| platform computerplatform, |
| schedule computerschedule, |
| state requeststate, |
| state requestlaststate, |
| state computerstate |
| |
| |