Subversion Repositories DevTools

Rev

Rev 3859 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# Copyright ( C ) 2008 ERG Limited, All rights reserved
#
# Module name   : jats.sh
# Module type   : Makefile system
# Compiler(s)   : n/a
# Environment(s): jats
#
# Description   : Display Daemon Status information
#
# Usage         : See POD at end of file
#
#......................................................................#

require 5.6.1;
use strict;
use warnings;
use JatsError;
use JatsSystem;
use Getopt::Long;
use Pod::Usage;
use JatsRmApi;
use Term::ANSIColor qw(:constants);
use DBI;

my $VERSION = "1.0.0";                      # Update this
my $opt_verbose = 1;
my $opt_help = 0;
my $opt_repeat;
my $opt_short = 0;
my $opt_color;
my @opt_rtag;
my %opt_rtag;
my $opt_filter;
my $RM_DB;
my %pname;
my %rc;
my %rl;
my %rname;
my %official;
my $indefinite = 0;
my $ff_string = "\f";
my $dead_time = ( 5 * 60 ) * 2;
my %StateData = ( 0 => 'Undefined',
                  1 => 'Disk Full',
                  2 => 'Paused',
                  3 => 'Active',
                  4 => 'Idle' ,
                  5 => 'Waiting',
                  6 => 'Publishing',
                  );

#-------------------------------------------------------------------------------
# Function        : Main Entry
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
my $result = GetOptions (
                "help:+"        => \$opt_help,          # flag, multiple use allowed
                "manual:3"      => \$opt_help,          # flag
                "verbose:+"     => \$opt_verbose,       # flag
                "repeat=i"      => \$opt_repeat,        # Integer
                "dead=i"        => \$dead_time,         # Integer
                "short:+"       => \$opt_short,         # Flag
                "color"         => \$opt_color,         # Flag
                "rtag=s"        => \@opt_rtag,          # Array
                "filter"        => \$opt_filter,        # Flag
                );

#
#   Process help and manual options
#
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
pod2usage(-verbose => 1)  if ($opt_help == 2 );
pod2usage(-verbose => 2)  if ($opt_help > 2);

ErrorConfig( 'name'    =>'DSTATUS' );

#
#   Native windows doesn't handle color
#   Dispable color by default
#
unless ( $opt_color )
{
    $ENV{ANSI_COLORS_DISABLED} = 1;
    $ff_string = "\n\n\n";
}

#
#   Convert array of RTAGS into a hash for simpler usage
#

$opt_rtag{$_} = 1 foreach ( split( /[,\s]+/, "@opt_rtag"));

#
#   Attempt to prevent users from repeating every second
#   If the user specified < 10, then set it to 10
#   Exports ( with internal knowledge) can set shorter times
#
$opt_repeat = 10 if ( $opt_repeat && $opt_repeat < 10 );
$opt_repeat -= 1000 if ( $opt_repeat && $opt_repeat > 1001 );

#
#   Repeat for ever
#
while (1)
{
    getGlobal();
    GetConfigData();
    GetRunData();
    DisplayInfo();

    last unless ( $opt_repeat );
    sleep ($opt_repeat );

    #
    #   Cleanout any data from previous run
    #
    %pname = ();
    %rc = ();
    %rl = ();
    %rname = ();
    %official = ();
    
}

disconnectRM(\$RM_DB);
exit;

#-------------------------------------------------------------------------------
# Function        : DisplayInfo
#
# Description     : Display collected information
#
# Inputs          : 
#
# Returns         : 
#
sub DisplayInfo
{

#DebugDumpData ("Data", \%rc);

    #
    #   Display a header
    #   Include a form feed if possible
    #
    if ( $opt_repeat )
    {
        print $ff_string, BOLD, "Build Daemon Status [" . localtime() . "]" , RESET, "\n";
    }
    if ( $opt_short && $indefinite )
    {
        print RED "*** Indefinite Pause", RESET, "\n";
    }

    #
    #  Sort by Project Name and Release Name
    #
    foreach my $pname ( sort keys %pname )
    {
        foreach my $rname ( sort keys %{$pname{$pname}} )
        {
            my $rtag_id = $pname{$pname}{$rname};
            my @orderm;
            my @orders;
            my $building = 0;
            my $dead = 0;
            my $paused = 0;
            my $in_error = 0;
            

            foreach my $rcon_id ( keys %{$rc{$rtag_id}}  )
            {
                next unless ( exists $rl{$rcon_id} );

                #
                #   Maintain alive info
                #
                if ( $rl{$rcon_id}{deltat} )
                {
                    if ( $rl{$rcon_id}{deltat} > $dead_time )
                    {
                        $dead = 1;
                    }
                }

                #
                #   Determine if any of the machines are building a package
                #
                $building = 1 if ( $rl{$rcon_id}{cpid} );

                #
                #   Sort into Master and Slaves
                #   Done so that we can print the master at the top of the list
                #
                if ($rc{$rtag_id}{$rcon_id}{hostmode} =~ m{M} )
                {
                    push @orderm, $rcon_id;
                }
                else
                {
                    push @orders, $rcon_id;
                }

                #
                #   Paused deamons don't maintain alive data
                #   Disabled daemons don't maintain alive data
                #
                $paused += 1
                    if ( $rl{$rcon_id}{crl} == 2 );

                $paused += 1
                    if ( $rl{$rcon_id}{pause} == 2 );
                    

                $dead = 0
                    if ( $paused );

                $in_error ++
                    if ( $rl{$rcon_id}{crl} == 1 );
                
            }

            if ( $in_error || $dead || $building || $opt_short < 2  )
            {
                print BOLD GREEN "[$rtag_id] $rname{$rtag_id} ($official{$rtag_id})", RESET, "\n";
            }
            
            if ( $in_error || $dead || $building || $opt_short < 1 )
            {
                foreach my $rcon_id ( @orderm, sort(@orders) )
                {
                    if ( $opt_filter )
                    {
                         printf "    %1.1s: %-20.20s %s\n",
                            $rc{$rtag_id}{$rcon_id}{hostmode},
                            $rc{$rtag_id}{$rcon_id}{hostname},
                            $rc{$rtag_id}{$rcon_id}{filter};
                    }
                    else
                    {
                             printf "    %1.1s: %-20.20s %s%10s%s(%1.1s) %-20s %-20s (%5s)\n",
                #                $rtag_id, $rcon_id,
                                $rc{$rtag_id}{$rcon_id}{hostmode},
                                $rc{$rtag_id}{$rcon_id}{hostname},
                                $indefinite ? RED : RESET,
                                $indefinite ? ('AllStop') : (getState($rl{$rcon_id})),
                                RESET,
                                defined ($rl{$rcon_id}{pause} ) ? $rl{$rcon_id}{pause} : '-',
                                $rl{$rcon_id}{cpid} || '-',
                                $rl{$rcon_id}{alive} || '-',
                                $rl{$rcon_id}{deltat} || '-',
                            ;
                    }
                }
                print "\n";
            }
        }
    }
}

#-------------------------------------------------------------------------------
# Function        : getGlobal
#
# Description     : Get global information
#
# Inputs          : 
#
# Returns         : 
#

sub getGlobal
{
    my (@row);
    $indefinite = 0;
    
    # if we are not or cannot connect then return 0 as we have not found anything
    connectRM( \$RM_DB) unless $RM_DB;

    # First get details from pv_id

    my $m_sqlstr = "SELECT SCHEDULED_PAUSE, SCHEDULED_RESUME, REPEAT, INDEFINITE_PAUSE" .
                   " FROM RELEASE_MANAGER.RUN_LEVEL_SCHEDULE";

    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
                    $indefinite = 1 if ( $row[3] )
#                    print "@row\n";
                }
            }
            $sth->finish();
        }
        else
        {
        Error("Execute failure: getGlobal", $m_sqlstr );
        }
    }
    else
    {
        Error("Prepare failure: getGlobal" );
    }
}

#-------------------------------------------------------------------------------
# Function        : GetConfigData
#
# Description     : Build up a list of all releases that have daemons
#                   configured
#
# Inputs          : 
#
# Returns         : 
#
sub  GetConfigData
{
    my $foundDetails = 0;
    my (@row);

    # if we are not or cannot connect then return 0 as we have not found anything
    connectRM( \$RM_DB) unless $RM_DB;

    # First get details from pv_id

    my $m_sqlstr = "SELECT rc.RCON_ID, rc.RTAG_ID, rc.GBE_ID, bm.DISPLAY_NAME, " .
                          "rc.DAEMON_MODE, rc.GBE_BUILDFILTER, rt.RTAG_NAME, " .
                          "p.PROJ_NAME, rt.OFFICIAL".
                    " FROM release_manager.release_config rc, " .
                           "release_manager.RELEASE_TAGS rt, " .
                           "release_manager.PROJECTS p, " .
                           "release_manager.BUILD_MACHINE_CONFIG bm " .
                    " WHERE       rt.RTAG_ID = rc.RTAG_ID" .
                            " AND rt.PROJ_ID = p.PROJ_ID" .
                            " AND rt.OFFICIAL != 'A'" .
                            " AND rt.OFFICIAL != 'Y'" .
                            " AND rc.GBE_ID = bm.GBE_ID" .
                            " AND rc.DAEMON_HOSTNAME is not null" .
                            " AND rc.DAEMON_HOSTNAME = bm.MACHINE_HOSTNAME" .
                            "";

    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
                    my $rcon_id = $row[0];
                    my $rtag_id = $row[1];
                    my $gbe_id =  $row[2];
                    my $hostname = $row[3];
                    my $hostmode = $row[4];
                    my $filter = $row[5];
                    my $rname = $row[6];
                    my $pname = $row[7];
                    my $official = $row[8];

                    next unless ( $hostname );
                    if ( @opt_rtag )
                    {
                        next unless ( defined $opt_rtag{$rtag_id} );
                    }

                    my %data;
                    $data{rcon_id}  = $rcon_id;
                    $data{hostname} = $hostname || 'Unknown';
                    $data{hostmode} = $hostmode;
                    $data{filter}   = $filter;

                    $rc{$rtag_id}{$rcon_id} = \%data;

                    $rname{$rtag_id} = "$pname: $rname";

                    $pname{$pname}{$rname} = $rtag_id;

                    $official{$rtag_id} = $official;
                    
#                    print "@row\n";
                }
            }
            $sth->finish();
        }
        else
        {
        Error("Execute failure: GetConfigData", $m_sqlstr, $sth->errstr() );
        }
    }
    else
    {
        Error("Prepare failure: GetConfigData" );
    }
}

#-------------------------------------------------------------------------------
# Function        : GetRunData
#
# Description     : Build up data for each daemon
#
# Inputs          : 
#
# Returns         : 
#
sub  GetRunData
{
    my $foundDetails = 0;
    my (@row);

    # if we are not or cannot connect then return 0 as we have not found anything
    connectRM( \$RM_DB) unless $RM_DB;

    # First get details from pv_id

    my $m_sqlstr = "SELECT rl.RCON_ID, rl.CURRENT_BUILD_FILES, rl.CURRENT_RUN_LEVEL, rl.PAUSE, " .
                            "rl.CURRENT_PKG_ID_BEING_BUILT, pkg.PKG_NAME, " .
                            "rl.KEEP_ALIVE, TRUNC (86400*(SYSDATE - rl.KEEP_ALIVE))" .
                    " FROM RELEASE_MANAGER.RUN_LEVEL rl, RELEASE_MANAGER.PACKAGES pkg" .
                    " WHERE pkg.PKG_ID (+)= rl.CURRENT_PKG_ID_BEING_BUILT";


    my $sth = $RM_DB->prepare($m_sqlstr);
    if ( defined($sth) )
    {
        if ( $sth->execute( ) )
        {
            if ( $sth->rows )
            {
                while ( @row = $sth->fetchrow_array )
                {
#                    print "@row\n";
                    my $rcon_id = $row[0] || '';
                    my $cbf     = $row[1] || '';
                    my $crl     = $row[2] || '0';
                    my $pause   = $row[3] || '0';
                    my $cpid    = $row[5] || '';
                    my $alive   = $row[6] || '';
                    my $deltat  = $row[7] || '0';

                    $rl{$rcon_id}{crl} = $crl;
                    $rl{$rcon_id}{pause} = $pause;
                    $rl{$rcon_id}{cpid} = $cpid;
                    $rl{$rcon_id}{alive} = $alive;
                    $rl{$rcon_id}{deltat} = $deltat;
#                    printf "%10s, %10s, %10s, %10s, %10s, %20s\n", $rcon_id, $cbf, $crl, $pause, $cpid, "$alive, $deltat";
                }
            }
            $sth->finish();
        }
        else
        {
        Error("Execute failure: GetRunData", $m_sqlstr );
        }
    }
    else
    {
        Error("Prepare failure" );
    }
}

#-------------------------------------------------------------------------------
# Function        : getState
#
# Description     : Convert state into a nice state string
#
# Inputs          : Ref for info
#
# Returns         : 
#
sub getState
{
    my ($rlidp) = @_;
    return "Undefined" unless ( defined $rlidp );

    my $num = $rlidp->{crl};
    my $pause = $rlidp->{pause};
    return "Undefined" unless ( defined $num && defined $pause );

    if ( $pause == 2 ) {
        return 'Disabled';
    } elsif ( $pause == 1 ) {
        return 'Paused';
    }

    if ( exists ($StateData{$num}) )
    {
        return $StateData{$num};
    }
    return "Unknown:$num";
}

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=head1 NAME

dstatus - Display Daemon Status

=head1 SYNOPSIS

  jats dstatus [options]

 Options:
    -help              - brief help message
    -help -help        - Detailed help message
    -man               - Full documentation
    -repeat=num        - Repeat display every n seconds
    -short             - Fold up inactive releases
    -short -short      - Supress inactive releases
    -color             - Pretty color display
    -rtag=num[,num]    - List of RTAG Ids to display
    -filter            - Display GBE_BUILDFILTER
    -dead=num          - Set DeadTime Threshold

=head1 OPTIONS

=over 8

=item B<-help>

Print a brief help message and exits.

=item B<-help -help>

Print a detailed help message with an explanation for each option.

=item B<-man>

Prints the manual page and exits.

=item B<-repeat=num>

This option will cause the program to re-display the status page every B<num>
seconds. The default option is to display the status once and exit.

If the user specifies a repeat time of less than 10 seconds, then it will be set
to 10 seconds - to avoid heavy loads on the Release Manager database.

This option works best with -color on a non-windows console as the screen
will be cleared before the display is refreshed.

=item B<-short>

This option will generate a short display. The body of inactive releases will
not be displayed. This option is useful in conjunction with a repeating display
to limit the display space used.

If B<-short> is used twice then the header for inactive releases will also
be supressed.

=item B<-color>

This option will enable a colored display. This will not work on Windoes.
The default is for a non-colored display.

=item B<-rtag=num[,num]>

This option will limit the display to the specified rtag Id's (Numeric Release ID).
This option can be used multiple times to specify a list, or the ID's can be comma seperated.

The default option is to display all Releases.

=item B<-filter>

This optionwill alter the display such that the GBE_BUILDFILTER for each platform
is displayed instead of the normal status information. This may result in a very
wide display.

=item B<-dead=num>

This option alters the B<Set DeadTime Threshold>. If a deamon has not
communicated with the Release Manager Database within this time, then the daemon
may be dead and will be flagged in the shortened displays.

The default value is 600 seconds.

=back

=head1 DESCRIPTION

This program will display the status of the build daemons on all daemon enabled
releases.

=cut