#!/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)); use lib "$::XCATROOT/lib/perl"; require xCAT::Client; require xCAT::Utils; use strict; use Expect; require File::Basename; import File::Basename; my $scriptname = $0; ############################################## # Globals ############################################## my $verbose = 0; my $node; my $ips; my $id; my $hwtype; ########################################################################## # 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"; } #use xcatd to get the attribute $fsp_name and $id of the node. my $fsp_api = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api"; my $action = "console"; my $type = "0"; my $Rc = 0; 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 $ipl_num = 0; 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."; sleep 5; } else { print "."; sleep 30; } } 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; $index++; print "\nDestination $machine is POWERING ON, please wait."; sleep 5; } else { print "."; sleep 30; } } elsif ($res =~ /(power-off-transition)$/) { if (!$pre_state or ($pre_state ne $1)) { $pre_state = $1; print "\nDestination $machine is POWERING OFF."; sleep 20; } else { print "."; sleep 5; next; } } elsif ($res =~ /(IPL-in-process)$/) { if (!$pre_state) { $pre_state = $1; sleep 10; next; } elsif ($pre_state and ($pre_state eq $1) and !$index) { print "\nDestination $machine is POWERING ON, please wait."; $index++; } else { #print "\r\n====>pre_state=$pre_state\n"; $ipl_num++; $pre_state = $1; if ($ipl_num == 4) { print "."; $ipl_num = 0; } } sleep 5; } else { $pre_state = $res; sleep 20; } } my $cmd = "$fsp_api -a $action -t $type:$fsp_ip:$id:$node:\r"; 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); print "The connection is resetting, please wait."; my $link_state = ""; my $rs_num = 0; while (!$link_state or $link_state !~ /state=LINE UP/i) { sleep 2; $rs_num++; $link_cmd = "$fsp_api -a query_connection -t $type:$fsp_ip:$id:$node: 2>&1"; $link_state = xCAT::Utils->runcmd($link_cmd, -1); if ($rs_num == 5) { print "."; $rs_num = 0; } } print "\n"; $exp->hard_close(); return (0); } my $escape = "\030"; $exp->send("\r"); $exp->interact(\*STDIN, $escape); $exp->hard_close(); return (0); } ############################################## # Start main body of code ############################################## 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);