#! /usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2009,2019 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG use IO::Socket; use Getopt::Long; my $prompt = "=== terminal input mode (q|quit|<[file]|{|}|value )"; my $adapter, $node, $process, $no_template, $help; if (!GetOptions("adapter" => \$adapter, "node" => \$node, "process" => \$process, "reconfig" => \$reconfig, "no_template" => \$no_template, "help" => \$help)) { usage(1); } # # Only one predefined template can be loaded. # if ($adapter + $node + $process + $reconfig > 1) { usage(1); } my $path; if ($adapter) { $path = "/tmp/Cluster/{adapter_events"; } elsif ($node) { $path = "/tmp/Cluster/{node_events"; } elsif ($process) { $path = "/tmp/Cluster/{process_events"; } elsif ($reconfig) { $path = "/tmp/Cluster/{reconfig_events"; } else { # # At least one predefined template must be specified. # usage(1); } # # Ready the directory that contains the socket file. # system("mkdir -p /tmp/Cluster 1>/dev/null 2>/dev/null"); # # Start with a clean socket file situation. # remove_socket_file(); # # Cleanup socket file on Ctrl-C. # $SIG{INT} = \&cleanup; STDOUT->autoflush(1); # # Create the unix domain sockets for the specified path. # my $socket; $socket = new IO::Socket::UNIX(Local => $path, Listen => 1, Reuse => 1) or die sprintf("%d: couldn't create the socket", __LINE__); $socket->autoflush(1); # # Wait for a client on the socket. # my $client; my $broken_pipe; accept_client(); $broken_pipe = 0; # # Trap the SIGPIPE signal delivered to the process when attempting to write to # a broken pipe. # $SIG{PIPE} = \&accept_client; my @template; if (!$no_template) { push @template, "BEGIN_EVENT_INFO"; push @template, "RC_FROM_EVPROD=0"; push @template, "SEQUENCE_NUM=0"; push @template, "TIME_tvsec=1244830365"; push @template, "TIME_tvnsec=637528480"; push @template, "PID=360544"; push @template, "UID=0"; push @template, "UID_LOGIN=0"; push @template, "GID=0"; push @template, "PROG_NAME=ahafs_sim_multi"; push @template, "BEGIN_EVPROD_INFO"; if ($adapter) { push @template, "EVENT_TYPE=ADAPTER_%s"; push @template, "NODE_NUMBER=%s"; push @template, "NODE_ID=%s"; push @template, "INTERFACE_NAME=%s"; } elsif ($node) { push @template, "EVENT_TYPE=NODE_%s"; push @template, "NODE_NUMBER=%s"; push @template, "NODE_ID=%s"; } elsif ($process) { push @template, "EVENT_TYPE=PROCESS_%s"; push @template, "NODE_NUMBER=%s"; push @template, "NODE_ID=%s"; push @template, "SEQUENCE_NUMBER=%s"; push @template, "COMMAND_NAME=%s"; } elsif ($reconfig) { push @template, "EVENT_TYPE=CLUSTER_RECONFIG"; push @template, "SEQUENCE_NUMBER=%s"; push @template, "REASON_CODE=%s"; } push @template, "END_EVPROD_INFO"; push @template, "END_EVENT_INFO"; } # # Read commands form STDIN. # while () { chomp; if (/^\s*#/) { next; } elsif (/{/) { @template = (); while () { chomp; if (/^\s*#/) { next; } elsif (/}/) { last; } push(@template, $_); } } elsif (/^quit/ || /^q$/) { last; } elsif (/^accept(); print "client has connected\n"; # # Verify the client is requesting the right stuff. # my $expected_request = "CHANGED=YES;CLUSTER=YES"; if ($client) { my $actual_request = <$client>; chomp $actual_request; if ($actual_request ne $expected_request) { print "ERROR: client: expected_request($expected_request) actual_request($actual_request)\n"; exit 1; } } # # Say pipe is broken. Caller can override as necessary. # $broken_pipe = 1; } sub remove_socket_file { if ($path) { system("rm -f $path 1>/dev/null 2>/dev/null"); } } sub cleanup { if ($client) { $client->shutdown(2); $client->close(); } remove_socket_file(); exit(0); } # For input we still keep the sequence number, reason number # but in writing to socket don't write them since the input # code is also used for process event,reconfiguration event # But for node event and adapter event they have no sequence # number or reason code in parsing any more. sub usage { print STDERR <<"USAGE"; Usage: ahafs_sim --adapter | --node | --process | --reconfig [--no_template] [--help] where: --adapter - pre-loads the adapter liveness template --node - pre-loads the node liveness template --process - pre-loads the process liveness template --reconfig - pre-loads the cluster reconfiguration template --no_template - permits socket file association per the selected template, but doesn't actually load the template If the options are accepted, ahafs_sim waits until a client connects to the unix domain socket associated with a given liveness template type, after which it goes into command mode, reading commands from standard input. Acceptable commands include: # - comment if first character in line { - begin template definition (must appear alone on line) } - end template definition (must appear alone on line) < - begin terminal input mode ./ahafs_sim --node $prompt UP 1 2 3 4 A client would receive the following: BEGIN_EVENT_INFO RC_FROM_EVPROD=0 SEQUENCE_NUM=0 TIME_tvsec=1244830365 TIME_tvnsec=637528480 PID=360544 UID=0 UID_LOGIN=0 GID=0 PROG_NAME= BEGIN_EVPROD_INFO EVENT_TYPE=NODE_UP NODE_NUMBER=1 NODE_ID=2 SEQUENCE_NUMBER=3 REASON_CODE=4 END_EVPROD_INFO END_EVENT_INFO 2) Begin a node simulator whose template definition is supplied manually. Commands are input from the terminal. > ./ahafs_sim --node --no_template $prompt { BEGIN_EVENT_INFO RC_FROM_EVPROD=0 SEQUENCE_NUM=0 TIME_tvsec=1244830365 TIME_tvnsec=637528480 PID=360544 UID=0 UID_LOGIN=0 GID=0 PROG_NAME= BEGIN_EVPROD_INFO EVENT_TYPE=NODE_%s NODE_NUMBER=%s NODE_ID=%s SEQUENCE_NUMBER=%s REASON_CODE=%s END_EVPROD_INFO END_EVENT_INFO } UP 1 2 3 4 A client would receive the following: BEGIN_EVENT_INFO RC_FROM_EVPROD=0 SEQUENCE_NUM=0 TIME_tvsec=1244830365 TIME_tvnsec=637528480 PID=360544 UID=0 UID_LOGIN=0 GID=0 PROG_NAME= BEGIN_EVPROD_INFO EVENT_TYPE = NODE_UP NODE_NUMBER=1 NODE_ID=2 SEQUENCE_NUMBER=3 REASON_CODE=4 END_EVPROD_INFO END_EVENT_INFO 3) Begin an adapter simulator whose commands are input from a file. > ./ahafs_sim --adapter