#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/bin/cdat/cdat-show.pl 1.6 # # 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 # @(#)27 1.6 src/bos/usr/bin/cdat/cdat-show.pl, cdat, bos720 7/15/11 05:38:04 use strict; use warnings; use Getopt::Long; use Fcntl ':flock'; # LOCK_* constants use XML::LibXML; use cdat; use messages; # # Constants. # my $XMLFILE = 'cdat.xml'; # # Globals. # my $path; my @collects; # Default verbosity level is set to 0 my $verbose = 0; ###################################################################### # Function: usage # Purpose: Display usage. # Tasks: Print usage and exit. # Input: None # Output: None ###################################################################### sub usage { printf(STDERR catgets(MSG_CDAT_SHOW_USAGE, "Usage: cdat show -h\n". " cdat show [-v]\n". " cdat show [-v] Id\n". " cdat show [-v] -p PMR\n". " cdat show [-v] -n [Host]\n")); exit(1); } ###################################################################### # Function: show_id # Purpose: Show collect information for the specified collect id # or for all collects. # Tasks: Display collects information. # Input: list of collect XML elements, collect id or undef to # show all collects # Output: None ###################################################################### sub show_id { my ($id) = @_; if (defined($id)) { # a collect id is specified, find it... my $found = 0; foreach my $collect (@collects) { my $attr = $collect->getAttribute('id'); if (defined($attr) && $id eq $attr) { # ... and display it. print_collect($collect); $found = 1; last; # there can be only 1 collect with that id } } if (!$found) { printf(catgets(MSG_NO_COLLECT_FOUND_FOR_ID, "No collect found for id %s.\n"), $id); } } else { # no collect id is specified, display all collects foreach my $collect (@collects) { print_collect($collect); } } } ###################################################################### # Function: show_pmr # Purpose: Show collects information for the specified PMR. # Tasks: Search for collects with the specified PMR number and # display them. # Input: list of collect elements, PMR number # Output: None ###################################################################### sub show_pmr { my ($pmr) = @_; my $found = 0; foreach my $collect (@collects) { my @pmrs = $collect->getElementsByTagName('pmr'); next if (@pmrs == 0); # no pmr tag for this collect, skip # retrieve value of first pmr tag my $val = $pmrs[0]->textContent; # skip if it does not match specified PMR number next if ($pmr ne $val); print_collect($collect); $found = 1; # NB: there can be several collects for a given PMR } if (!$found) { printf(catgets(MSG_NO_COLLECT_FOUND_FOR_PMR, "No collect found for PMR %s.\n"), $pmr); } } ###################################################################### # Function: show_node # Purpose: Show collects information for a specified node or for # all nodes. # Tasks: Display collects information. # Input: list of collect XML elements, node name or "" for all # nodes. # Output: None ###################################################################### sub show_node { my ($name) = @_; # ignore -v option with -n $verbose = 0; # get the list of collects per node (NB: $name can be '') my %list = get_collects_for_node($name); # display results while (my ($hostname, $collects) = each(%list)) { print("$hostname:\n\n"); foreach my $collect (@$collects) { print_collect($collect); } } } ###################################################################### # Function: get_nodes # Purpose: Retrieve the list of node XML elements for a given # XML file. # Tasks: Parse XML file and retrieve all node elements. # Input: XML filename # Output: Array of node XML elements ###################################################################### sub get_nodes { my ($filename) = @_; my @nodes = (); my $parser = XML::LibXML->new(); return @nodes if (!defined($parser)); my $tree = $parser->parse_file($filename); return @nodes if (!defined($tree)); my $root = $tree->getDocumentElement; return @nodes if (!defined($root)); @nodes = $root->getElementsByTagName('node'); return @nodes; } ###################################################################### # Function: get_collects_for_node # Purpose: Retrieve per-node XML collect elements # Tasks: Parse XML files and build a hash of node to XML # collect elements. # Input: node name or '' for all nodes. # Output: Hash of (node => array of XML collect elements) ###################################################################### sub get_collects_for_node { my ($name) = @_; my %list; foreach my $collect (@collects) { # retrieve sub-directory of the collect my @locations = $collect->getElementsByTagName('location'); next if (@locations == 0); # should not happen my $location = $locations[0]->textContent; # retrieve the list of nodes from the XML file my @nodes = get_nodes("$path/$location/collect.xml"); foreach my $node (@nodes) { my $hostname = $node->getAttribute('hostname'); next if (!defined($hostname)); # should not happen # skip nodes that do not match query next if ($name ne '' && $name ne $hostname); if (!defined($list{$hostname})) { $list{$hostname} = [ $collect ]; } else { push(@{ $list{$hostname} }, $collect); } } } return %list; } ###################################################################### # Function: print_node # Purpose: Display information about a node. # Tasks: Display information about a node (name, machine id...) # Input: node XML element # Output: None ###################################################################### sub print_node { my ($node) = @_; my $hostname = $node->getAttribute('hostname'); return if (!defined($hostname)); # should not happen print("\n $hostname:\n"); my @types = $node->getElementsByTagName('node-type'); if (@types != 0) { printf("\t%-11s: %s\n", catgets(MSG_TYPE, "type"), $types[0]->textContent); } my @users = $node->getElementsByTagName('user'); if (@users != 0) { printf("\t%-11s: %s\n", catgets(MSG_USER, "user"), $users[0]->textContent); } my @machine_ids = $node->getElementsByTagName('machine_id'); if (@machine_ids != 0) { printf("\t%-11s: %s\n", catgets(MSG_MACHINE_ID, "machine id"), $machine_ids[0]->textContent); } my @lpar_ids = $node->getElementsByTagName('lpar_id'); if (@lpar_ids != 0) { printf("\t%-11s: %s\n", catgets(MSG_LPAR_ID, "lpar id"), $lpar_ids[0]->textContent); } my @timezones = $node->getElementsByTagName('timezone'); if (@timezones != 0) { printf("\t%-11s: %s\n", catgets(MSG_TIMEZONE, "timezone"), $timezones[0]->textContent); } } ###################################################################### # Function: print_collect # Purpose: Display information about a collect. # Tasks: Display information about a collect and about the # nodes this collect was run on if verbosity is > 0. # Input: collect XML element # Output: None ###################################################################### sub print_collect { my ($collect) = @_; my $id = $collect->getAttribute('id'); return if (!defined($id)); # should not happen print("$id:"); my @dates = $collect->getElementsByTagName('date'); if (@dates) { print(" " . $dates[0]->textContent); } print("\n\n"); my @descriptions = $collect->getElementsByTagName('description'); if (@descriptions) { my $descr = $descriptions[0]->textContent; print(" $descr\n"); } my @pmrs = $collect->getElementsByTagName('pmr'); if (@pmrs) { printf(catgets(MSG_PMR, " PMR: %s\n"), $pmrs[0]->textContent); } my @locations = $collect->getElementsByTagName('location'); my $location; if (@locations) { $location = $locations[0]->textContent; printf(catgets(MSG_LOCATION, " Location: %s\n"), "$path/$location"); } if ($verbose != 0 && defined($location)) { my @nodes = get_nodes("$path/$location/collect.xml"); foreach my $node (@nodes) { print_node($node); } } print("\n"); } ###################################################################### # Function: main # Purpose: Entry point of the show subcommand. # Tasks: Parse command line and print collects matching query. # Input: None # Output: None ###################################################################### sub main { my ($rc, $pmr, $node, $id); # Parse command line options Getopt::Long::Configure('bundling', 'no_ignore_case'); $rc = GetOptions( 'h' => \&usage, 'v+' => \$verbose, 'p=s' => \$pmr, 'n:s' => \$node ); if (!$rc) { usage(); } if (!defined($pmr) && !defined($node)) { # neither -p nor -n is specified, check if a collectid is specified if (@ARGV > 0) { $id = shift @ARGV; } } # make sure there are no extra arguments usage if (@ARGV != 0); # validate PMR number if (defined($pmr) && !($pmr =~ m/\d{5,}(,[0-9A-Za-z]{3,}){2}/)) { printf(STDERR catgets(MSG_INVALID_PMR, "Invalid PMR '%s', format should be 'PMR#,BRANCH#,COUNTRY#'.\n"), $pmr); exit(1); } $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(2); } cdat::switch_user(); my $fh; if (!open($fh, "<", "$path/$XMLFILE")) { printf(STDERR catgets(MSG_CANNOT_OPEN, "Cannot open %s.\n"), "$path/$XMLFILE"); exit(2); } # Try to acquire read-only access to the XML file (but do not block) if (!flock($fh, LOCK_SH | LOCK_NB)) { printf(STDERR catgets(MSG_BUSY, "Another instance of the cdat command is running.\n". "Please wait until this instance terminates.\n")); exit(2); } my $parser = XML::LibXML->new(); if (!defined($parser)) { printf(STDERR catgets(MSG_CANNOT_CREATE_XML_PARSER, "Cannot create XML parser.\n")); exit(2); } my $tree = $parser->parse_fh($fh); if (!defined($tree)) { printf(STDERR catgets(MSG_CANNOT_PARSE, "Cannot parse %s.\n"), "$path/$XMLFILE"); exit(2); } printf(catgets(MSG_REPOSITORY , "Repository: %s\n"), $path); printf(catgets(MSG_LOCAL_USER , "Local user: %s\n"), cdat::odm_get_user()); printf("\n"); my $root = $tree->getDocumentElement; @collects = $root->getElementsByTagName('collect'); if (defined($pmr)) { # -p is specified, display all collects for specified PMR number show_pmr($pmr); } elsif (defined($node)) { # -n is specified, display collects by nodes show_node($node); } else { # neither -p nor -n is specified, display collects by id show_id($id); } } main;