Unsolved

This post is more than 5 years old

53 Posts

1196

February 5th, 2010 07:00

Scripting, Solutions Enabler, and SCSI-3 Persistent flags

Well, I've just been working on getting SCSI-3 persistent mode set on all the devices on one of our Symms.

One of the things I've sort of tripped up on though, is I can't actually find an easy way to tell - for every device - whether it has the flag is set already.

So I've had to knock up a little something in perl, to do the job for me.

It lead me to wonder - has anyone come up with a good solution to the problem of 'doing/checking something on every device on a symm'?

I've often thought that Solutions Enabler could do with a Perl API, but as it is, I've mostly been running/parsing stuff like symmaskdb list database, and symdev list/show.

What increasingly becomes obvious is that the different commands within Solutions Enabler were written by different people, with slightly different ideas of what 'command syntax/output' was supposed to mean.

So anyway, does anyone have any neat scripts they'd like to show off/share?

9 Legend

 • 

20.4K Posts

February 5th, 2010 08:00

how do you feel about parsing XML output versus standard out ? You can add "-output xml" to your symcli commands and redirect output to an xml formatted file. For years I've been scrubbing output from std out with bash/perl but i started slowly switching to parsing xml output. There a was a presentation by Steve Giampa where he explains how to parse XML output with xml:simple module. I just find XML output more uniform, much easier to parse.  If you can't find this presentation drop me an email at linuxrox@gmail.com

1 Message

February 5th, 2010 13:00

Hi Ed_R

Would you be able to point me in the right direction on figuring out how to get the SCSI-3 persist mode set up on a device?  I'm using Solutions Enabler v6.3.2.0.   I am assuming this has to be done on devices that are not mapped.  What if they are already designated as R1's?

Any help would be appreciated.

Regards

Tonja

53 Posts

February 8th, 2010 00:00

Setting it with symconfigure is fairly easy:

set device 01EF attribute=SCSI3_persist_reserv;

You can do that on any device - mapped or unmapped.

The hard part is finding which ones have been set already or not - which was what was annoying me.

If you run a symconfigure script that covers everything, for example, it'll bomb out on the ones that are already set. (And you don't necessarily want to do that anyway.

Regarding that XML output Dynamox, that does sound handy. Hopefully it's a bit easier to parse the XML than it is the ... somewhat ad-hoc formatting of some of the command outputs.

I'll give it a try.

Mostly I don't mind just doing a regular expression to parse, but I do occasionally find myself wishing that there wasn't a space in "2-Way Mir" for example

On our array, things like 'symdev show' take a while to complete, so I've just finished knocking together something that parallelizes it.

I need to do 'symdev show' and extract the SCSI-3 Persistent Reserve: line, which is easy enough, but pretty timeconsuming when you've got a lot of LUNs.

Running parallelism (threads = number of GKs) seems to make it significantly faster.

Perhaps a bit overkill, but... this is what I've knocked together (runs with 'activestate perl' which you would need to be installing first - for this to work, you need both perl and solutions enabler installed on the same host)

use strict;
use warnings;

use thread;

#because 'symdev show' takes a while to complete on our array, we parallelize.
#parallelizm you can get away with threads up to the number of gatekeepers - more doesn't
#really do much apart from wasting processor time. 

my %devlist;

my $thread_limit = 10; #up to the number of gatekeepers speed this up
my $join_delay = 1; #set to zero will lead to a 'busy' loop, whilst this script
                    #runs.
my $output_file = "SCSI3_check.csv";


#this is the threading sub, that we create a thread to run.
sub check_SC3_P
{
  my ( $dev ) = @_;
  print "fetch thread for $dev started\n";
  my ( $SCSI3_persist ) = ( `symdev show $dev` =~ m/SCSI-3 Persistent Reserve\:\s+(\w+)/i );
  print "symdev show $dev SC3: $SCSI3_persist\n";
  return "$dev,$SCSI3_persist";
}

#merges and returns joinable threads.
sub thresh_threads
{
  print "Threshing threads... ",scalar threads -> list," threads running\n";
  foreach my $thread ( threads -> list() )
  {
    if ( $thread -> is_joinable() )
    {
      my $returned_result = $thread -> join ;
      my ( $returned_dev, $returned_SC3_flag ) = split (/,/, $returned_result );
      print "joining $returned_dev=$returned_SC3_flag\n";
      $devlist{$returned_dev}{'SC3'} = $returned_SC3_flag;
#     print join (",", "\'$returned_dev", $devlist{$returned_dev}{'config'},
#            $devlist{$returned_dev}{'capacity'}, $devlist{$returned_dev}{'SC3'}), "\n";   
      print join (",", "\'$returned_dev",
            $devlist{$returned_dev}{'capacity'}, $devlist{$returned_dev}{'SC3'}), "\n";   
    }   
  } #foreach
  print "Threshing done ",scalar threads -> list," threads running\n";
}

#run a symdev list, and stuff the results in an array
my @symdev_list = `symdev list`;
my $break_count = 0;

foreach ( @symdev_list )
{

  #pattern match to extract symdev, config and capacity. We don't really need config for this
  #script, but I find it handy for reporting.
#  my ( $symdev, $capacity ) =  ( m/^([0-9A-F]{4})\s+.*\s+(\d+)$/ );
  my ( $symdev, $config, $capacity ) =
        ( m/^([0-9A-F]{4})\s+.{6}\w*\s+\S+\s+\S+\s+(.{6}\w*)\s+.*\s+(\d+)$/ );

#next if $break_count++ >50;

#  print $_;
  next unless $capacity; #if that pattern match didn't work, we get no 'capacity'.
  print "$symdev, $config, $capacity\n";
 
  #this happens when it's e.g. a meta member - no capacity is listed.

#  $config =~ s/\s+$//g; #remove trailing whitespace.

  #$devlist{$symdev}{'config'} = $config;
  $devlist{$symdev}{'capacity'} = $capacity;

}

#and here we get cute - spawn threads, to go run the 'symdev show',
#because it's a slow command to return.

#'keys' returned the key values from a hash, in a nondeterministic order.
#that's fine, as we're doing concurrent stuff anyway - as long as we get all of them
#then the order will be random anyway.

foreach my $dev ( keys %devlist )
{
  #print "$dev\n";
  #two parts - thread spawner, and then catcher.
  #cycle back and forth, starting threads up to 'limit'
  #and then sit in a loop, waiting for them to exit.
  if ( scalar threads -> list() < $thread_limit )
  {
    print "spawning fetch for $dev thread count: ", scalar threads -> list() + 1,"\n";
    my $thread = threads -> create ( 'check_SC3_P', $dev );
    next;
  }
  else
  {
    #we've got limit threads running, so we need to join a few before we can proceed.
    #thus we run a while loop, with a sleep, checking each to see if joinable.
    until ( scalar threads -> list() < $thread_limit )
    {
      #sit in a loop, catch 'joinables' and then pause - before starting the next fetcher, and proceeding.
      thresh_threads;
      sleep $join_delay;
    } #until
    print "spawning fetch for $dev thread count: ", scalar threads -> list() + 1,"\n";
    my $thread = threads -> create ( 'check_SC3_P', $dev );
  } #else
}

#then we should still have some threads still running, left to join, so we do that again.

while ( threads -> list() )
{
  thresh_threads;
  sleep $join_delay;
}

print "Writing output file...\n";
#now we write the output. File's called SCSI3_check.csv oddly enough.
open ( OUTPUT, ">$output_file" );
print OUTPUT "symdev, config, capacity, SCSI-3_Persistent_Reserve\n";

#print them into the file, sorted into numeric hex order.
#we stick a ' in front of $symdev, because excel has a nasty habit of
#'processing' cells, and converting 01E3 to 1000, and nonsense like that.

foreach my $symdev ( sort { hex($a) <=> hex($b) } keys %devlist )
{

  print OUTPUT join (",", "\'$symdev",
            $devlist{$symdev}{'capacity'}, $devlist{$symdev}{'SC3'}), "\n";   
}

close ( OUTPUT );

9 Legend

 • 

20.4K Posts

February 11th, 2010 16:00

mad perl skills Ed ...very nice

instead of running "symdev show" on every single device you could dump output from "symdev list -sid 123 -v" and then parse the flat file. That would be much faster.

53 Posts

February 24th, 2010 01:00

Yeah, another case of scripting enthusiasm overtaking logical problem solving.

And there was me thinking I'd found a really awesome use for a threaded perl script

Parsing the symdev list -v works much better, although I am going to see about some manner of CSV adaptation.

53 Posts

February 24th, 2010 05:00

Have gone back to the 'CSV' roots and sure enough, it ends up just that much neater.

Run a 'symdev show -v -output XML' to see what the format of the XML is - you can probably adapt the 'device handler' below accordingly.

I don't like having to dump the data to a file, but given that our 'symdev list -v -output XML' comes to ~200Mb, it really does eat a massive amount of memory if you don't. (Rule of thumb on XML parsing is a factor of 10)

use strict;
use warnings;

use XML::Twig;
use Data::Dumper;

my @symms;

sub sym_list
{
  my ( $twig, $symm ) = @_;
  print $symm -> first_child('symid') -> text,"\n";
  push ( @symms, $symm -> first_child('symid') -> text );
}

sub symm_handler
{
  my ( $twig, $symm ) = @_;
  my $symid = $symm -> first_child('symid') -> text;
  print "New Symmetrix: ", $symid, "\n";
  open ( SC3_REP, ">SCSI-3_persist.$symid.txt" );
  print SC3_REP "dev,config,size(cyl),scsi3_persist_res,meta\n";
  open ( OUTPUT, ">SCSI-3_symconfigure.$symid.txt" );
}
 

sub device_handler
{
  my ( $twig, $device ) = @_;

  print SC3_REP join (",",
      join ("", "'",$device -> first_child('Dev_Info') -> first_child('dev_name') -> text ),
      $device -> first_child('Dev_Info') -> first_child('configuration') -> text,
      $device -> first_child('Capacity') -> first_child('cylinders') -> text,
      $device -> first_child('Flags') -> first_child('scsi3_persist_res') -> text,
      $device -> first_child('Flags') -> first_child('meta') -> text,     
  );
  print SC3_REP "\n";

#"#$devn,$conf,$cap,NoSC3->SC3\nset device $devn attribute=SCSI3_persist_reserv;\n";

  if ( $device -> first_child('Capacity') -> first_child('cylinders') -> text > 100
       and
       $device -> first_child('Flags') -> first_child('scsi3_persist_res') -> text =~ m/Disabled/
       and
       $device -> first_child('Flags') -> first_child('meta') -> text =~ m/(Head|None)/i
     )
  {
    print $device -> first_child('Dev_Info') -> first_child('dev_name') -> text, " needs SCSI-3 Persist set\n";

    print OUTPUT join (",",
        join ("", "#'",$device -> first_child('Dev_Info') -> first_child('dev_name') -> text ),
        $device -> first_child('Dev_Info') -> first_child('configuration') -> text,
        $device -> first_child('Capacity') -> first_child('cylinders') -> text,
        $device -> first_child('Flags') -> first_child('scsi3_persist_res') -> text,
        $device -> first_child('Flags') -> first_child('meta') -> text,     
    );
    print OUTPUT "\n";
    print OUTPUT "set device ", $device -> first_child('Dev_Info') -> first_child('dev_name') -> text,
                 " attribute=SCSI3_persist_reserv;\n";
  }
  $twig -> purge;
}

my $symtwig = new XML::Twig (
                  twig_handlers => { 'Symm_Info' => \&sym_list }
                  );
my $symcfg = `symcfg list -output XML`;

$symcfg =~ s/^$//mi;
$symtwig -> parse ( $symcfg );
#$symtwig -> parsefile ( "symcfg_list.xml" );


my $twig = new XML::Twig (
             twig_handlers =>
                     { 'Symm_Info' => \&symm_handler,
                       'Device' => \&device_handler } );

#test text - reads some entries from a sample file, because it's quick and not memory greedy for testing.
#open ( INPUT, "symdev_list_small.xml");
#my $input_text = join("",);
#close ( INPUT );

print "Running symcfg discover...\n";
print `symcfg discover`;

foreach my $symm ( @symms )
{
  print "Dumping symdev list to temporary file 'symdev_list_v.$symm.xml'\n";
  print `symdev list -v -sid $symm -output XML > symdev_list_v.$symm.xml`;
    #open ( OUTPUT, ">set_scsi3.txt");
  $twig -> parsefile ( "symdev_list_v.$symm.xml" );


close ( OUTPUT );

Message was edited by: Ed_R Added a bit more to the code, to support multiple symms in an environment, and write both a report and a 'symconfigure' script to set the SCSI3 persist.

0 events found

No Events found!

Top