#!/usr/local/bin/perl -w #=============================================================================# # Program: ddn_cmd # # Author: Chad Kerner # #-----------------------------------------------------------------------------# # Contact Information: # # Chad Kerner, ckerner@ncsa.uiuc.edu # # Systems Engineer, Storage Enabling Technologies # # National Center for Supercomputing Applications # # 605 East Springfield # # Champaign, IL 61820 # # # # Web Site: http://www.ncsa.uiuc.edu/~ckerner # #-----------------------------------------------------------------------------# # Purpose: This script is for running commands against a set of DDN disk # # controllers. It is based on the sw_cmd script that I wrote in # # order to execute commands against Brocade switches. # #-----------------------------------------------------------------------------# # History: # # 20050306 - Chad Kerner - Initial Coding # # 20050308 - Chad Kerner - Added the logic for the debug option. # # - Added the logic to allow the output file to be # # appended instead of overwritten each time. # #=============================================================================# #-----------------------------------------------------------------------------# # Package Declarations # #-----------------------------------------------------------------------------# use strict; use Net::Telnet; use Getopt::Long; use Term::ReadKey; #-----------------------------------------------------------------------------# # Function Prototypes # #-----------------------------------------------------------------------------# sub check_options(); sub print_help_screen(); sub get_password($); sub handle_error($); sub print_version(); #-----------------------------------------------------------------------------# # Variable Declarations # #-----------------------------------------------------------------------------# $main::version = "0.02"; $main::password = ""; $main::logfile = ""; $main::cmdfile = ""; $main::userid = ""; $main::command = ""; $main::debug_file = 'ddn_cmd.debug'; #-----------------------------------------------------------------------------# # Main Code Block # #-----------------------------------------------------------------------------# { my $controller; my $ctrl; my $command; my $ok; my $error; check_options(); if( $main::logfile ne "" ) { if( $main::append_log) { open(LOGFILE,">>$main::logfile") || die("Unable To Open File: $main::logfile\n"); } else { open(LOGFILE,">$main::logfile") || die("Unable To Open File: $main::logfile\n"); } $main::print_log = 1; } else { $main::print_log = 0; } foreach $controller (@main::controllers) { my $ctrl_prompt = '/.*' . $controller . ':/i'; if ( $main::checkpass && ! $main::interactive ) { $main::password = get_password($controller); $main::checkpass = 0; } elsif( $main::interactive ) { $main::password = get_password($controller); } if( $main::debug ) { $ctrl = new Net::Telnet (Timeout => 10, Errmode => 'return', Dump_Log => $main::debug_file, Prompt => '/.*login: /' ); } else { $ctrl = new Net::Telnet (Timeout => 10, Errmode => 'return', Prompt => '/.*login: /' ); } # Establish a connection with the controller. $ok = $ctrl->open("$controller"); if( ! $ok ) { handle_error($ctrl->errmsg); } # Wait for the login prompt. $ok = $ctrl->waitfor(Match => '/.*login: /', Timeout => 10); if( ! $ok ) { handle_error($ctrl->errmsg); } # Send the user id. $ok = $ctrl->print("$main::userid"); if( ! $ok ) { handle_error($ctrl->errmsg); } # Waid for the password prompt. $ok = $ctrl->waitfor(Match => '/.*assword: /', Timeout => 10); if( ! $ok ) { handle_error($ctrl->errmsg); } # Send the password. $ok = $ctrl->print("$main::password"); if( ! $ok ) { handle_error($ctrl->errmsg); } # Wait for the command prompt. $ok = $ctrl->waitfor(Match => $ctrl_prompt, Timeout => 20); if( ! $ok ) { handle_error($ctrl->errmsg); } foreach $command (@main::cmds) { if( ! $main::print_log ) { print "### Controller: $controller\tCommand: $command\n"; } else { print LOGFILE "### Controller: $controller\tCommand: $command\n"; } # Send the command. $ok = $ctrl->print("$command"); if( ! $ok ) { handle_error($ctrl->errmsg); } my $text; my $match; LINE: while( ($text,$match) = $ctrl->waitfor(Match => $ctrl_prompt, Timeout => 120) ) { $text =~ s/^\s+//; # Strip Leading Spaces $text =~ s/\s+$//; # Strip Trailing Spaces $text =~ s/\cM//g; # Strip Control-M if( $match ne "" && $text ne "" ) { $text = " " . $text; } last LINE if $text =~ m/^$/; chomp $text; if( ! $main::print_log ) { print "$text\n"; } else { print LOGFILE "$text\n"; } $ctrl->print(""); } if( ! $main::print_log ) { print "\n\n"; } else { print LOGFILE "\n\n"; } } # Close the connection. $ok = $ctrl->close(); if( ! $ok ) { handle_error($ctrl->errmsg); } } exit; } # End of the main code block. #-----------------------------------------------------------------------------# # check_options() - This routine will check the command line options that # # were specified by the user. # #-----------------------------------------------------------------------------# sub check_options() { # If no command arguments are specified, print the help screen. if( scalar @ARGV == 0 ) { print_help_screen(); } my $result = GetOptions ( 'c=s' => \$main::controller, 'u=s' => \$main::userid, 'p=s' => \$main::password, 'a' => \$main::append_log, 'd' => \$main::debug, 'i' => \$main::interactive, 'v' => sub { print_version(); }, 'o=s' => \$main::logfile, 'f=s' => \$main::cmdfile, 'h' => sub { print_help_screen(); }, ); # Combine the rest of the command line into the command. foreach(@ARGV) { $main::command = $main::command . " " . $_; } @main::controllers = split(/,/,$main::controller); if( scalar @main::controllers == 0 ) { print "\n\tYou must specify at least 1 controller.\n\n"; exit; } # If no user is specified, default to admin if( $main::userid eq "" ) { $main::userid = "admin"; } # If no password is specified, be sure to prompt for one. if( $main::password eq "" ) { $main::checkpass = 1; } else { $main::checkpass = 0; } if( $main::cmdfile eq "" ) { if( $main::command ne "" ) { push @main::cmds, $main::command; } } else { open(CMDFILE,"$main::cmdfile") || die("Unable To Open File: $main::cmdfile\n"); foreach () { chomp; s/^\s+//; # Remove leading whitespace s/\s+$//; # Remove trailing whitespace next if /^$/; # Skip blank lines next if /^#/; # Skip comment lines s/\s*#.*//; # Skip partial comment lines push @main::cmds, $_; } close(CMDFILE); } # If no commands are specified, print the help screen. if( scalar @main::cmds == 0 ) { print_help_screen(); } return; } # End of the check_options() routine. #-----------------------------------------------------------------------------# # print_help_screen() - This routine will print the generic help screen. # #-----------------------------------------------------------------------------# sub print_help_screen() { print STDERR "\n\n"; print STDERR "\tUsage: ddn_cmd -c \n"; print STDERR "\t -u -p -a -d -h -v\n"; print STDERR "\t -i -o -f \n\n"; print STDERR "\tOptions:\n\n"; print STDERR "\t-c\tComma seperated list of controllers\n"; print STDERR "\t-u\tUserid to connect with(admin by default)\n"; print STDERR "\t-p\tPassword of the account being used\n"; print STDERR "\t-i\tPrompt for the password for each controller\n"; print STDERR "\t-o\tFile to hold the command output\n"; print STDERR "\t-a\tAppend the logfile instead of replacing it.\n"; print STDERR "\t-h\tDisplay the help screen you are currently looking at.\n"; print STDERR "\t-v\tDisplay the utility version information.\n"; print STDERR "\t-d\tExecute in debug mode, producing ddn_cmd.debug log file.\n"; print STDERR "\t-f\tFile containing a list of commands to run on the controllers\n"; print STDERR "\n\t \tCommand to execute\n\n"; exit; } # End of the print_help_screen() routine. #-----------------------------------------------------------------------------# # This routine gets the password from the prompt. #-----------------------------------------------------------------------------# sub get_password($) { my $controller = $_[0]; my $passwd; print STDERR "Enter $main::userid password for $controller: "; ReadMode 'noecho'; $passwd = ReadLine 0; chomp $passwd; ReadMode 'normal'; print STDERR "\n"; return $passwd; } # End of the get_password() routine. #-----------------------------------------------------------------------------# # This routine will handle the telnet object errors. #-----------------------------------------------------------------------------# sub handle_error($) { my $msg = $_[0]; print "\nError==> $msg\n"; if( $main::debug ) { print "\nDebug Information: \n"; open(INFIL,"$main::debug_file"); foreach() { print; } close(INFIL); print "\nIf you think this is a bug or need help debugging the problem, \n"; print "please email the command being executed as well as the contents \n"; print "of this error message to: ckerner\@ncsa.uiuc.edu \n\n"; } exit; } # End of the handle_error() routine. #-----------------------------------------------------------------------------# # This routine will print the contact and version information. # #-----------------------------------------------------------------------------# sub print_version() { print "\n\n"; print "\tProgram: ddn_cmd\n"; print "\tVersion: $main::version\n\n"; print "\t Author: Chad Kerner, ckerner\@ncsa.uiuc.edu\n"; print "\t Systems Engineer, Storage Enabling Technologies\n"; print "\t National Center for Supercomputing Applications\n"; print "\t 605 East Springfield \n"; print "\t Champaign, IL 61820 \n\n"; print "\t URL: http://www.ncsa.uiuc.edu/~ckerner \n"; print "\n\n"; exit; } # End of the print_version() routine.