JustPaste.it

#!/usr/bin/perl
#
# symaccess masking view report
#
# Produces a report summarizing the masking views and storage groups for an EMC VMax.
# This script uses the symaccess command with the "-output XML" option to obtain its
# information and requires the use of the perl XML module to do the parsing.
#
# The script can produce plain text, or a simple HTML page.  The HTML page has
# intra document links to make it easier to navigate around. The script can also
# produce a "light" or "list only" version of it's output, where it just prints the
# devices and the masking views that the devices are in.
#
# In a nut shell, the full output of this script consists of a prettied up version of
# "symaccess list view" with the disk space used by each view listed.  Then the script
# runs "symaccess show view <viewname>" for each view.  It also runs a symaccess show
# for any storage groups that are not included in any masking views.
#
# The script does not print information about old style mapping/masking commands, it
# only documents symaccess structures.
#
# The script can take a while to run if a system has many masking views.  Running
# the script with a -v for verbose gives feedback on what the script is doing, so
# it can be handy to use that option when initially testing the script in a new
# environment.
#
# This script has been tested on Linux and AIX.  It requires SYMCLI.
#
# Options:
# -s sid  - specifies the SID of the VMax.  Otherwise we depend on SYMCLI_SID
# -v      - Verbose.  Prints diag messages as it runs various symcli commands.
# -l      - light or list output.  
#           prints device ids and the masking view that they are in.
# -h      - prints usage statement
# -H      - HTML output
#
# Andy Welter
#
# V1.0 March 2011, initial version.
# V1.1 May 2011, cleanup unneeded code.
# V1.2 May 2011, add "light" option that only lists devices with their masking view.
# V1.2 Aug 2011, add reporting for storage groups that are not in views.
# V1.3 Dec 2011, added usage statement and some comments.
#

# use module
use XML::Simple;
use Data::Dumper;
use Getopt::Std;
$usage="USAGE: emc-maskrep <-s sid> <-l> <-H> <-v>\n-s specify SID if not using SYMCLI_SID env variable\n-l sg list only, aka light output\n-H html output\n-v verbose output\n";
getopts ('s:Hhlv') || die "$usage";
if ( $opt_s ne "" ) {
    $ENV{SYMCLI_SID}=$opt_s;
};
if ( $ENV{SYMCLI_SID} eq "" ) {
    print "ERROR: must specify an array with SYMCLI_SID or -s\n";
    exit 1;
};
if ( $opt_H ne "" ) {
    $html=1;
};
#
# Note: RDF info not currently supported.
if ( $opt_r ne "" ) {
    # get RDF info with symrdf list
    $rdf=1;
};
if ( $opt_l ne "" ) {
    # "list" output, only list devices by storage view
    $light=1;
};
if ( $opt_v ne "" ) {
    # verbose output... print info to std err to track progress.
    $verbose=1;
};
if ( $opt_h ne "" ) {
    # help and exit
    print "$usage";
    exit 0;
};

sub refToList  {
# when we have one item in a list in the XML, it
# gets parsed as a scalar instead of an array.  So we sometimes
# want to be able to force that to be one item list to make
# coding easier.
#
# This is complicated, so I'll break it down:
# @_ is the array of parameters to the function.
# @_[0] is the first parameter, which in this case is a reference
# The ref test then checks to see whether that reference is to a scalar
# or is a reference to an array.
my @list;
my $item;
if ( ref (@_[0]) eq "ARRAY" ) {
    # The first parameter is a reference to an array.  But what I want
    # is the array itself, not the reference to it.  So that is what the @{} gets me.
    #@list=@{@_[0]};
    foreach $item (@{@_[0]}) {
    if ($item ne "") {
        push (@list, $item);
    };
    };
} else {
        # the reference is to a scalar, and that is easier to decode.  I then turn
        # it into an array.
        my ($item)=(@_);
        @list=($item);
};
# and now I return the array.
return @list;
};


sub getSgList() {
my $xml = new XML::Simple (KeyAttr=>[]);
$verbose && print STDERR "list -type storage...\n";
my $cmdout=`symaccess list -type storage -output XML 2> NULL`;
if ( $cmdout eq "" ) {
    print "ERROR symaccess list -type storge \n";
    return;
};
my $sym=$xml->XMLin($cmdout);
my @sglist=refToList ($sym->{Symmetrix}{Storage_Group});
my $sg;
my %sgdb;
my $name;
foreach $sg (@sglist) {
    $name=$sg->{Group_Info}{group_name};
    $sgdb{$name}="";
};
return %sgdb;

};

sub getMaskViews() {
my $xml = new XML::Simple (KeyAttr=>[]);
$verbose && print STDERR "list view...\n";
my $cmdout=`symaccess list view  -output XML 2> NULL`;
if ( $cmdout eq "" ) {
    print "ERROR symaccess list view \n";
    return;
};
my $sym=$xml->XMLin($cmdout);
my @viewlist=refToList ($sym->{Symmetrix}{Masking_View});
my $view;
my $viewXML,$showViewOut;
my %viewdb;
my $name,$ig,$pg,$sg,$size;
foreach $view (@viewlist) {
    $name=    $view->{View_Info}{view_name};
    $ig=    $view->{View_Info}{init_grpname};
    $pg=    $view->{View_Info}{port_grpname};
    $sg=    $view->{View_Info}{stor_grpname};
    my $size=0;
    if ( $light != 1 ) {
        $verbose && print STDERR "get size view $name...\n";
        $showViewOut=`symaccess show view $name  -output XML 2> NULL`;
        $viewXML=$xml->XMLin($showViewOut);
        my $device,@devlist;
        @devlist=refToList($viewXML->{Symmetrix}{Masking_View}{View_Info}{Device});
        my @cap;
        foreach $device (@devlist) {
        @cap=refToList($device->{capacity});
            $size+=$cap[0];
        };
    };
    $viewdb{$name}="$ig,$pg,$sg,$size";
};
return %viewdb;
};

sub printListViews {
my (%maskviews)=@_;
my $view,@values;
$date=`date`;
if ( $html == 1 ) {
    print "<h1>Masking View Report</h1>\n<h2>$date $ENV{SYMCLI_SID}</h2>\n<table border cellpadding=5>\n";
    print "<tr><th>view <th>init group <th>port group  <th>storage group <th>capacity</tr>\n";
} else {
    print "#########################################################################################\n";
    print "# Masking View Report $date $ENV{SYMCLI_SID}\n";
    print "# view              init group          port group          storage group        capacity\n";
    print "#################   #################   #################   ##################  #########\n";
};
my $total=0;
foreach $view (sort (keys (%maskviews))) {
    @values=split /,/,$maskviews{$view};
    $total+=$values[3];
    if ( $html == 1 ) {
        printf "<tr><td><a href=\"#%s\">%s</a><td>%s<td>%s<td>%s<td align=right>%d</tr>\n",
        $view,$view,$values[0],$values[1],$values[2],$values[3];
    } else {
        printf "%-19s %-19s %-19s %-19s %9d\n",
        $view,$values[0],$values[1],$values[2],$values[3];
    };
};
if ( $html == 1 ) {
    print "<tr><td>&nbsp<td>&nbsp<td>&nbsp<td>total MB<td>$total</table>\n<br>\n";
    print "<hr>\n";
    print "\n<h2><a href=#unused-sglist>Link to Unmasked Storage Group List</a></h2>\n";
    print "<hr>\n";
    print "\n<h2>Masking View Details</h2>\n";
} else {
    print "%80s%10d\n"," ", $total;
};
};

#
# NOTE: rdf info option not currently supported.
sub getRDF {
my $xml = new XML::Simple (KeyAttr=>[]);
$verbose && print  STDERR "run symrdf list...\n";
return;
my $cmdout=`/usr/symcli/bin/symrdf list -output XML 2> NULL`;
my $sym=$xml->XMLin($cmdout);
my @devlist=refToList ($sym->{Symmetrix}{Device});
my $dev;
my %rdfhash;
my $local,$remote,$type,$group;
foreach $dev (@devlist) {
    $local=$dev->{Local}{dev_name};    
    $type=$dev->{Local}{type};    
    $group=$dev->{Local}{ra_group_num};    
    $remote=$dev->{Remote}{dev_name};
    $rdfhash{$local}="$type:$group\t$remote";
};
return %rdfhash
};

sub getLightView {
my ($view)=@_;
my $xml = new XML::Simple (KeyAttr=>[]);
$verbose && print STDERR "show view $view...\n";
my $cmdout=`symaccess show view $view -output XML 2>NULL`;
my $sym=$xml->XMLin($cmdout);
my @devlist=refToList ($sym->{Symmetrix}{Masking_View}{View_Info}{Device});
my @devs,$dev;
foreach $dev (@devlist) {
    push (@devs,$dev->{dev_name});    
};
return @devs;
};

sub showLightView {
my ($view)=@_;
my @list=getLightView($view);
foreach $dev (@list) {
    print "$dev\t$view\n";
};
};

sub showView {
my ($view)=@_;
my $xml = new XML::Simple (KeyAttr=>[]);
$verbose && print STDERR "show view $view...\n";
my $cmdout=`symaccess show view $view 2> NULL` ;
if ( $html == 1 ) {
    print "<a name=\"$view\">\n";
    print "<a href=#top>[top]</a>\n";
};
print "\n\n############################################################################\n";
print "## View $view\n";
print "############################################################################\n";
print "$cmdout";
};


############################################################################
# Main routine
############################################################################

my (%sglist)=&getSgList();
my (%maskviews)=&getMaskViews();

if ( $html == 1 ) {
    print "<html>\n<pre>\n";
};
if ( $light != 1 ) {
    printListViews(%maskviews);
};
my @masklist=sort keys (%maskviews);
my %rdfhash;
if ( $rdf ne "" ) {
    %rdfhash=getRDF();
};
foreach $view (@masklist) {
    if ( $light != 1 ) {
    showView($view);
    } else {
    showLightView($view);
    };
    # mark the storage group for this view as used
    my @mvparms=split/,/,$maskviews{$view};
    $sglist{$mvparms[2]}=$view;
};

if ( $light != 1 ) {
# print out the list of unused storage groups
my $sg;
if ( $html == 1 ) {
    print "<hr>\n";
    print "<a name=\"unused-sglist\">\n";
    print "\n<h2>Unmasked Storage Groups</h2>\n";
    print "<a href=#top>[top]</a>\n";
} else {
    print "\n\nUnmasked Storage Groups\n";
};
foreach $sg (sort keys (%sglist)) {
    if ( $sglist{$sg} eq "" ) {
    if ( $html == 1 ) {
        print "<a href=\"#sg-$sg\">$sg</a>\n";
        } else {
        print "$sg\n";
        };
    };
};
# show details of each unused sg
foreach $sg (sort keys (%sglist)) {
    if ( $sglist{$sg} eq "" ) {
        my $cmdout=`symaccess show $sg -type storage 2> NULL` ;
        if ( $html == 1 ) {
        print "<a name=\"sg-$sg\">\n";
        print "<h2>$sg</h2>\n";
        print "<a href=#unused-sglist>[unmasked list]</a>\n";
        print "$cmdout"
        } else {
        print "\n$cmdout";
        };
    };
};
};
    

if ( $html == 1 ) {
    print "</pre>\n</html>\n";
};