#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html use strict; 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 "Fatal error securing 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; } my $sleepint; use lib "$::XCATROOT/lib/perl"; require xCAT::Client; require xCAT::Utils; require File::Basename; my $scriptname = $0; mkpath("/tmp/xcat/"); unless (sysopen(LOCKHANDLE, "/tmp/xcat/consolelock", O_WRONLY | O_CREAT)) { xCAT::Utils::console_sleep(15, "Unable to open lock file"); exit 0; } get_lock(); my $cmdref = { command => ["getcons"], arg => ["text"], noderange => [ $ARGV[0] ] }; use Data::Dumper; my $dsthost; my $dstty; my $speed; sub getans { my $rsp = shift; if ($rsp->{node}) { $dsthost = $rsp->{node}->[0]->{sshhost}->[0]; $dstty = $rsp->{node}->[0]->{psuedotty}->[0]; $speed = $rsp->{node}->[0]->{baudrate}->[0]; } } xCAT::Client::submit_request($cmdref, \&getans); until ($dsthost and $speed and $dstty) { release_lock(); $sleepint = int(rand(30)) + 60; xCAT::Utils::console_sleep($sleepint, "Console not ready, retrying in $sleepint seconds ( Ctrl-E c o to skip delay)\n"); } release_lock(); # TERM may be empty (SLES 12, PowerKVM); a terminal multiplexer needs it. if (!$ENV{'TERM'}) { $ENV{'TERM'} = "vt100"; } # Attach to the KVM guest's serial console inside a shared tmux session on the # hypervisor. tmux (unlike screen) is present on every libvirt host we target, # incl. ppc64le power hosts that ship no screen; `new-session -A` gives the same # detach/reattach + multi-client behaviour screen provided (goconserver and an # interactive rcons share one session). The console itself is opened by # `virsh console` keyed on the domain name (== the xCAT node name for KVM), which # is stable across guest reboots (the raw serial pty is not). -x/-y size the # pane so the guest sees a sane terminal geometry. my $node = $ARGV[0]; my $session = "serial-$node-cons"; my $virshcons = "virsh -c qemu:///system console --force $node"; # Create the session once, detached, with the status bar OFF so the captured # console log stays clean serial (no tmux chrome/clock redraws) -- matching what # screen gave; then attach. `new-session -d -A` is a no-op if it already exists, # so concurrent clients (goconserver + rcons) share the single session. exec "ssh -t $dsthost \"tmux -u new-session -d -A -x 200 -y 50 -s $session '$virshcons'; tmux set-option -t $session status off; exec tmux -u attach -t $session\"";