Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
0 Kudos

In Kathrin Winkmann's SDN blog

["Check this out and get an example how to create your own observer mode and alert function!" | The specified item was not found.]

there is a perl script available implementing an observer mode and an alert function for versions of the Software Delivery Tools (SDT) and EHP installer without that features.

Using the script showed some areas for improvements.

So I changed/enhanced it a bit:

    • shows timestamps
    • executes the alert command only on status changes

And there was an error regarding return codes and related messages. That should be fixed as well.

The current version is here:

#!/usr/bin/perl -w
#
# Query status of running SL-controller
#
# Copyright (c) 2008-2009 SAP-AG
#
# Joerg Schoen
#
# Enhanced by Christian Ziemski 11/2011
#
use strict;
use IO::Socket::INET;
use XML::Parser;
use Time::Local;

my $SERVICE_PROTOCOL = "ExecServiceProtocol";
my $SERVICE_PROTOCOL2 = "LupServiceProtocol";
my $PROTOCOL_VERSION = "2.1";
my $DEFAULT_PORT = 4239;

my $mylastglobalstatus = -99;

my %MapRoadMap = (
                "extract" => "Extraction",
                "configure" => "Configuration",
                "check" => "Checks",
                "pre-execute" => "Preprocessing",
                "execute" => "Downtime",
                "post-execute" => "Postprocessing"
                );
if(scalar @ARGV == 0) {
        print "Usage: getslcstatus.pl [] [:] ...\n";
        print " Get the status of a running SL-Controller on the given host(s).\n";
        print " A non-standard port can be given, otherwise it defaults to '" . $DEFAULT_PORT . "'.\n";
        print "Options:\n";
        print " -D Show low level communication with SLC.\n";
        print " -q Be quiet, only execute alert and set exit code.\n";
        print " -S Repeatedly get status and wait in between.\n";
        print " -A In case the tool is not running, execute the alert command.\n";
        exit 5;
}
# Bit 0: If set, show communication details with SLC.
my $Debug = 0;
my $Verbose = 1;
my $SleepTime = 0;
my $AlertCommand;
while(scalar @ARGV > 0 && $ARGV[0] =~ /^-/) {
        if($ARGV[0] eq "-D") {
                $Debug = 1;
        } elsif($ARGV[0] eq "-q") {
                $Verbose = 0;
        } elsif($ARGV[0] =~ /^-S(\d+)/) {
                $SleepTime = $1;
        } elsif($ARGV[0] =~ /^-A(.+)/) {
                $AlertCommand = $1;
        } else {
                die "Invalid option " . $ARGV[0];
        }
        shift @ARGV;
}
# 0: Everything is OK, the tool is running (or waiting for the parallel JAVA part)
# 1: The tool is waiting in a dialogue
# 2. The tool failed.
my $globalstatus = 0;
my $lastline = "";
my $currline = "";
my $isnewline = 1;
my %seenunexpectedsubtags;
my $lastphase = "";
my $secondlastphase = "";
my $titlecounter = -1;

#------------------------------------------------------------------------------

sub print_timestamp {
        my ($sec, $min, $hour, $mday, $month, $year, $wday, $ydat, $isdst) = localtime();
        printf("----- %s-%02s-%02s_%02s:%02s:%02s %s\n", $year+1900,$month+1,$mday,$hour,$min,$sec, "-" x 59);
}

#------------------------------------------------------------------------------

sub print_title(){
        print_timestamp();
        if ($titlecounter == -1 || $titlecounter > 9) {
                printf "%-10s|%-6s|%-10s|%-15s|%-5s|%-10s\n", "Machine", "Stack", "Status", "Step", "Perc", "Description";
                print "-" x 85 . "\n";
                $titlecounter = 0;
        }
        $titlecounter += 1;
}

#------------------------------------------------------------------------------

while(1) {
        $globalstatus = 0;

        foreach my $hostport (@ARGV) {
                my $results = &queryslc($hostport);

                if(!defined $results) {
                        printf "%s is not accessible!\n", $hostport if $Verbose > 0;
                        $globalstatus = 2;
                } else {
                        my $allcompleted = 1;
                        foreach my $result (@$results) {
                                my ($reqid, $status, $step, $details, $procs, $total) = @$result;
                                $details = "" unless defined $details;
                                $secondlastphase = $lastphase;
                                $lastphase = $details;
                                if ($Verbose > 0) {
                                        $currline = sprintf ("%-10s|%-6s|%-10s|%-15s|%5s|%-10s\n", $hostport, $reqid, $status, $step, int(100 * ($procs / $total)), $details) ;
                                        if ($currline ne $lastline) {
                                                print_title();
                                                print $currline;
                                                $lastline = $currline;
                                                $isnewline = 1;
                                        } else {
                                                $isnewline = 0;
                                        }
                                }
                                $allcompleted = 0 if $status ne "COMPLETED";
                                next if $status eq "INITIAL" || $status eq "RUNNING" || $status eq "WAITING";
                                if($status eq "DIALOGUE") {
                                        $globalstatus = 1 if $globalstatus < 1;
                                } else {
                                        $globalstatus = 3;
                                }
                        }
                        $globalstatus = 2 if $allcompleted && $globalstatus < 2;
                }
                print "-" x 85 . "\n" if ($Verbose > 0 && $isnewline == 1);
        }

        if ($mylastglobalstatus != $globalstatus) {
                my $msg = "";
                $msg = "A tool is waiting for user interaction." if $globalstatus == 1;
                $msg = "A tool failed!"                          if $globalstatus == 2;
                $msg = "Current step completed!"                 if $globalstatus == 3;

                if(defined $AlertCommand && $globalstatus != 0) {
                        if($Verbose > 0){
                                print "Executing AlertCommand...\n";
                        }
                        system($AlertCommand . " " . $msg . " -- " . $lastphase . " -- " . $secondlastphase);
                }
                if($Verbose > 0 && $globalstatus > 0) {
                        print "$msg" . "\n";
                }
                $mylastglobalstatus = $globalstatus;
                $isnewline = 1;
        }

        last if $SleepTime == 0;
        sleep($SleepTime);
}
exit $globalstatus;

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sub queryslc
{
        my ($hostport) = @_;
        # First get the overall status
        my $status = &queryslc1($hostport, "status");
        return undef unless defined $status;
        # Ask again to get the substati for each running request
        # (i. e. ABAP, JAVA).
        for(my $i = 0 ; $i < scalar @$status ; ++$i) {
                my $reqid = $$status[$i]->[0];
                my $progress = &queryslc1($hostport, "progress", $reqid);
                $$status[$i]->[4] = $progress->[0]->[0];
                $$status[$i]->[5] = $progress->[0]->[1];
        }
        #
        # The returned structure looks like
        # [
        # [ 'ABAP', 'DIALOGUE', 'Extraction', 'Waiting for completion of the dialog', '105', '106' ],
        # [ 'Java_EE', 'WAITING', 'Extraction', 'Waiting until the ABAP upgrade tool has finished the extraction', '1', '1' ]
        # ]
        # The entries are:
        # Request-Id: Either 'ABAP' or 'JAVA'
        # Status: One of:
        # 'INITIAL': Request hasn't been started yet.
        # 'RUNNING': Request is running.
        # 'WAITING': Request is waiting for other requess in sync phase.
        # 'COMPLETED': Request is completed.
        # 'DIALOGUE': Request is waiting in a user dialogue (error or configuration).
        # Roadmapstep: Corresponds to the roadmap steps on the SDTGui.
        # Details: Details of Status.
        # Procs/Total: Executed steps from given total steps. Simple division gives a percentage.
        #
        return $status;
}
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Send and retrieve one SL-controller query.
sub queryslc1
{
        my ($hostport, $type, $reqid) = @_;
        my ($hostname, $port);
        unless(($hostname, $port) = ($hostport =~ /^(\S+):(\d+)$/)) {
                $hostname = $hostport;
                $port = $DEFAULT_PORT;
        }
        my $socket = IO::Socket::INET->new(PeerAddr => $hostname,
                                        PeerPort => $port,
                                        Proto => "tcp",
                                        Type => SOCK_STREAM);
        return undef unless defined $socket;
        &sendquery($socket, $type, $reqid);
        shutdown($socket, 1);
        my $buf;
        my $xmlString = "";
        while((my $len = $socket->read($buf, 4096)) > 0) {
                $xmlString .= $buf;
        }
        if($Debug & 1) {
                for my $line (split "\n", $xmlString) {
                        printf "<< %s\n", $line;
                }
        }
        my $xmlParser = XML::Parser->new(Style => 'Tree');
        my $xml = $xmlParser->parse($xmlString);
        close $socket;
        # Check top level tag and protocol version
        my $tagname = $$xml[0];
        if(defined $SERVICE_PROTOCOL) {
                die "Invalid reply '$tagname' from $hostport"
                        unless $tagname eq $SERVICE_PROTOCOL || $tagname eq $SERVICE_PROTOCOL2;
        }
        $xml = $$xml[1];
        if(defined $PROTOCOL_VERSION) {
                my $protvers = $$xml[0]->{"version"};
                die "Unsupported version '$protvers'"
                        unless $protvers eq $PROTOCOL_VERSION;
        }
        my @result;
        for(my $i = 1 ; $i < scalar @$xml ; $i += 2) {
                my $tagname = $$xml[$i];
                next if $tagname eq "0";
                my $tagcont = $$xml[$i + 1];
                if($tagname eq "CmdStatus") {
                        my $subxml = $tagcont;
                        for(my $j = 1 ; $j < scalar @$subxml ; $j += 2) {
                                $tagname = $$subxml[$j];
                                next if $tagname eq "0";
                                $tagcont = $$subxml[$j + 1];
                                if($tagname eq "SDTRequestStatus") {
                                        my $reqId = $$tagcont[0]->{"requestId"};
                                        my $status = $$tagcont[0]->{"status"};
                                        my $operation = $$tagcont[0]->{"operation"};
                                        my $details;
                                        for(my $ii = 1 ; $ii < scalar @$tagcont ; $ii += 2) {
                                                $tagname = $$tagcont[$ii];
                                                next if $tagname eq "0";
                                                my $tagcont2 = $$tagcont[$ii + 1];
                                                if($tagname eq "Details") {
                                                        $details = &gettagcont($tagcont2);
                                                        $details =~ s/\s+$//;
                                                } else {
                                                        if (not $seenunexpectedsubtags{ $tagname }) {
                                                                $seenunexpectedsubtags{ $tagname } = "1";
                                                                warn "Unexpected subtag '$tagname' ignored (reported only once!)";
                                                        }
                                                }
                                        }
                                        $operation = $MapRoadMap{$operation} if defined $MapRoadMap{$operation};
                                        $status = "DIALOGUE" if defined $details && $details =~ m/dialog/i;
                                        push @result, [ $reqId, $status, $operation, $details ];
                                } else {
                                        warn "Unexpected tag '$tagname' ignored";
                                }
                        }
                } elsif($tagname eq "CmdProgress") {
                        my $processed = $$tagcont[0]->{"processed"};
                        my $total = $$tagcont[0]->{"total"};
                        push @result, [ $processed, $total ];
                } else {
                        warn "Unexpected tag '$tagname' ignored";
                }
        }
        return \@result;
}
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Send a query to SLC
sub sendquery
{
        my ($handle, $type, $reqid) = @_;
        my @querylines;
        push @querylines, sprintf "" .
"<%s version=\"%s\" secure=\"false\">\n",
                $SERVICE_PROTOCOL, $PROTOCOL_VERSION;
        if($type eq "status") {
                push @querylines, sprintf " \n";
        } elsif($type eq "progress") {
                if(defined $reqid) {
                        push @querylines, sprintf " \n", $reqid;
                } else {
                        push @querylines, sprintf " \n";
                }
        } else {
                die "Unknown type '$type'";
        }
        push @querylines, sprintf "\n", $SERVICE_PROTOCOL;
        # The following characters (byte 255) is crucial, since SLC needs it to detect the end of input!
        push @querylines, sprintf "\xff";
        foreach my $line (@querylines) {
                print $handle $line;
                print ">>> " . $line if $Debug & 1;
        }
        print "\n" if $Debug & 1;
        $handle->flush;
}
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Simple method to get the content of a tag
sub gettagcont
{
        my ($xml) = @_;
        my $content = "";
        for(my $i = 1 ; $i < scalar @$xml ; $i += 2) {
                my $tagname = $$xml[$i];
                die "Sub tags not expected" if $tagname ne "0";
                $content .= $$xml[$i + 1];
        }
        return $content;
}

Obviously it's work in progress - as software always is. 😉

I'll update it here when appropriate or needed.

Christian

1 Comment