# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT::PPCcli; use strict; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(SUCCESS RC_ERROR EXPECT_ERROR NR_ERROR); use Expect; ############################################# # Removes Ctrl characters from term output ############################################# $ENV{'TERM'} = "vt100"; ############################################## # Constants ############################################## use constant { SUCCESS => 0, RC_ERROR => 1, EXPECT_ERROR => 2, NR_ERROR => 3, DEFAULT_TIMEOUT => 60 }; ############################################## # lssyscfg supported formats ############################################## my %lssyscfg = ( fsp =>"lssyscfg -r sys -m %s -F %s", cec =>"lssyscfg -r sys -m %s -F %s", fsps =>"lssyscfg -r sys -F %s", node =>"lssyscfg -r lpar -m %s -F %s --filter lpar_ids=%s", lpar =>"lssyscfg -r lpar -m %s -F %s", lpar2 =>"lssyscfg -r lpar -m %s --filter %s", bpa =>"lssyscfg -r frame -e %s -F %s", frame =>"lssyscfg -r frame -e %s -F %s", bpas =>"lssyscfg -r frame -F %s", prof =>"lssyscfg -r prof -m %s --filter %s", profs =>"lssyscfg -r prof -m %s -F %s --filter %s", cage =>"lssyscfg -r cage -e %s -F %s" ); my %chsyscfg = ( prof =>"chsyscfg -r prof -m %s -i %s", bpa =>"chsyscfg -r frame -e %s -i %s", fsp =>"chsyscfg -r sys -m %s -i %s", frame =>"chsyscfg -r frame -e %s -i %s", cec =>"chsyscfg -r sys -m %s -i %s", ); ############################################## # Power control supported formats ############################################## my %powercmd = ( lpar => { on =>"chsysstate -r %s -m %s -o on -b norm --id %s -f %s", of =>"chsysstate -r %s -m %s -o on --id %s -f %s -b of", sms =>"chsysstate -r %s -m %s -o on --id %s -f %s -b sms", reset =>"chsysstate -r %s -m %s -o shutdown --id %s --immed --restart", off =>"chsysstate -r %s -m %s -o shutdown --id %s --immed", softoff =>"chsysstate -r %s -m %s -o shutdown --id %s", boot =>"undetermined" }, sys => { reset =>"chsysstate -r %s -m %s -o off --immed --restart", on =>"chsysstate -r %s -m %s -o on", onstandby =>"chsysstate -r %s -m %s -o onstandby", off =>"chsysstate -r %s -m %s -o off", boot =>"undetermined" } ); ############################################## # lsrefcode supported formats ############################################## my %lsrefcode = ( fsp => { pri =>"lsrefcode -r sys -m %s -s p", sec =>"lsrefcode -r sys -m %s -s s", }, cec => { pri =>"lsrefcode -r sys -m %s -s p", sec =>"lsrefcode -r sys -m %s -s s", }, lpar =>"lsrefcode -r lpar -m %s --filter lpar_ids=%s", ); ############################################## # mksysconn support formats ############################################## my %mksysconn = ( fsp => "mksysconn --ip %s -r sys --passwd %s", cec => "mksysconn --ip %s -r sys --passwd %s", bpa => "mksysconn --ip %s -r frame --passwd %s", frame => "mksysconn --ip %s -r frame --passwd %s", ); ############################################## # rmsysconn support formats ############################################## my %rmsysconn = ( fsp => "rmsysconn -o remove --ip %s", cec => "rmsysconn -o remove --ip %s", bpa => "rmsysconn -o remove --ip %s", frame => "rmsysconn -o remove --ip %s", ); ############################################## # lssysconn support formats ############################################## my %lssysconn = ( all => "lssysconn -r all", alls => "lssysconn -r all -F %s" ); ############################################## # Change IP address for managed systems # or frames ############################################## my %chsyspwd = ( fsp => "chsyspwd -t %s -m %s --passwd %s --newpasswd %s", bpa => "chsyspwd -t %s -e %s --passwd %s --newpasswd %s", cec => "chsyspwd -t %s -m %s --passwd %s --newpasswd %s", frame => "chsyspwd -t %s -e %s --passwd %s --newpasswd %s", ); ########################################################################## # Logon to remote server ########################################################################## sub connect { my $req = shift; my $hwtype = shift; my $server = shift; my $pwd_prompt = 'assword: $'; my $continue = 'continue connecting (yes/no)?'; my $retry = $req->{ppcretry}; my $timeout = $req->{ppctimeout}; my $verbose = $req->{verbose}; my $ssh; my $expect_log; my $errmsg; if ($req->{command} eq 'rflash') { $verbose = 0; } ################################################## # Use timeout from site table (if defined) ################################################## if ( !$timeout ) { $timeout = DEFAULT_TIMEOUT; } ################################################## # Shell prompt regexp based on HW Type ################################################## my %prompt = ( hmc => "~> \$", ivm => "\\\$ \$" ); ################################################## # Get userid/password ################################################## my $cred = $req->{$server}{cred}; my $parameters = "@$cred[0]\@$server"; ################################################## # Redirect STDERR to variable ################################################## if ( $verbose ) { close STDERR; if ( !open( STDERR, '>', \$expect_log )) { return( "Unable to redirect STDERR: $!" ); } } ################################################## # Redirect STDOUT to variable ################################################## if ( $verbose ) { close STDOUT; if ( !open( STDOUT, '>', \$expect_log )) { return( "Unable to redirect STDOUT: $!" ); } } ###################################################### # -re $continue # "The authenticity of host can't be established # RSA key fingerprint is .... # Are you sure you want to continue connecting (yes/no)?" # # -re pwd_prompt # If the keys have already been transferred, we # may already be at the command prompt without # sending the password. # ###################################################### while ( $retry-- ) { my $success = 0; my $pwd_sent = 0; $expect_log = undef; $ssh = new Expect; ################################################## # raw_pty() disables command echoing and CRLF # translation and gives a more pipe-like behaviour. # Note that this must be set before spawning # the process. Unfortunately, this does not work # with AIX (IVM). stty(qw(-echo)) will at least # disable command echoing on all platforms but # will not suppress CRLF translation. ################################################## #$ssh->raw_pty(1); $ssh->slave->stty(qw(sane -echo)); ################################################## # exp_internal(1) sets exp_internal debugging # to STDERR. ################################################## $ssh->exp_internal( $verbose ); ################################################## # log_stdout(0) disables logging to STDOUT. # This corresponds to the Tcl log_user variable. ################################################## $ssh->log_stdout( $verbose ); unless ( $ssh->spawn( "ssh", $parameters )) { return( $expect_log."Unable to spawn ssh connection to server"); } my @result = $ssh->expect( $timeout, [ $continue, sub { $ssh->send( "yes\r" ); $ssh->clear_accum(); $ssh->exp_continue(); } ], [ $pwd_prompt, sub { if ( ++$pwd_sent ) { $ssh->send( "@$cred[1]\r" ); $ssh->exp_continue(); } } ], [ $prompt{$hwtype}, sub { $success = 1; } ] ); ########################################## # Expect error - retry ########################################## if ( defined( $result[1] )) { $errmsg = $expect_log.expect_error(@result); sleep(1); next; } ########################################## # Successful logon.... # Return: # Expect # HW Shell Prompt regexp # HW Type (hmc/ivm) # Server hostname # UserId # Password # Redirected STDERR/STDOUT # Connect/Command timeout ########################################## if ( $success ) { return( $ssh, $prompt{$hwtype}, $hwtype, $server, @$cred[0], @$cred[1], \$expect_log, $timeout ); } ########################################## # Failed logon - kill ssh process ########################################## $ssh->hard_close(); return( $expect_log."Invalid userid/password" ); } $ssh->hard_close(); return( $errmsg ); } ########################################################################## # Logoff to remote server ########################################################################## sub disconnect { my $exp = shift; my $ssh = @$exp[0]; if ( defined( $ssh )) { $ssh->send( "exit\r" ); $ssh->hard_close(); @$exp[0] = undef; } } ########################################################################## # List attributes for resources (lpars, managed system, etc) ########################################################################## sub lssyscfg { my $exp = shift; my $res = shift; my $d1 = shift; my $d2 = shift; my $d3 = shift; ################################### # Select command ################################### my $cmd = sprintf( $lssyscfg{$res}, $d1, $d2, $d3 ); ################################### # Send command ################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Changes a logical partition configuration data ########################################################################## sub chsyscfg { my $exp = shift; my $res = shift; my $d = shift; my $cfgdata = shift; ##################################### # Select command ##################################### my $cmd = sprintf( $chsyscfg{$res}, @$d[2], $cfgdata ); ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # List reference codes for resources (lpars, managed system, etc) ########################################################################## sub lsrefcode { my $exp = shift; my $res = shift; my $d1 = shift; my $d2 = shift; my $cmd = undef; my @cmds = undef; my $result = undef; my @values; ################################### # Select command ################################### if($res =~ /^(fsp|cec)$/) { $cmds[0] = sprintf($lsrefcode{$res}{pri}, $d1); $cmds[1] = sprintf($lsrefcode{$res}{sec}, $d1); } elsif($res eq 'lpar'){ $cmds[0] = sprintf($lsrefcode{$res}, $d1, $d2); } else { return [[0,'Not available']]; } ################################### # Send command ################################### foreach $cmd (@cmds){ $result = send_cmd( $exp, $cmd ); push @values, $result; } return \@values; } ########################################################################## # Creates a logical partition on the managed system ########################################################################## sub mksyscfg { my $exp = shift; my $res = shift; my $d = shift; my $cfgdata = shift; ##################################### # Command only support on LPARs ##################################### if ( @$d[4] ne "lpar" ) { return( [RC_ERROR,"Command not supported on '@$d[4]'"] ); } ##################################### # Format command based on CEC name ##################################### my $cmd = "mksyscfg -r $res -m @$d[2] -i \"$cfgdata\""; ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Removes a logical partition on the managed system ########################################################################## sub rmsyscfg { my $exp = shift; my $d = shift; ##################################### # Command only supported on LPARs ##################################### if ( @$d[4] ne "lpar" ) { return( [RC_ERROR,"Command not supported on '@$d[4]'"] ); } ##################################### # Format command based on CEC name ##################################### my $cmd = "rmsyscfg -r lpar -m @$d[2] --id @$d[0]"; ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Lists environmental information ########################################################################## sub lshwinfo { my $exp = shift; my $res = shift; my $frame = shift; my $filter = shift; ##################################### # Format command based on CEC name ##################################### my $cmd = "lshwinfo -r $res -e $frame -F $filter"; ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Changes the state of a partition or managed system ########################################################################## sub chsysstate { my $exp = shift; my $op = shift; my $d = shift; ##################################### # Format command based on CEC name ##################################### my $cmd = power_cmd( $op, $d ); if ( !defined( $cmd )) { return( [RC_ERROR,"'$op' command not supported"] ); } ##################################### # Special case - return immediately ##################################### if ( $cmd =~ /^reboot$/ ) { my $ssh = @$exp[0]; $ssh->send( "$cmd\r" ); return( [SUCCESS,"Success"] ); } ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Opens a virtual terminal session ########################################################################## sub mkvterm { my $exp = shift; my $type = shift; my $lparid = shift; my $mtms = shift; my $ssh = @$exp[0]; my $hwtype = @$exp[2]; my $failed = 0; my $timeout = 3; ########################################## # Format command based on HW Type ########################################## my %mkvt = ( hmc =>"mkvterm --id %s -m %s", ivm =>"mkvt -id %s" ); ########################################## # HMC returns: # "A terminal session is already open # for this partition. Only one open # session is allowed for a partition. # Exiting...." # # HMCs may also return: # "The open failed. # "-The session may already be open on # another management console" # # But Expect (for some reason) sees each # character preceeded with \000 (blank??) # ########################################## my $fail_msg = "HSCL"; my $ivm_open = "Virtual terminal is already connected"; my $hmc_open = "\000o\000p\000e\000n\000 \000f\000a\000i\000l\000e\000d"; my $hmc_open2 = "\000a\000l\000r\000e\000a\000d\000y\000 \000o\000p\000e\000n"; ########################################## # Set command based on HW type # mkvterm -id lparid -m cecmtms ########################################## my $cmd = sprintf( $mkvt{$hwtype}, $lparid, $mtms ); if ( $type ne "lpar" ) { return( [RC_ERROR,"Command not supported on '$type'"] ); } ########################################## # Close the old sessions ########################################## if ( $hwtype eq "ivm" ) { rmvterm( $exp, $lparid, $mtms ); sleep 1; } else { rmvterm_noforce( $exp, $lparid, $mtms ); sleep 1; } ########################################## # Send command ########################################## $ssh->clear_accum(); $ssh->send( "$cmd\r" ); ########################################## # Expect result ########################################## my @result = $ssh->expect( $timeout, [ "$hmc_open|$hmc_open2|$ivm_open|$fail_msg", sub { $failed = 1; } ] ); if ( $failed ) { $ssh->hard_close(); if (grep(/$fail_msg/, @result)) { return( [RC_ERROR, "mkvterm returns the unsuccessful value, please check your entry and retry the command."] ); } else { return( [RC_ERROR,"Virtual terminal is already connected"] ); } } ########################################## # Success... # Give control to the user and intercept # the Ctrl-X (\030). ########################################## my $escape = "\030"; $ssh->send( "\r" ); $ssh->interact( \*STDIN, $escape ); ########################################## # Close session ########################################## rmvterm( $exp, $lparid, $mtms ); $ssh->hard_close(); return( [SUCCESS,"Success"] ); } ########################################################################## # Force close a virtual terminal session ########################################################################## sub rmvterm { my $exp = shift; my $lparid = shift; my $mtms = shift; my $ssh = @$exp[0]; my $hwtype = @$exp[2]; ##################################### # Format command based on HW Type ##################################### my %rmvt = ( hmc =>"rmvterm --id %s -m %s", ivm =>"rmvt -id %s" ); ##################################### # Set command based on HW type # rmvt(erm) -id lparid -m cecmtms ##################################### my $cmd = sprintf( $rmvt{$hwtype}, $lparid, $mtms ); ##################################### # Send command ##################################### $ssh->clear_accum(); $ssh->send( "$cmd\r" ); } ########################################################################## # Force close a virtual terminal session ########################################################################## sub rmvterm_noforce { my $exp = shift; my $lparid = shift; my $mtms = shift; my $ssh = @$exp[0]; my $hwtype = @$exp[2]; ##################################### # Format command based on HW Type ##################################### my %rmvt = ( hmc =>"rmvterm --id %s -m %s", ivm =>"rmvt -id %s" ); ##################################### # Set command based on HW type # rmvt(erm) -id lparid -m cecmtms ##################################### my $cmd = sprintf( $rmvt{$hwtype}, $lparid, $mtms ); ##################################### # Send command ##################################### send_cmd( $exp, $cmd ); } ########################################################################## # Lists the hardware resources of a managed system ########################################################################## sub lshwres { my $exp = shift; my $d = shift; my $mtms = shift; my $cmd = "lshwres -r @$d[1] -m $mtms"; my $level = @$d[0]; my $Filter = @$d[2]; my $rsubtype = @$d[3]; ##################################### # Specify Filters ##################################### if ( $Filter ) { $cmd .=" -F $Filter"; } ##################################### # level may be "sys" or "lpar" ##################################### if ( defined( $level )) { $cmd .=" --level $level"; } ##################################### # Specify subtype ##################################### if ( $rsubtype ) { $cmd .=" --rsubtype $rsubtype" } ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd ); return( $result ); } ########################################################################## # Retrieve MAC-address from network adapter or network boots an LPAR ########################################################################## sub lpar_netboot { my $exp = shift; my $verbose = shift; my $name = shift; my $d = shift; my $opt = shift; my $timeout = my $t = @$exp[7]*10; my $cmd = "lpar_netboot -t ent -f"; my $gateway = $opt->{G}; my $node = @$d[6]; ##################################### # Power6 HMCs (V7) do not support # 0.0.0.0 gateway. ##################################### if ( $gateway =~ /^0.0.0.0$/ ) { my $fw = lshmc( $exp, "RM" ); my $Rc = shift(@$fw); if ( $Rc == SUCCESS ) { if ( @$fw[0] =~ /^V(\d+)/ ) { ######################### # Power4 not supported ######################### if ( $1 < 6 ) { return( [RC_ERROR,"Command not supported on V$1 HMC"] ); } ######################### # Use server for gateway ######################### elsif ( $1 >= 7 ) { $opt->{G} = $opt->{S}; } } } } ##################################### # Verbose output ##################################### if ( $verbose ) { $cmd.= " -x -v"; } ##################################### # Force LPAR shutdown if -f specified ##################################### if ( exists( $opt->{f} )) { $cmd.= " -i"; } else { ################################# # Force LPAR shutdown if LPAR is # running Linux ################################# my $table = "nodetype"; my $intable = 0; my @TableRowArray = xCAT::DBobjUtils->getDBtable($table); if ( @TableRowArray ) { foreach ( @TableRowArray ) { my @nodelist = split(',', $_->{'node'}); my @oslist = split(',', $_->{'os'}); my $osname = "AIX"; if ( grep(/^$node$/, @nodelist) ) { if ( !grep(/^$osname$/, @oslist) ) { $cmd.= " -i"; } $intable = 1; last; } } } ################################# # Force LPAR shutdown if LPAR OS # type is not assigned in table # but mnt node is running Linux ################################# if ( xCAT::Utils->isLinux() && $intable == 0 ) { $cmd.= " -i"; } } ##################################### # Get MAC-address or network boot ##################################### my $mac = $opt->{m}; $cmd.= ( defined( $mac )) ? " -m $mac" : " -M -A -n"; ##################################### # Command only supported on LPARs ##################################### if ( @$d[4] ne "lpar" ) { return( [RC_ERROR,"Command not supported on '@$d[4]'"] ); } ##################################### # Network specified (-D ping test) ##################################### if ( exists( $opt->{S} )) { my %nethash = xCAT::DBobjUtils->getNetwkInfo( [$node] ); ##################################### # Network attributes undefined ##################################### if ( !%nethash ) { return( [RC_ERROR,"Cannot get network information for $node"] ); } my $netmask = $nethash{$node}{mask}; $cmd.= (!defined( $mac )) ? " -D" : ""; $cmd.= " -s auto -d auto -S $opt->{S} -G $opt->{G} -C $opt->{C} -K $netmask"; } ##################################### # Add lpar name, profile, CEC name ##################################### $cmd.= " \"$name\" \"@$d[1]\" \"@$d[2]\""; ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd, $timeout ); return( $result ); } ########################################################################## # List Hardware Management Console configuration information ########################################################################## sub lshmc { my $exp = shift; my $attr = shift; my $hwtype = @$exp[2]; ##################################### # Format command based on HW Type ##################################### my %cmd = ( hmc =>"lshmc -v", ivm =>"lsivm" ); ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd{$hwtype} ); ##################################### # Return error ##################################### if ( @$result[0] != SUCCESS ) { return( $result ); } ##################################### # Only return attribute requested ##################################### if ( defined( $attr )) { if ( my ($vpd) = grep( /^\*$attr\s/, @$result )) { $vpd =~ s/\*$attr\s+//; return( [SUCCESS, $vpd ] ); } return( [RC_ERROR, "'$attr' not found"] ); } ##################################### # IVM returns: # 9133-55A,10B7D1G,1 # # HMC returns: # "vpd=*FC ???????? # *VC 20.0 # *N2 Mon Sep 24 13:54:00 GMT 2007 # *FC ???????? # *DS Hardware Management Console # *TM 7310-CR4 # *SE 1017E6B # *MN IBM # *PN Unknown # *SZ 1058721792 # *OS Embedded Operating Systems # *NA 9.114.222.111 # *FC ???????? # *DS Platform Firmware # *RM V7R3.1.0.1 ##################################### if ( $hwtype eq "ivm" ) { my ($model,$serial,$lparid) = split /,/, @$result[1]; return( [SUCCESS,"$model,$serial"] ); } my @values; my $vpd = join( ",", @$result ); ##################################### # Power4 (and below) HMCs unsupported ##################################### if ( $vpd =~ /\*RM V(\d+)/ ) { if ( $1 <= 5 ) { return( [RC_ERROR,"Command not supported on V$1 HMC"] ); } } ##################################### # Type-Model may be in the formats: # "eserver xSeries 336 -[7310CR3]-" # "7310-CR4" ##################################### if ( $vpd =~ /\*TM ([^,]+)/ ) { my $temp = $1; my $model = ($temp =~ /\[(.*)\]/) ? $1 : $temp; push @values, $model; } ##################################### # Serial number ##################################### if ( $vpd =~ /\*SE ([^,]+)/ ) { push @values, $1; } return( [SUCCESS,join( ",",@values)] ); } ########################################################################## # Updates authorized_keys2 file on the HMC/IVM ########################################################################## sub mkauthkeys { my $exp = shift; my $option = shift; my $logon = shift; my $sshkey = shift; my $ssh = @$exp[0]; my $hwtype = @$exp[2]; my $userid = @$exp[4]; ######################################### # On IVM-based systems, the mkauthkeys # command does not exist, so we have to # include the generated key at # /home//.ssh/authorized_keys2 # manually. ######################################### if ( $hwtype =~ /^ivm$/ ) { my @authkey; my $auth = "/home/$userid/.ssh/authorized_keys2"; my $result = send_cmd( $exp, "cat $auth" ); my $Rc = shift(@$result); ##################################### # Return error ##################################### if ( $Rc != SUCCESS ) { return( $result ); } ##################################### # When adding, remove old keys first ##################################### foreach ( @$result ) { unless ( /$logon$/ ) { push @authkey, $_; } } ##################################### # Add new key ##################################### if ( $option =~ /^enable$/i ) { push @authkey, $sshkey; } ##################################### # Rewrite the key file ##################################### my $keys = join( "\n", @authkey ); $result = send_cmd( $exp,"echo \"$keys\" | tee $auth" ); return( $result ); } ######################################### # When adding, remove old keys first ######################################### my $result = send_cmd( $exp,"mkauthkeys --remove '$logon'" ); if ( $option =~ /^enable$/i ) { $result = send_cmd( $exp,"mkauthkeys --add '$sshkey'" ); } return( $result ); } ########################################################################## # List Licensed Internal Code levels on HMC for FSP/BPAs ########################################################################## sub lslic { my $exp = shift; my $d = shift; my $timeout = shift; my $cmd = "lslic "; ########################################## # Use timeout from site table (if defined) ########################################## if ( !defined( $timeout ) || $timeout == 0 ) { $timeout = @$exp[7] * 3; } ##################################### # Command only support on CEC/BPAs ##################################### if ( @$d[4] !~ /^(fsp|bpa)$/ ) { return( [RC_ERROR,"Command not supported on '@$d[4]'"] ); } ##################################### # Format command based on name ##################################### $cmd.= (@$d[4] =~ /^fsp$/) ? "-t sys -m " : "-t power -e "; $cmd.= @$d[2]; ##################################### # Send command ##################################### my $result = send_cmd( $exp, $cmd , $timeout); return( $result ); } ########################################################################## # Sends command and waits for response ########################################################################## sub send_cmd { my $exp = shift; my $cmd = shift; my $timeout = shift; my $ssh = @$exp[0]; my $prompt = @$exp[1]; ########################################## # Use timeout from site table (if defined) ########################################## if ( !defined( $timeout )) { $timeout = @$exp[7]; } ########################################## # Send command ########################################## $ssh->clear_accum(); $ssh->send( "$cmd; echo Rc=\$\?\r" ); ########################################## # The first element is the number of the # pattern or string that matched, the # same as its return value in scalar # context. The second argument is a # string indicating why expect returned. # If there were no error, the second # argument will be undef. Possible errors # are 1:TIMEOUT, 2:EOF, 3:spawn id(...)died, # and "4:..." (see Expect (3) manpage for # the precise meaning of these messages) # The third argument of expects return list # is the string matched. The fourth argument # is text before the match, and the fifth # argument is text after the match. ########################################## my @result = $ssh->expect( $timeout, "-re", "(.*$prompt)" ); ########################################## # Expect error ########################################## if ( defined( $result[1] )) { return( [EXPECT_ERROR,expect_error( @result )] ); } ########################################## # Extract error code ########################################## if ( $result[3] =~ s/Rc=([0-9])+\r\n// ) { if ( $1 != 0 ) { return( [RC_ERROR,$result[3]] ); } } ########################################## # No data found - return error ########################################## if ( $result[3] =~ /No results were found/ ) { return( [NR_ERROR,"No results were found"] ); } ########################################## # If no command output, return "Success" ########################################## if ( length( $result[3] ) == 0 ) { $result[3] = "Success"; } ########################################## # Success ########################################## my @values = ( SUCCESS ); push @values, split /\r\n/, $result[3]; return( \@values ); } ########################################################################## # Return Expect error ########################################################################## sub expect_error { my @error = @_; ########################################## # The first element is the number of the # pattern or string that matched, the # same as its return value in scalar # context. The second argument is a # string indicating why expect returned. # If there were no error, the second # argument will be undef. Possible errors # are 1:TIMEOUT, 2:EOF, 3:spawn id(...)died, # and "4:..." (see Expect (3) manpage for # the precise meaning of these messages) # The third argument of expects return list # is the string matched. The fourth argument # is text before the match, and the fifth # argument is text after the match. ########################################## if ( $error[1] eq "1:TIMEOUT" ) { return( "Timeout waiting for prompt" ); } if ( $error[1] eq "2:EOF" ) { if ( $error[3] ) { return( $error[3] ); } return( "ssh connection terminated unexpectedly" ); } return( "Logon failed" ); } ########################################################################## # Returns built command based on CEC/LPAR action ########################################################################## sub power_cmd { my $op = shift; my $d = shift; #my $type = (@$d[4] eq "fsp") ? "sys" : @$d[4]; my $type = ( @$d[4] =~ /^(fsp|cec)$/ ) ? "sys" : @$d[4]; ############################## # Build command ############################## my $cmd = $powercmd{$type}{$op}; if ( defined( $cmd )) { return( sprintf( $cmd, $type, @$d[2],@$d[0],@$d[1] )); } ############################## # Command not supported ############################## return undef; } ##################################### # Reset HMC network (hostname & IP) ##################################### sub network_reset { my $exp = shift; my $current_ip = shift; my $hostname_ip =shift; my $hwtype = @$exp[2]; my ($ip,$hostname) = split /,/, $hostname_ip; if ( !$hostname || !$ip) { return ( [RC_ERROR,"No valid hostname or IP find. This could be a internal bug of xCAT."] ); } ##################################### # Format command based on HW Type ##################################### my %cmd = ( hmc =>"lshmc -n -F hostname:ipaddr", ivm =>"lsivm" #just for future consideration ); ##################################### # Get current hostname and IP ##################################### my $result = send_cmd( $exp, $cmd{$hwtype} ); if ( @$result[0] != SUCCESS ) { return( $result ); } my ($current_hostname,$current_all_ip) = split /:/, @$result[1]; ##################################### # Find the correct interface ##################################### my @eth_ip = split /,/,$current_all_ip; my $i; my $matched = 0; for( $i=0; $i < scalar(@eth_ip); $i++) { if ($eth_ip[$i] eq $current_ip) { $matched = 1; last; } } if ( !$matched ) { # What's happen? return ( [RC_ERROR,"No appropriate IP addresses to be updated. This could be a internal bug of xCAT."]); } %cmd = ( # probably need update netmask also hmc => "chhmc -c network -s modify -h $hostname -i eth$i -a $ip", ivm => "nothing" ); $result = send_cmd( $exp, $cmd{$hwtype} ); ##################################### # Return error ##################################### return( $result ); } ########################################################################## # List connection for CEC/BPA ########################################################################## sub lssysconn { my $exp = shift; my $res = shift; my $filter = shift; my $cmd = sprintf( $lssysconn{$res}, $filter ); my $result = send_cmd( $exp, $cmd); return ( $result); } ########################################################################## # Create connection for CEC/BPA ########################################################################## sub mksysconn { my $exp = shift; my $ip = shift; my $type = shift; my $passwd = shift; my $cmd = sprintf( $mksysconn{$type}, $ip, $passwd); my $result = send_cmd( $exp, $cmd); return ( $result); } ########################################################################## # Change IP address for managed systems or frames ########################################################################## sub chsyspwd { my $exp = shift; my $user = shift; my $type = shift; my $mtms = shift; my $passwd = shift; my $newpwd = shift; my $cmd = sprintf( $chsyspwd{$type}, $user, $mtms, $passwd, $newpwd ); my $result = send_cmd( $exp, $cmd); return ( $result ); } ########################################################################## # Remove connection for CEC/BPA ########################################################################## sub rmsysconn { my $exp = shift; my $type = shift; my $name = shift; my $cmd = sprintf( $rmsysconn{$type}, $name); my $result = send_cmd( $exp, $cmd); return ( $result); } ########################################################################## # Get FSP/BPA IP address for the redundancy FSP/BPA from HMC ########################################################################## sub getHMCcontrolIP { my $node = shift; if (($node) && ($node =~ /xCAT::/)) { $node = shift; } my $exp = shift; #get node type first my $type = xCAT::DBobjUtils::getnodetype($node, "ppc"); unless ($type) { return undef; } #get node ip from hmc my $tab = xCAT::Table->new("vpd"); my $ent; if ($tab) { $ent = $tab->getNodeAttribs($node, ['serial', 'mtm']); } my $serial = $ent->{'serial'}; my $mtm = $ent->{'mtm'}; #my $mtms = $mtm . '*' . $serial; #my $nodes_found = lssyscfg( $exp, "$type", "$mtms"); my $nodes_found = lssysconn ($exp, "all"); my @ips; my $ip_result; if ( @$nodes_found[0] eq SUCCESS ) { my $Rc = shift(@$nodes_found); #my @newnodes = split(/,/, $nodes_found->[0]); #$Rc = shift(@newnodes); #for my $entry (@newnodes) { # if(xCAT::Utils->isIpaddr($entry)) { # push @ips,$entry; # } # $ip_result = join( ",", @ips ); #} foreach my $entry ( @$nodes_found ) { if ( $entry =~ /$mtm\*$serial/) { $entry =~ /ipaddr=(\d+\.\d+\.\d+\.\d+),/; push @ips, $1; } } $ip_result = join( ",", @ips ); } return $ip_result; } 1;