## @summary StateDefinitions Module ## @author anerudh@netapp.com, dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::Transit::StateDefinitions =head1 DESCRIPTION The NACL::Transit::StateDefinitions module contains information on how to detect each state and what transitions to other states are possible from each state. A state corresponds to a prompt or a set of prompts ( the occurance of the prompt is detected as the occurance of the state ). Each state is represented as a package with subroutines bearing the names of other terminal states or state types (base class states) which return information about what has to be done next for getting to that state or state type. For some state types, the action to be performed for reaching a particular kind of state may be contained in the base class of that state. =cut package NACL::Transit::StateDefinitions; #########################BASE CLASS############################################# =head2 NACL::Transit::StateDefinitions::STATE The NACL::Transit::StateDefinitions::STATE package is the base class of all types of states and contains data that is made available to each state type (package). Items include the hostrec object being used, the current state, the destination state, the username to login, password, the halt command that is being used, the action to perform when taken over, diag password and the value indicating whether to restore system configuration (syncflash). =cut package NACL::Transit::StateDefinitions::STATE; our ( $regex, $host, $from, $to, $username, $password, $haltcmd, $iftakenover, $diag_password, $restore_system_config, $bootimage, $conn, $ifpanic ); sub is_ONTAP { my $state = shift; return 1 if $state->isa('NACL::Transit::StateDefinitions::ONTAP'); return 0; } sub is_Transient { my $state = shift; return 1 if ${"$state".'::is_transient'}; return 0; } sub SERVICE_PROCESSOR { [ 1, "\cG" ]; } ##############################ONTAP BASE CLASS################################## package NACL::Transit::StateDefinitions::ONTAP; use base qw/NACL::Transit::StateDefinitions::STATE/; #############################BANNER BASE CLASS################################## package NACL::Transit::StateDefinitions::BANNER; use base qw/NACL::Transit::StateDefinitions::STATE/; # generic methods for all BANNER states sub STATE { [ 1, "" ]; } sub FIRMWARE { [ 0, " " ]; } ##################BASE CLASSES FOR DISK_ZERO AND UP_OR_TAKE_OVER################ package NACL::Transit::StateDefinitions::DISK_ZERO; use base qw/NACL::Transit::StateDefinitions::ONTAP/; package NACL::Transit::StateDefinitions::UP_OR_TAKEN_OVER; use base qw/NACL::Transit::StateDefinitions::ONTAP/; ###############################BASE CLASS FOR TAKE_OVER######################### package NACL::Transit::StateDefinitions::TAKE_OVER; use base qw/NACL::Transit::StateDefinitions::UP_OR_TAKEN_OVER/; # Exceptions use NACL::Transit::Exceptions::TransitException qw/:try/; use NATE::Exceptions::Argument qw/:try/; # sub execute_before { if ( $iftakenover eq "error" ) { alarm 0; NACL::Transit::Exceptions::TransitException->throw( "partner has taken over"); } elsif ( $iftakenover eq "wait" ) { } elsif ( $iftakenover ne "takeback" ) { alarm 0; NATE::Exceptions::Argument->throw( "unknown value '$iftakenover' for iftakenover option"); } } sub STATE { [ 1, "" ]; #for "wait" } #############################BASE CLASS FOR SERVICE_PROCESSOR################### package NACL::Transit::StateDefinitions::SERVICE_PROCESSOR; use base qw/NACL::Transit::StateDefinitions::STATE/; sub STATE { [ 1, "exit\r"]; } sub SERVICE_PROCESSOR { # this is to avoid doing a Ctrl-G when we're already in a service processor # state (Overriding the default behavior defined in package STATE) return STATE(); } #############################BASE CLASS FOR UP################################## package NACL::Transit::StateDefinitions::UP; use base qw/NACL::Transit::StateDefinitions::UP_OR_TAKEN_OVER/; ############################# ACTUAL STATES #################################### =head2 NACL::Transit::StateDefinitions::CLI The state when the the console logged in at the normal (NGSH or 7Mode CLI) / take over prompt. =over =item Examples abcd-vsim3::*> abcd-vsim3::volume*> fas-abcd-05*> =back =cut package NACL::Transit::StateDefinitions::CLI; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { [ 1, "$haltcmd\r" ]; } sub DBLADECLI { return [ 0, "system node run -node local\r" ] if $host->hosttype() =~ /filer-ng/; alarm 0; NACL::Transit::Exceptions::TransitException->throw("DBALDECLI is supported". " only on CMode"); } sub SYSTEMSHELL { my $hosttype = $host->hosttype(); my @arr = ( 0, "priv set advanced ; useradmin diaguser unlock ; systemshell\r", 0, "diag\r", 0, "$diag_password\r" ); if ( $hosttype =~ /filer-ng/ ) { my $output = $conn->execute( command => "set -confirmations off; rows 0;set -privilege test; system node uichanges local;" ); #as per burt 956571 systemshell directly prompts for password if ( $output =~ /security-protocol-unsecure-enable-disable/ ){ splice(@arr,2,2); } my $privilege = 'diagnostic'; if ( $output =~ /systemshell-remote-node/ ) { $privilege = 'test'; } $arr[1] = "set -confirmations off -privilege $privilege ; " . "system node systemshell -node local\r"; } return \@arr; } sub UP { # for 7Mode, use Ctrl-D to exit out of this state my $exit_sequence = "\cD"; # for CMode, use "exit\r" to exit out of this state if ( $host->hosttype() =~ /filer-ng/ ) { $exit_sequence = "exit\r"; } return [0, $exit_sequence]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::DBLADECLI The state when the console is at the Nodescope prompt. This is applicable only for CMode. =over =item Example abcd-vsim3-01> =back =cut package NACL::Transit::StateDefinitions::DBLADECLI; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { [ 1, "$haltcmd\r" ]; } sub UP { [0, "exit\r"]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::SYSTEMSHELL The SYSTEMSHELL / FreeBSD prompt. =over =item Examples abcd-vsim3-01% fas-abcd% =back =cut package NACL::Transit::StateDefinitions::SYSTEMSHELL; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { [ 1, "sudo halt\r" ]; } sub UP { [0, "exit\r"]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::LOGIN_TO_SYSTEMSHELL_QUERY The state corresponds to the prompt "Do you want to login to the systemshell as the 'diag' user?" if to_state is "SYSTEMSHELL" then it will be answered as "yes" else "no" =cut package NACL::Transit::StateDefinitions::LOGIN_TO_SYSTEMSHELL_QUERY; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { [ 0, "no\r" ]; } sub SYSTEMSHELL { my @arr = ( 0, "yes\r", 0, "diag\r", 0, "$diag_password\r" ); #as per burt 956571 systemshell directly prompts for password if ( $host->is_cmode() ) { my $output = $conn->execute( command => "set -confirmations off; rows 0;set -privilege test; system node uichanges local;" ); if ( $output =~ /security-protocol-unsecure-enable-disable/ ){ splice(@arr,2,2); } } return \@arr; } ################################################################################ =head2 NACL::Transit::StateDefinitions::HALT_REBOOT_QUERY The state corresponds to the prompts "Are you sure you want to reboot node "sti71-vsim-ucs168i"? {y|n}" "Are you sure you want to halt node "sti71-vsim-ucs168i"? {y|n}" "Do you want to continue? {y|n}" =cut package NACL::Transit::StateDefinitions::HALT_REBOOT_QUERY; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { [ 1, "yes\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::SP the service processor prompt. Either after logging in as admin or naroot at the SP_LOGIN prompt. =cut package NACL::Transit::StateDefinitions::SP; use base qw/NACL::Transit::StateDefinitions::SERVICE_PROCESSOR/; ################################################################################ =head2 NACL::Transit::StateDefinitions::SP_ROOT the service processor root prompt - reached after logging in as root at the SP_LOGIN prompt. =cut package NACL::Transit::StateDefinitions::SP_ROOT; use base qw/NACL::Transit::StateDefinitions::SERVICE_PROCESSOR/; ################################################################################ =head2 NACL::Transit::StateDefinitions::SP_LOGIN The state that corresponds to the login prompt of the service processor =cut package NACL::Transit::StateDefinitions::SP_LOGIN; use base qw/NACL::Transit::StateDefinitions::SERVICE_PROCESSOR/; sub STATE { [ 1, "root\r", 1, "superuser\r" ]; } sub SP_ROOT { return STATE(); } sub SP { my $hosttype = $host->hosttype(); my @arr = ( 1, "naroot\r", 1, "$password\r" ); if($hosttype =~ /filer-ng/) { $arr[1] = "admin\r"; } return \@arr; } ################################################################################ =head2 NACL::Transit::StateDefinitions::FIRMWARE This state is for the firmware prompt. The prompt that occurs after halting in BIOS based appliances. =over =item Examples SIMLOADER> CFE> LOADER-A> =back =cut package NACL::Transit::StateDefinitions::FIRMWARE; use base qw/NACL::Transit::StateDefinitions::STATE/; sub STATE { my @answer; my $hosttype = $host->hosttype(); if ( $hosttype =~ /vsim/ ) { if ($bootimage) { @answer = ( map { ( 1, "$_\r" ) } ( split( /;/, $bootimage ) ) ); } else { @answer = ( 1, "boot\r" ); } } elsif ( $hosttype =~ /cfe|ng|vsa/ ) { if ($bootimage) { @answer = ( map { ( 1, "$_\r" ) } ( split( /;/, $bootimage ) ) ); } else { @answer = ( 1, "boot_ontap\r" ); } } elsif ( $hosttype =~ /simulator/ ) { @answer = ( 1, "cd " . $host->{simdir} . " && /usr/local/bin/sudo $bootimage\r" ); } else { @answer = $bootimage ? ( 1, "boot $bootimage\r" ) : ( 1, "boot\r" ); } return \@answer; } ################################################################################ =head2 NACL::Transit::StateDefinitions::BOOT_MENU This state is for the BOOT_MENU. The Selection (1-5) prompt or variations of it. =cut package NACL::Transit::StateDefinitions::BOOT_MENU; use base qw/NACL::Transit::StateDefinitions::ONTAP/; my ( $normal_boot_command, $maint_command, $init_command, $syncflash_command ); # Something that has to be executed before we execute the code to do the # state transition sub execute_before { my $hosttype = $host->hosttype(); $normal_boot_command = $hosttype =~ /filer-ng/ ? "normal" : "1"; $maint_command = $hosttype =~ /filer-ng/ ? "maint" : "5"; $init_command = $hosttype =~ /filer-ng/ ? "init" : "4"; $syncflash_command = $hosttype =~ /filer-ng/ ? "syncflash" : "6"; if ( $regex eq 'Selection \\(1-\\d\\)\\?' ) { $normal_boot_command = "1"; $maint_command = "5"; $init_command = "4"; $syncflash_command = "6"; } } sub NORC { return [ 0, "2\r" ] if $host->hosttype() !~ /filer-ng/; alarm 0; NACL::Transit::Exceptions::TransitException->throw("Reaching NORC is not ". "yet supported on CMode"); } sub UP_OR_TAKEN_OVER { $restore_system_config ? [ 0, "$syncflash_command\r" ] : [ 0, "$normal_boot_command\r" ]; } sub DISK_ZERO { [ 0, "$init_command\r" ]; } sub MAINT { [ 0, "$maint_command\r", 0, "\r" ]; } sub STATE { [ 0, "$maint_command\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::NORC booted into "no rc mode", i.e. option "2" from the BOOT_MENU =cut package NACL::Transit::StateDefinitions::NORC; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { [1, "$haltcmd\r"]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::WIPE_CONFIG Getting the message "Wipe filer procedure requested". It will zero the disks and filer config will be wiped =cut package NACL::Transit::StateDefinitions::WIPE_CONFIG; use base qw/NACL::Transit::StateDefinitions::DISK_ZERO/; sub STATE { [ 0, "" ]; } $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::WIPE_CONFIG_QUERY Getting message "Rebooting to finish wipeconfig request". After this the system will be rebooted =cut package NACL::Transit::StateDefinitions::WIPE_CONFIG_QUERY; use base qw/NACL::Transit::StateDefinitions::DISK_ZERO/; sub WIPE_CONFIG { [ 1, ""]; } $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::ZERO_DISKS_QUERY asking one of the "are you sure?" questions before zeroing disks. After answering yes at this prompt, we reach the WIPE_CONFIG_QUERY state where the filer will be rebooted to wipe out the config. =cut package NACL::Transit::StateDefinitions::ZERO_DISKS_QUERY; use base qw/NACL::Transit::StateDefinitions::DISK_ZERO/; sub STATE { [ 1, "no\r" ]; } sub WIPE_CONFIG { [ 0, "yes\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::REBOOTING_TO_LOAD_NEW_NVRAM_FIRMWARE Getting message "REBOOTING TO LOAD NEW NVRAM FIRMWARE". After this the system will be rebooted =cut package NACL::Transit::StateDefinitions::REBOOTING_TO_LOAD_NEW_NVRAM_FIRMWARE; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { [ 1, ""]; } $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::MAINT Maintenance mode. The state reached after answering 5 at the boot menu. =cut package NACL::Transit::StateDefinitions::MAINT; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { my @answer = ( 1, "$haltcmd\r" ); @answer = ( 0, "storage release disks\r", 0, "yes\r", @answer ) if ( $iftakenover eq "takeback" ); return \@answer; } sub MAINT_SYSTEMSHELL { my @arr = ( 0, "systemshell\r", 0, "diag\r", 0, "$diag_password\r" ); return \@arr; } ################################################################################ =head2 NACL::Transit::StateDefinitions::MAINT_SYSTEMSHELL Systemshell inside Maintenance mode. It is reached by running "systemshell" command at maintainance mode =cut package NACL::Transit::StateDefinitions::MAINT_SYSTEMSHELL; use base qw/NACL::Transit::StateDefinitions::MAINT/; sub STATE { [0, "exit\r"]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::NONSTD_BOOT_QUERY the "continue with boot?" question that one is asked before entering maintenance mode on a clustered filer =cut package NACL::Transit::StateDefinitions::NONSTD_BOOT_QUERY; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { # the extra return is because the appliance seems to print one # prompt of ">" before printing "*>", so it looks like # it's reached NORC rather than MAINT. return [ 0, "yes\r", 0, "\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_WAITING_OFW The "Waiting for giveback" prompt, issued in open firmware when trying to boot from a disk when that disk has a reservation asserted by the partner. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_WAITING_OFW; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; sub STATE { my $self = shift; if ( $iftakenover eq "takeback" ) { return [ 1, "\cC", 0, "release-disks\r" ]; } else { return $self->SUPER::STATE(); } } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_MAINT_MESSAGE The "Press Ctrl-C for Maintenance menu to release disks" prompt, issued by ontap when ontap has already started but some disks have reservations asserted by the partner. The system is not fully ready for a giveback by its partner at this stage. This is a transient state. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_MAINT_MESSAGE; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; $is_transient = 1; sub execute_before { $iftakenover = "wait" if $iftakenover eq "error"; NACL::Transit::StateDefinitions::TAKE_OVER::execute_before(); } sub STATE { if ( $iftakenover eq "takeback" ) { return [ 1, $host->irptchar() ]; } return NACL::Transit::StateDefinitions::TAKE_OVER::STATE(); } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_WAITING_ONTAP The "Waiting for giveback" prompt, issued by ontap when ontap has already started but some disks have reservations asserted by the partner. The system is ready for giveback by its partner at this stage. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_WAITING_ONTAP; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; sub STATE { if ( $iftakenover eq "takeback" ) { return [ 1, $host->irptchar() ]; } else { return NACL::Transit::StateDefinitions::TAKE_OVER::STATE(); } } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_QUERY A "Do you wish to halt this node rather than wait [y/n]?" prompt, issued when this node was previously taken over and partner is detected as alive. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_QUERY; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; sub STATE { if ( $iftakenover eq "takeback" ) { return [ 1, "" ]; } else { return NACL::Transit::StateDefinitions::TAKE_OVER::STATE(); } } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_DEAD A "YOUR FILESYSTEMS MAY BE DESTROYED ... do you wish to continue [y/n]?" prompt which asks if you wish to take back the filesystem when the partner has taken over but seems to be dead. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_DEAD; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; sub STATE { if ( $iftakenover eq "takeback" ) { return [ 1, "y\r" ]; } else { return NACL::Transit::StateDefinitions::TAKE_OVER::STATE(); } } ################################################################################ =head2 NACL::Transit::StateDefinitions::MAINT_RELEASE_DISKS_QUERY confirmation prompt from "storage release disks" in maintainance mode =cut package NACL::Transit::StateDefinitions::MAINT_RELEASE_DISKS_QUERY; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { [ 0, "yes\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::USERNAME the login: prompt that an appliance may present when booting is complete but before the CLI prompt may be reached =cut package NACL::Transit::StateDefinitions::USERNAME; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { #as per burt#964249, On few testbeds USERNAME (ONTAP state) can directly reach to a NONONTAP state [ 1, "$username\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::PASSWORD the Password: prompt that an appliance may present when booting is complete but before the CLI prompt may be reached =cut package NACL::Transit::StateDefinitions::PASSWORD; use base qw/NACL::Transit::StateDefinitions::UP/; sub STATE { #as per burt#957400, On few testbeds PASSWORD (ONTAP state) can directly reach to a NONONTAP state [ 1, "$password\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::HALTED this is an intermediate state for clusterd ontap. It prints "The operating system has halted. Please press any key to reboot." when the system is halted (not when rebooted), after which the boot loader is loaded. =cut package NACL::Transit::StateDefinitions::HALTED; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { [ 1, " " ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::RESTORE_SYSTEM_CONFIG_QUERY A "Are you sure you want to continue?" question before replacing all boot-card-based configuration with the last disk backup. =cut package NACL::Transit::StateDefinitions::RESTORE_SYSTEM_CONFIG_QUERY; use base qw/NACL::Transit::StateDefinitions::ONTAP/; sub STATE { [ 0, "no\r" ]; } sub UP_OR_TAKEN_OVER { [ 1, "yes\r" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::ZERO_DISKS booted into zeroing disks mode, i.e. the state just after option "4" from the BOOT_MENU and answering yes to both of the "are you sure?" questions. This state is transient. =cut package NACL::Transit::StateDefinitions::ZERO_DISKS; use base qw/NACL::Transit::StateDefinitions::DISK_ZERO/; $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::CTRL_C the "Press CTRL-C for special boot menu" or equivalent message which appears as ontap is booted on anything other than a 7G simulator. This state is transient =cut package NACL::Transit::StateDefinitions::CTRL_C; use base qw/NACL::Transit::StateDefinitions::ONTAP/; $is_transient = 1; sub execute_before { sleep(1); } sub UP_OR_TAKEN_OVER { [ 0, "" ]; } sub CLI { [ 1, "" ]; } sub BOOT_MENU { [ 1, $host->irptchar() ]; } sub STATE { [ 0, $host->irptchar() ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::SIMLOADER_BANNER the "Hit [Enter] to boot immediately, or any other key for command prompt." message which appears as a vsim simulator resets. This state is transient =cut package NACL::Transit::StateDefinitions::SIMLOADER_BANNER; use base qw/NACL::Transit::StateDefinitions::BANNER/; sub WIPE_CONFIG { [ 1, ""]; } $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::OFW_BANNER the "Open Firmware by FirmWorks" message which appears as Open FirmWare appliances reset. This state is transient. =cut package NACL::Transit::StateDefinitions::OFW_BANNER; use base qw/NACL::Transit::StateDefinitions::BANNER/; $is_transient = 1; sub FIRMWARE { [ 0, "\c?" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::CFE_BANNER the "CFE version x.x.x based on Broadcom CFE" message which appears as CFE applicances reset. This state is transient. =cut package NACL::Transit::StateDefinitions::CFE_BANNER; use base qw/NACL::Transit::StateDefinitions::BANNER/; $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::LOADER_BANNER the "Boot Loader version x.x" message which appears as boot loader applicances reset. This state is transient. =cut package NACL::Transit::StateDefinitions::LOADER_BANNER; use base qw/NACL::Transit::StateDefinitions::BANNER/; $is_transient = 1; sub WIPE_CONFIG { [ 0, ""]; } sub FIRMWARE { [ 0, "" ]; } sub BOOT_MENU { [ 1, "" ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::LOADER_ABORT_AUTOBOOT the "Starting AUTOBOOT press Ctrl-C to abort" message which appears as boot loader applicances prepare to boot. This state is transient =cut package NACL::Transit::StateDefinitions::LOADER_ABORT_AUTOBOOT; use base qw/NACL::Transit::StateDefinitions::BANNER/; $is_transient = 1; sub FIRMWARE { [ 0, "\cC" ]; } sub WIPE_CONFIG { [ 1, ""]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::TAKEN_OVER_TRANSIENT A "HALT: cluster partner has taken over" message which appears when the partner takes over unexpectedly while this node is already up. =cut package NACL::Transit::StateDefinitions::TAKEN_OVER_TRANSIENT; use base qw/NACL::Transit::StateDefinitions::TAKE_OVER/; $is_transient = 1; ################################################################################ =head2 NACL::Transit::StateDefinitions::SYSTEM_REBOOTING This state corresponds to message "NO LOGINS: System going down at" shown at the filer prompt. The message will be shown when someone try to login to the system through console while it is rebooting/shuting down =cut package NACL::Transit::StateDefinitions::SYSTEM_REBOOTING; use base qw/NACL::Transit::StateDefinitions::ONTAP/; $is_transient = 1; sub STATE { [ 1, ""]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::PANIC this is an intermediate state for clusterd ontap. It prints "Panic occurred at:" =cut package NACL::Transit::StateDefinitions::PANIC; use base qw/NACL::Transit::StateDefinitions::ONTAP/; $is_transient = 1; # Exceptions use NACL::Transit::Exceptions::TransitException qw/:try/; use NATE::Exceptions::Argument qw/:try/; # sub execute_before { if ( $ifpanic eq "error" ) { alarm 0; NACL::Transit::Exceptions::TransitException->throw( "panic occured during state changes."); } elsif ( $ifpanic eq "pass" ) { } else { alarm 0; NATE::Exceptions::Argument->throw( "unknown value '$ifpanic' for ifpanic option"); } } sub STATE { [ 1, " " ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::DUMPCORE_START This state is reached when filer paniced and about to start core dump. It prints "DUMPCORE: START". Currently you can not use change_state method to reach to this state. =cut package NACL::Transit::StateDefinitions::DUMPCORE_START; use base qw/NACL::Transit::StateDefinitions::STATE/; $is_transient = 1; sub STATE { [ 1, " " ]; } ################################################################################ =head2 NACL::Transit::StateDefinitions::DUMPCORE_END This state is reached when filer paniced and finished dumping core. It prints "DUMPCORE: END". Currently you can not use change_state method to reach to this state. =cut package NACL::Transit::StateDefinitions::DUMPCORE_END; use base qw/NACL::Transit::StateDefinitions::STATE/; $is_transient = 1; sub STATE { [ 1, " " ]; } ################################################################################ package NACL::Transit::StateDefinitions; use Class::ISA; use Tharn; use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use NATE::Util qw(derefarray); use NACL::Transit::Exceptions::Internal qw/:try/; use Tie::IxHash (); use strict; use warnings; # This subroutine is used for constructing a hash keyed by regex and having the # state names as values sub make_prompt_hash { my $self = shift; my $host = $self->{conn}->hostp(); my $hosttype = $host->hosttype(); # the hashes that hold the Prompt => State mapping my %hash; my $ixhash = tie(%hash,"Tie::IxHash"); my %transient_prompt_hash; my $transient_prompt_ixhash = tie(%transient_prompt_hash,"Tie::IxHash"); # Fill firmware prompts first, because some firmware prompts # (e.g. LOADER>) also look like normal/CLI prompts, but should be # counted as firmware. my @fwprompts; if ( $hosttype =~ /vsim/ ) { @fwprompts = ('^\r*SIMLOADER> ', '^\r*VLOADER> '); } elsif ( $hosttype =~ /vsa/ ) { @fwprompts = ('^\r*VSALOADER> ', '^\r*VLOADER> '); } elsif ( $hosttype =~ /sdot/ ) { @fwprompts = ('^\r*VLOADER> '); } elsif ( $hosttype =~ /ng|cfe/ ) { @fwprompts = ( '^\r*CFE> ', '^\r*LOADER(?:-\\w+)?\\*?> ' ); } elsif ( $hosttype =~ /simulator/ ) { @fwprompts = derefarray( $host->prompt_fw() ); } foreach my $re (@fwprompts) { $hash{$re} = 'FIRMWARE'; } # As part of fix for burt572357 prompt for SP state should # come before CLI state in prompt hash. foreach my $re ( derefarray( $host->prompt_norm(), $host->prompt_take(), $host->prompt_virt() ) ) { $hash{'^\r*SP\s'.$re} = 'SP'; } $hash{'^\r*SP(\s'.'\S+)?>\s'} = 'SP'; foreach my $re ( derefarray( $host->prompt_system(), $host->prompt_take(), $host->prompt_virt() ) ) { $hash{$re} = 'CLI'; } $hash{'^\r*::(?:\\*?)>\\s'} = 'CLI'; # New CLI prompt regex to handle the cluster prompt along with nodescope # and systemshell # Can be removed if it is populated in prompt_norm of the hostrec # For now its not present there - see burts 456674 and 460433 # Regex modified to handle the LOADER prompt on Absolut - burt 464507 $hash{'^\r*\S+(::[^>#%\n]*|-\d+)\*?[>#%]\s'} = 'CLI'; $hash{'^\r*#\s$'} = 'SP_ROOT'; $hash{'Service Processor Login:\s'} = 'SP_LOGIN'; $hash{"Selection \\(1-\\d\\)\\?"} = 'BOOT_MENU'; $hash{"Please make a selection:"} = 'BOOT_MENU'; $hash{"Please choose a selection"} = 'BOOT_MENU'; # added from NG/Transit.pm $hash{"Please choose one of the following:"} = 'BOOT_MENU'; # added from NG/Transit.pm $hash{"^\r*>"} = 'NORC'; $hash{"Zero disks and install a new file system\\? "} = 'ZERO_DISKS_QUERY'; $hash{"Install a new file system\\? "} = 'ZERO_DISKS_QUERY'; $hash{"Zero disks, reset config and install a new file system\\?: "} = 'ZERO_DISKS_QUERY'; $hash{"This will erase all the data on the disks, are you sure\\?"} = 'ZERO_DISKS_QUERY'; $hash{"^\r*\\*> "} = 'MAINT'; $hash{"Continue with boot\\? "} = 'NONSTD_BOOT_QUERY'; $hash{"(?s:Hit \\^C to abort.*Waiting for giveback\\.\\.\\.)"} = 'TAKEN_OVER_WAITING_OFW'; $hash{"Waiting for giveback\\.\\.\\.\\(Press Ctrl-C to abort wait\\)"} = 'TAKEN_OVER_WAITING_ONTAP'; $hash{"Waiting for giveback"} = 'TAKEN_OVER_WAITING_ONTAP'; $hash{"Do you wish to halt this node rather than wait \\[y/n\\]\\? "} = 'TAKEN_OVER_QUERY'; $hash{ "(?s:YOUR FILESYSTEMS MAY BE DESTROYED.*Do you wish to continue \\[y/n\\]\\? )" } = 'TAKEN_OVER_DEAD'; $hash{ "(?s:This command will release all disk reservations.*Do you wish to continue\\? )" } = 'MAINT_RELEASE_DISKS_QUERY'; $hash{'login:\s+$'} = 'USERNAME'; $hash{'Password:\s?'} = 'PASSWORD'; $hash{'diag@127.0.0.1\'s password:\s?'} = 'PASSWORD'; $hash{'diag@localhost\'s password:\s?'} = 'PASSWORD'; $hash{ "The operating system has halted\\.\\s*Please press any key to reboot\\." } = 'HALTED'; $hash{"This will replace all flash-based configuration with the last backup to\r\ndisks\\. Are you sure you want to continue\\?"} = 'RESTORE_SYSTEM_CONFIG_QUERY'; $hash{'Panic\s+occurred\s+at:'} = 'PANIC'; $hash{'Panic\s+in\s+process:'} = 'PANIC'; $hash{'PANIC\s*:'} = 'PANIC'; $hash{'panic\(\)\s+at\s+panic'} = 'PANIC'; # 7Mode $hash{"Do you want to login to the systemshell as the \'diag\' user\\?"} = 'LOGIN_TO_SYSTEMSHELL_QUERY'; $hash{"Are you sure you want to (reboot|halt) node*{y|n}"} = 'HALT_REBOOT_QUERY'; $hash{"Do you want to continue\\?*{y|n}"} = 'HALT_REBOOT_QUERY'; $transient_prompt_hash{'DUMPCORE\s*:\s+START'} = 'DUMPCORE_START'; $transient_prompt_hash{'DUMPCORE\s*:\s+END'} = 'DUMPCORE_END'; $transient_prompt_hash{"Rebooting to finish wipeconfig request\\."} = 'WIPE_CONFIG_QUERY'; $transient_prompt_hash{"Press Ctrl-C for Maintenance menu to release disks"} = 'TAKEN_OVER_MAINT_MESSAGE'; $transient_prompt_hash{"Press CTRL-C for (?:special|floppy) boot menu"} = 'CTRL_C'; # (7G) $transient_prompt_hash{ "(?s:Press Ctrl-C for Boot Menu.*" . ( "\\*" x 31 ) . ")" } = 'CTRL_C'; # (converged ontap) $transient_prompt_hash{ "Firmware version \\d+ has been successfully downloaded on to the \\S+ card. The system will automatically reboot now." } = 'NVRAM_FW_UPDATE'; $transient_prompt_hash{ "Updating nvram firmware, battery is (?:off|on). The system will automatically reboot when the update is complete." } = 'NVRAM_FW_UPDATE'; if ( $hosttype =~ /(vsim|vsa|sdot)/ ) { $transient_prompt_hash{ "Hit \\[Enter\\] to boot immediately, or any other key for command prompt." } = 'SIMLOADER_BANNER'; } elsif ( $hosttype =~ /^(filer|cache)$/ ) { $transient_prompt_hash{"Open Firmware by FirmWorks"} = 'OFW_BANNER'; } elsif ( $hosttype =~ /cfe|ng/ ) { $transient_prompt_hash{"CFE version \\d+\\.\\d+\\.\\d+ based on Broadcom CFE"} = 'CFE_BANNER'; $transient_prompt_hash{"Boot Loader version \\d+\\.\\w+"} = 'LOADER_BANNER'; $transient_prompt_hash{"Starting AUTOBOOT press Ctrl-C to abort"} = 'LOADER_ABORT_AUTOBOOT'; } $transient_prompt_hash{"HALT: cluster partner has taken over"} = 'TAKEN_OVER_TRANSIENT'; $transient_prompt_hash{"NO LOGINS: System going down at"} = 'SYSTEM_REBOOTING'; $transient_prompt_hash{"REBOOTING TO LOAD NEW NVRAM FIRMWARE"} = 'REBOOTING_TO_LOAD_NEW_NVRAM_FIRMWARE'; $self->{prompt_hash} = \%hash; $self->{transient_prompt_hash} = \%transient_prompt_hash; } =head1 Methods =head2 NACL::Transit::StateDefinitions::next_message This method is used to obtain the next action ( a stream of characters ) that have to be sent over the connection to get to the desired destination state. This information is obtained by next_message when it calls the subroutine bearing the name of the destination state (or its type) in the package that represents the current state. This is called internally from the package C =over =item Synopsis $obj->next_message(%args) =item Returns An array that contains alternate boolean and string values. The strings represent the character sequences that have to be sent over the connection to change to another state. If true, the boolean value indicates that the immediate next state reached from the current state can be ONTAP / non ONTAP. If false, then the boolean value indicates that the immediate next state reached from the current state has to be either ONTAP / non ONTAP depending on whether the current state was ONTAP / non ONTAP. =back =cut sub next_message { my ($self, %args) = @_; $from = $args{from}; $to = $args{to}; if ( $from eq $to ) { return ( 0, "" ); } $regex = $args{regex}; $conn = $self->{conn}; $host = $self->{conn}->hostp(); $username = defined( $args{username} ) ? $args{username} : $self->{username}; $password = defined( $args{password} ) ? $args{password} : $self->{password}; $haltcmd = defined( $args{haltcmd} ) ? $args{haltcmd}.' ' : $self->{haltcmd}; my $inhibit_takeover = defined( $args{'inhibit_takeover'} ) ? $args{'inhibit_takeover'} : $self->{'inhibit_takeover'}; $iftakenover = defined( $args{iftakenover} ) ? $args{iftakenover} : $self->{iftakenover}; $ifpanic = defined( $args{ifpanic} ) ? $args{ifpanic} : $self->{ifpanic}; $diag_password = defined $args{prompt_password} ? $args{prompt_password} : $self->{prompt_password}; $restore_system_config = defined $args{restore_system_config} ? $args{restore_system_config} : $self->{restore_system_config}; if ($inhibit_takeover == 0) { $haltcmd = "halt"; } # the default haltcmd is "halt -f". # If any other haltcmd is present, then it will contain a space in the end # In such cases, for the CLI state in CMode, we will not prefix: # "system node" and suffix: "-ignore-quorum-warnings -node local" # If the user overrides this for any reason, then we take the command as is if ( $from eq 'CLI' && $host->hosttype() =~ /filer-ng/ ) { use NATE::ParamSet qw( param_global); use NACL::C::Node; #global param SET_SDOT_REBOOT & IS_SDOT are used so that each time #it does not executes same set of command and times-out. my $ci = NACL::C::Node->new(name => $host->hostname()); if( (! param_global->get('SET_SDOT_REBOOT'))) { if ( $haltcmd =~ /halt/ && $host->hosttype() =~ /filer-ng-sdot/ ) { param_global->set( key => 'SET_SDOT_REBOOT', value => '1' ); my $autoboot_val = $ci->get_7m_or_nodescope_apiset()->bootargs_get( arg => 'bootarg.vm.no_poweroff_on_halt')->get_raw_output(); if ( $autoboot_val !~ /bootarg.vm.no_poweroff_on_halt == true/i){ $haltcmd = "system node reboot -node local"; } } } if($haltcmd eq 'halt -f -t 0' || $haltcmd eq 'halt -t 0' || $haltcmd eq 'halt -f' || $haltcmd eq 'halt'){ #as per burt#607399, use the cluster shell command for rebooting or #halting a node instead of the node scope command #remove "-t 0" from haltcmd as cluster shell command doesn't #accept this option $haltcmd =~ s/ -t 0//g; $haltcmd = "system node $haltcmd -ignore-quorum-warnings -skip-lif-migration-before-shutdown -node local"; } } my $actual_from = $from; $from = 'NACL::Transit::StateDefinitions::' . $from; NACL::Transit::Exceptions::Internal->throw( "$actual_from is an unknown boot state - package probably not " . "defined" ) unless $from->isa('NACL::Transit::StateDefinitions::STATE'); if ( $from->can('execute_before') ) { $from->execute_before; } my @super_classes = Class::ISA::super_path( 'NACL::Transit::StateDefinitions::' . $to ); map { $_ =~ s/NACL::Transit::StateDefinitions::// } @super_classes; foreach ( $to, @super_classes ) { if ( $from->can("$_") ) { return @{ $from->$_() }; } } # this error is thrown when no mapping is defined from $from to $to or any # super class of $to NACL::Transit::Exceptions::Internal->throw( "Internal error in StateDefinitions: Don't " . "know how to transit from $actual_from to $to" ); } 1;