#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/bin/cdat/cdat-discover-nodes.pl 1.8 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,2011 # 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 # @(#)24 1.8 src/bos/usr/bin/cdat/cdat-discover-nodes.pl, cdat, bos720 7/15/11 04:33:13 use warnings; use strict; use Getopt::Long; use File::Copy; use cdat; use messages; # # Constants. # # This is the command that is run on HMC or IVM to list LPARs. use constant DISCOVER_LPARS_CMD => '(lssyscfg -r sys -F name |'. 'while read system; do '. 'lssyscfg -r lpar -m $system -F lpar_env,name |'. 'while read lpar; do '. 'echo "$lpar" | grep -q -e ^aixlinux -e ^vioserver && '. 'echo "$system,$lpar" || '. 'echo "$system,error,$lpar";'. 'done;'. 'done) 2>&1'; # This is the command that is run on LPARs to list WPARs. use constant DISCOVER_WPARS_CMD => '/usr/sbin/lswpar -cq -a Hostname | /usr/bin/sort'; # # Globals. # my @file = (); ###################################################################### # Function: usage # Purpose: Display usage. # Tasks: Print usage and exit. # Input: None # Output: None ###################################################################### sub usage { printf(STDERR catgets(MSG_CDAT_DISCOVER_USAGE, "Usage: cdat discover-nodes -h\n". " cdat discover-nodes [-a|-w] [-f File] -n Type:[User@]Node ...\n")); exit(1); } ###################################################################### # Function: discover_lpars # Purpose: Discover LPARs managed by a given host (HMC or IVM). # Tasks: Log onto the host and list the LPARs. # Update global array @file with the LPARs. # Input: Host (type, username, hostname) # Output: 0 on success, 1 otherwise ###################################################################### sub discover_lpars { my ($type, $user, $name) = @_; # Execute the discover command on the HMC/IVM. # NB: it may ask for a password. my @lines = cdat::remote_cmd($user, $name, DISCOVER_LPARS_CMD, $cdat::REMOTE_PROBE | $cdat::REMOTE_AUTO); my $status = $?; if ($status != 0 || !defined($lines[0])) { printf(STDERR catgets(MSG_CANNOT_DISCOVER_SKIP, "Cannot discover nodes from %s, skipping.\n"), $name); return 1; # skip this HMC/IVM } if ($type eq 'VIOS' && grep(/^\[VIOSE/, @lines)) { printf(STDERR catgets(MSG_CANNOT_DISCOVER_SKIP, "Cannot discover nodes from %s, skipping.\n"), $name); return 1; # skip this VIOS } if ($type eq 'HMC' && !grep(/^HMC:$name\n/, @file)) { # Add the HMC name itself push(@file, "HMC:$name\n"); } # Sort LPARs by managed system, type and name. Unfortunately, ioscli # does not have a 'sort' command (while HMCs have one) so we have to # sort things by ourselves. @lines = sort @lines; my $prev_system; foreach (@lines) { chomp; my ($system, $type, $name) = split(/,/, $_, 3); my $qualifier; # make sure we have all three fields next if (!defined($name)); if ($type eq "vioserver") { $qualifier = "VIOS:$name"; } elsif ($type eq "aixlinux") { $qualifier = "LPAR:$name"; } elsif ($type eq "error") { push(@file, "# Could not retrieve LPARs of managed system $system\n"); push(@file, "# $name\n"); next; } else { # skip unknown types next; } # Skip if node is already in the file next if (grep(/^$qualifier\n/, @file)); if (!defined($prev_system) || ($system ne $prev_system)) { push(@file, "# LPARs of managed system $system\n"); $prev_system = $system; } # Add node to the file push(@file, "$qualifier\n"); } return 0; } ###################################################################### # Function: discover_wpars # Purpose: Discover WPARs managed by a given LPAR. # Tasks: Log onto the host and list the WPARs. # Update global array @file with the WPARs. # Input: Host (type, username, hostname) # Output: None ###################################################################### sub discover_wpars { my ($type, $user, $name) = @_; # Execute the discover command on the LPAR. # NB: it may ask for a password. my @lines = cdat::remote_cmd($user, $name, DISCOVER_WPARS_CMD, $cdat::REMOTE_PROBE | $cdat::REMOTE_AUTO); my $status = $?; if ($status != 0 || !defined($lines[0])) { printf(STDERR catgets(MSG_CANNOT_DISCOVER_SKIP, "Cannot discover nodes from %s, skipping.\n"), $name); return 1; # skip this LPAR } if (!grep(/^LPAR:$name\n/, @file)) { # Add the LPAR name itself push(@file, "LPAR:$name\n"); } # NB: WPARs are already sorted by name my $hdr = 0; foreach (@lines) { chomp; my $wpar = $_; # Skip if WPAR is already in the file next if (grep(/^LPAR:$wpar\n/, @file)); if ($hdr == 0) { @file = (@file, "# WPARs of LPAR $name\n"); $hdr = 1; } # Add WPAR to the file push(@file, "LPAR:$wpar\n"); } return 0; } ###################################################################### # Function: main # Purpose: Entry point of the discover-nodes subcommand. # Tasks: Parse command line and call discover_nodes for each # specified node. # Input: None # Output: None ###################################################################### sub main { my ($rc, $filename, $overwrite, $append); my @rawnodes; # Parse command line options Getopt::Long::Configure('bundling', 'no_ignore_case'); $rc = GetOptions( 'h' => \&usage, 'n=s' => \@rawnodes, 'f=s' => \$filename, 'w' => \$overwrite, 'a' => \$append ); if (!$rc || @ARGV != 0) { usage(); } # check that -a and -w are not both defined if (defined($overwrite) && defined($append)) { usage(); } cdat::switch_user(); my %nodes = cdat::read_nodes_from_array(@rawnodes); if (!%nodes) { printf(STDERR catgets(MSG_NO_NODES_TO_CONNECT, "No nodes to connect to.\n")); exit(1); } if (!defined($filename)) { # no filename was specified, use default my $path = cdat::odm_get_path(); if (!defined($path)) { printf(STDERR catgets(MSG_DIR_NOT_DEFINED, "The cdat directory path is not defined.\n". "Please, run 'cdat init' first.\n")); exit(1); } $filename = "$path/nodes.txt"; } if ( -e $filename && ! -z _ ) { # # A file with that name already exists and is not empty, # decide what to do. # if (!defined($append) && !defined($overwrite)) { # neither -a nor -w were specified, ask user printf(catgets(MSG_FILE_ALREADY_EXISTS, "File %s already exists, replace it?"), $filename); if (cdat::yes_no(0)) { $overwrite = 1; } else { $append = 1; } } if (defined($append)) { # Read existing file content into memory $rc = open(FILE, "<$filename"); if (!$rc) { printf(STDERR catgets(MSG_CANNOT_OPEN_FOR_READING, "Cannot open %s for reading.\n"), $filename); exit(1); } @file = ; close(FILE); } else { # Make a copy of existing file and remove original $rc = move("$filename", "$filename.bak"); if (!$rc) { printf(STDERR catgets(MSG_CANNOT_BACKUP, "Cannot backup %s.\n"), $filename); exit(1); } } } # Discover nodes managed by each specified host my $status = 0; while (my ($name, $node) = each(%nodes)) { my $type = $node->{type}; # We can only discover nodes from HMCs, IVMs or LPARs for now. if ($type ne 'HMC' && $type ne 'VIOS' && $type ne 'LPAR') { printf(STDERR catgets(MSG_SKIPPING_NODE, "Unsupported node type %s, skipping %s.\n"), $type, $name); next; } my $user; if (!defined($node->{user})) { # Choose default user if ($type eq 'HMC') { $user = 'hscroot'; } elsif ($type eq 'VIOS') { $user = 'padmin'; } else { # LPAR $user = 'root'; } } else { $user = $node->{user}; } printf(catgets(MSG_DISCOVERING_NODES, "Discovering nodes managed by %s@%s...\n"), $user, $name); my $ret = 0; if ($type eq 'HMC' || $type eq 'VIOS') { $ret = discover_lpars($type, $user, $name); } else { # LPAR $ret = discover_wpars($type, $user, $name); } if ($ret == 0) { printf(catgets(MSG_DONE, "Done.\n")); } else { $status = 2; } } $rc = open(FILE, ">$filename"); if (!$rc) { printf(STDERR catgets(MSG_CANNOT_OPEN_FOR_WRITING, "Cannot open %s for writing.\n"), $filename); exit(3); } print(FILE @file); close(FILE); exit($status); } main;