#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html use Fcntl qw(:DEFAULT :flock); sub get_lock { unless (flock(LOCKHANDLE,LOCK_EX|LOCK_NB)) { $| = 1; print "Acquiring startup lock..."; flock(LOCKHANDLE,LOCK_EX) or die "Error trying to secure a startup lock"; print "done\n"; } truncate(LOCKHANDLE,0); print LOCKHANDLE $$."\n"; } sub release_lock { truncate(LOCKHANDLE,0); flock(LOCKHANDLE,LOCK_UN); } BEGIN { use Time::HiRes qw(sleep); use File::Path; use Fcntl qw(:DEFAULT :flock); $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; umask 0077; mkpath("/tmp/xcat/"); unless (sysopen(LOCKHANDLE,"/tmp/xcat/consolelock",O_WRONLY | O_CREAT)) { sleep 15; print "Unable to open lock file"; exit 0; } get_lock(); #my $sleepint=int(rand(10)); #Stagger start to avoid overwhelming conserver/xCATd #print "Opening console in ".(2+(0.5*$sleepint))." seconds...\n"; #sleep $sleepint; } my $sleepint=int(rand(10)); use lib "$::XCATROOT/lib/perl"; require xCAT::Client; require xCAT::Utils; use strict; #use Getopt::Long; #use xCAT::Table; #use xCAT::PPCdb; use Expect; #use xCAT::DBobjUtils; #use Data::Dumper; require File::Basename; import File::Basename; my $scriptname = $0; ############################################## # Globals ############################################## my $verbose = 0; my $node; my $ips; my $id; my $hwtype; ########################################## # Database errors ########################################## #my %errmsg = ( # NODE_UNDEF =>"Node not defined in '%s' database", # NO_ATTR =>"'%s' not defined in '%s' database", # DB_UNDEF =>"'%s' database not defined" #); ########################################################################## # Parse the command line for options and operands ########################################################################## #sub parse_args { # my %opt = (); # my @VERSION = qw( 2.0 ); # # ############################################# # # Responds with usage statement # ############################################# # local *usage = sub { # # my $cmd = __FILE__; # $cmd =~ s/.*([\w]{3}$)/$1/; # # if ( defined( $_[0] )) { # print STDERR "$_[0]\n"; # } # my @msg = ( # "$cmd -h|--help\n", # "$cmd -v|--version\n", # "$cmd singlenode [-V|-Verbose]\n" ); # print STDERR @msg; # }; # ############################################# # # Process command-line arguments # ############################################# # if ( !defined( @ARGV )) { # usage( "No node specified" ); # return(1); # } # ############################################# # # Checks case in GetOptions, allows opts # # to be grouped (e.g. -vx), and terminates # # at the first unrecognized option. # ############################################# # $Getopt::Long::ignorecase = 0; # Getopt::Long::Configure( "bundling" ); # # if ( !GetOptions( \%opt, qw(h|help V|Verbose v|version) )) { # usage(); # return(1); # } # ####################################### # # Option -h for Help # ####################################### # if ( exists( $opt{h} )) { # usage(); # return(1); # } # ####################################### # # Option -v for version # ####################################### # if ( exists( $opt{v} )) { # print STDERR \@VERSION; # return(1); # } # ####################################### # # Option -V for verbose output # ####################################### # if ( exists( $opt{V} )) { # $verbose = 1; # } # ####################################### # # Check for "-" with no option # ####################################### # if ( grep(/^-$/, @ARGV )) { # usage( "Missing option: -" ); # return(1); # } # ####################################### # # Get node # ####################################### # if ( !defined( $ARGV[0] )) { # usage( "No node specified" ); # return(1); # } # ####################################### # # Check for extra argument # ####################################### # $node = shift @ARGV; # if ( defined( $ARGV[0] )) { # usage( "Invalid Argument: $ARGV[0]" ); # return(1); # } # return(0); #} ########################################################################## # Open remote console ########################################################################## sub invoke_cmd { my $node = shift; my $fsp_ip = shift; my $id = shift; my $hwtype = shift; my $machine; if ($hwtype eq 'blade') { $machine = "BLADE"; } else { $machine = "CEC"; } #my @attribs = qw(id parent hcp); #my %tabs = (); ################################## # Open databases needed ################################## #foreach ( qw(ppc vpd nodetype) ) { # $tabs{$_} = xCAT::Table->new($_); # # if ( !exists( $tabs{$_} )) { # return( sprintf( $errmsg{DB_UNDEF}, $_ )); # } #} ################################## # Get node power type ################################## #my $hwtype = __FILE__; #$hwtype =~ s/.*([\w]{3})$/$1/; # ################################# # Get node type ################################# #my ($ent) = $tabs{nodetype}->getNodeAttribs($node, ["nodetype"] ); #if ( !defined( $ent )) { # return( sprintf( $errmsg{NODE_UNDEF}, "nodetype" )); #} ################################# # Check for type ################################# #if ( !exists( $ent->{nodetype} )) { # return( sprintf( $errmsg{NO_ATTR}, $ent->{nodetype},"nodetype" )); #} ################################# # Check for valid "type" ################################# #my @types = split /,/, $ent->{nodetype}; #my ($type) = grep( /^(lpar|osi)$/, @types ); # #if ( !defined( $type )) { # return( "Invalid node type: $ent->{nodetype}" ); #} ################################# # Get attributes ################################# #my ($att) = $tabs{ppc}->getAttribs({'node'=>$node}, @attribs ); # #if ( !defined( $att )) { # return( sprintf( $errmsg{NODE_UNDEF}, "ppc" )); #} ################################# # Verify required attributes ################################# #foreach my $at ( @attribs ) { # if ( !exists( $att->{$at} )) { # return( sprintf( $errmsg{NO_ATTR}, $at, "ppc" )); # } #} # #my $fsp_name = $att->{hcp}; #my $id = $att->{id}; #use xcatd to get the attribute $fsp_name and $id of the node. #my $fsp_api ="/opt/xcat/sbin/fsp-api"; my $fsp_api = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api"; my $action = "console"; my $type = "0"; #my $fsp_ip = (); my $Rc = 0; #$fsp_ip = xCAT::Utils::getNodeIPaddress( $fsp_name ); #if(!defined($fsp_ip)) { # return "Failed to get the $fsp_name\'s ip"; #} my $power_state_cmd = "$fsp_api -a cec_state -t $type:$fsp_ip:$id:$node: 2>&1"; my $res; my $index = 0; my $pre_state = undef; my $wait_interval =20; while (1) { $res = xCAT::Utils->runcmd($power_state_cmd, -1); if ($res =~ /(operating|standby)$/) { print "\n"; last; } elsif ($res =~ /(power off)$/) { if (!$pre_state or ($pre_state ne $1)) { $pre_state = $1; print "\nDestination $machine is in POWER OFF state, Please power it on and wait."; } else { print "."; } } elsif (($res =~ /(power-on-transition)$/) or ($pre_state eq "power off" and $res =~ /$node :\s([.*])/)) { if (!$pre_state or ($pre_state ne $1)) { $pre_state = $1; print "\nDestination $machine is POWERING ON, please wait."; } else { print "."; } } elsif ($res =~ /(power-off-transition)$/) { if (!$pre_state or ($pre_state ne $1)) { $pre_state = $1; print "\nDestination $machine is POWERING OFF."; } else { print "."; sleep 5; next; } } elsif ($res =~ /(IPL-in-process)$/) { if ($pre_state and ($pre_state eq $1) and !$index) { print "\nDestination $machine is POWERING ON, please wait."; $index++; } else { print "."; $pre_state = $1; if ($index == 1) { sleep 5; next; } } } else { $pre_state = $res; print "."; } $wait_interval =20+int(rand(20)); sleep $wait_interval; } my $cmd = "$fsp_api -a $action -t $type:$fsp_ip:$id:$node:\r"; #print "cmd: $cmd\n"; my $running_failed_code = "Reason code: 0x1000000"; my $fsp_standby_msg = "Reason code: 0x1300"; my $fsp_lock_msg = "Reason code: 0x1f00"; my $timeout = 30; my $failed = 0; my $exp = new Expect; $exp->log_stdout( 1 ); $exp->spawn( $cmd ) or die "Can't spawn $cmd\r\n"; my @result = $exp->expect( $timeout, [ "$running_failed_code", sub { $failed = 1; } ], [ "$fsp_standby_msg", sub { $failed = 2; }], ["$fsp_lock_msg", sub { $failed = 3; }] ); if($failed == 1) { $exp->hard_close(); return("Virtual terminal is already connected"); } if($failed == 2) { $exp->hard_close(); return("Failed to open the console. Please check the related FSP's status"); } if ($failed == 3) { my $link_cmd = "$fsp_api -a fsp_reconnect -t $type:$fsp_ip:$id:$node: 2>&1"; xCAT::Utils->runcmd($link_cmd, -1); my $link_state = ""; while (!$link_state or $link_state !~ /state=LINE UP/i) { sleep 10; $link_cmd = "$fsp_api -a query_connection -t $type:$fsp_ip:$id:$node: 2>&1"; $link_state = xCAT::Utils->runcmd($link_cmd, -1); } $exp->hard_close(); return("The connection is reset, please wait..."); } my $escape = "\030"; $exp->send( "\r" ); $exp->interact( \*STDIN, $escape ); $exp->hard_close(); return(0); } ############################################## # Start main body of code ############################################## #if ( parse_args() ) { # exit(1); #} sub getans { my $rsp = shift; if ($rsp->{node}) { $ips = $rsp->{node}->[0]->{fsp_ip}->[0]; $id = $rsp->{node}->[0]->{id}->[0]; $hwtype = $rsp->{node}->[0]->{type}->[0]; } } my $cmdref={ command=>["getfspcon"], arg=>["text"], noderange=>[$ARGV[0]] }; xCAT::Client::submit_request($cmdref,\&getans); until ($ips and $id) { release_lock(); #Let other clients have a go $sleepint=10+int(rand(20)); #Stagger to minimize lock collisions, but no big deal when it does happen print "Console not ready, retrying in $sleepint seconds (Hit Ctrl-E,c,o to skip delay)\n"; sleep $sleepint; get_lock(); xCAT::Client::submit_request($cmdref,\&getans); } release_lock(); #done with xcatd, can run with near impunity $node = $ARGV[0]; my $result = invoke_cmd($node, $ips, $id, $hwtype); if ( $result ne "0" ) { print STDERR "$node: $result\n"; exit(1); } exit(0);