Tivoli Tools and Utilities

Below are two scripts developed by MKAdvantage to help with an ITM deployment.  The first updates the time dimension for ITM and the other helps with log cleanup.  DISCLAMER:  The material contained in this page is presented "as is" without warranty. 

#!/usr/bin/perl
#
# create-time-dimension-sql.pl
#
#    Bryan A. Ignatow
#    MKAdvantage, Inc.
#    May/June 2011
#
#    Create the SQL statement to update the ITM TERM Time Dimension.
#    An example statement looks like:
#
#    CALL IBM_TRAM.CREATE_TIME_DIMENSION('2010-12-31-00.00.00.000000',
#                        '2012-12-31-00.00.00.000000', 60);
#
#    This statement is passed to the db2 command for execution.
#
#    The start time is fixed, and the end time will be calculated as
#    18 months from the current date.  This is expected to be run
#    once a month to extend the time dimension a month at a time.
#
#
use DateTime;

#
# Constants
#    StartDate: The starting date of the Time Dimension range
#    MonthIncrement: The number of months to increment from the current date
#
my $StartDate = '2010-12-31-00.00.00.000000';
my $MonthIncrement = 18;
my $SQLStatementTemplate = 'CONNECT TO WAREHOUS\nCALL IBM_TRAM.CREATE_TIME_DIMENSION(\'%s\', \'%s\', 60);';


#
# Variables
#
my ($dt, $EndDate, $SQLStatement);


#
# create a DateTime object set to the current date and time,
# with no particular timezone
#
$dt = DateTime->now( time_zone => 'floating' );


#
# Add 18 months
#
$dt->add( months => $MonthIncrement );


#
# Print the future date
#
$EndDate = sprintf("%d-%02d-%02d-00.00.00.000000",
           $dt->year, $dt->month, $dt->day);


#
# Construct the SQL Statement and print it
#
$SQLStatement = sprintf($SQLStatementTemplate, $StartDate, $EndDate);
print($SQLStatement);


#
# End of file
#


Here is the next script which does log file cleanup

#!/usr/bin/perl
#
# itm-log-cleanup.pl
#
#    Bryan A. Ignatow
#    MKAdvantage, Inc.
#    May/June 2011
#
#    Handle the special rotation of ITM log files that have unique names.
#
#    Check all *.inv files in the ITM logs directory and if file associated
#    with the last line in the file has a modification time in the last day,
#    remove any other files as listed in the file that have modifcations
#    times older than 30 days ago.
#
#    This script can be run from the command line or executed as part
#    of other log rotation (like under Redhat Enterprise Linux / CentOS):
#
#    /etc/logrotate.d/itm:
#        /opt/IBM/ITM/logs/candle_installation.log /opt/IBM/ITM/logs/kpacma.log {
#            missingok
#            notifempty
#            weekly
#            rotate 4
#            compress
#            postrotate
#                /usr/local/bin/itm-log-cleanup.pl 2> /dev/null || true
#            endscript
#        }
#
#
use strict;
use warnings;
use DateTime;
use File::stat;
use Time::localtime;


#
# Constants
#    ITMLogs: Log directory to search
#    FileAgeCheck: The number of hours old the last file line has to be
#    FilePurgeLimit: The minimum number of days old a file to be deleted is
#
my $ITMLogDir = '/opt/IBM/ITM/logs';
my $FileAgeCheck = 24;
my $FilePurgeLimit = 30;


#
# Variables
#
my ($dt, $agecheckdt, $purgelimitdt);
my ($invfile, @invfiles, $logfile, $linecount, %logfiles);
my ($lastfile, $modtime, $filedt, %keepfiles, $canpurge, @purgelist, %invmod);
my (@knownlist);
my ($printflag, $filemode, $fileuid, $filegid);


#
# Create a DateTime object set to the current date and time,
# with no particular timezone.  Then create two comparison times
# for the age of the current file (last line) and the age of the
# purlimit limit.  We're not concerned if they are a second or so
# different since we are dealing with hours and days.
#
$dt = DateTime->now();
$agecheckdt = DateTime->now->subtract( hours => $FileAgeCheck );
$purgelimitdt = DateTime->now->subtract( days => $FilePurgeLimit );


#
# Get the list of *.inv files to work
#
foreach $invfile (<$ITMLogDir/*.inv>) {
    push(@invfiles,$invfile);
}


#
# For each *.inv file, get the lines (which are filenames)
#
if ($#invfiles == -1) {
    warn "Warning: No log inventory files found in $ITMLogDir";

} else {
    %logfiles = ();
    foreach $invfile (@invfiles) {
        $linecount = 1;

        open(INVFILE, "<$invfile") ||
            die "Error: Unable to open log inventory file $invfile\n$!";
        while ($logfile = <INVFILE>) {
            chomp($logfile);
            $logfiles{$invfile}{$linecount++} = $logfile;
        }

        close(INVFILE);
    }
}


#
# For each *.inv file, check the date of the last file and if ok, check
# to see which files we will be purging (if any).
#
@purgelist = ();
%invmod = ();
foreach $invfile (@invfiles) {
    $lastfile = 1;
    $canpurge = 1;
    $invmod{$invfile} = 0;
    foreach $linecount (sort {$a<=>$b} keys %{$logfiles{$invfile}}) {
        #
        # If file exists - check dates and build keep hash & purge list
        #
        if (-f $logfiles{$invfile}{$linecount}) {
            #
            # Get file modification time
            #
            $modtime = stat($logfiles{$invfile}{$linecount})->mtime;
            $filedt = DateTime->from_epoch( epoch => $modtime );


            #
            # If this is the latest file, check its mod time
            #
            if ($lastfile) {
                #
                # If mod time is older than the age check date
                # don't purge any files from this INV file.
                #
                if (DateTime->compare($filedt, $agecheckdt)
                    == -1) {
                    $canpurge = 0;
                }

                $lastfile = 0;
                $keepfiles{$invfile}{$linecount} =
                    $logfiles{$invfile}{$linecount};


            #
            # If this is an older file and we are purging files in
            # this INV file
            #
            } elsif ($canpurge) {
                #
                # If mod time is older than the purge check
                # date, then add this file to the purge list
                #
                if (DateTime->compare($filedt, $purgelimitdt)
                    == -1) {
                    push(@purgelist,
                         $logfiles{$invfile}{$linecount});
                    $invmod{$invfile} = 1;


                #
                # Otherwise, keep it
                #
                } else {
                    $keepfiles{$invfile}{$linecount} =
                        $logfiles{$invfile}{$linecount};
                }


            #
            # Otherwise, just put it back on the keep hash
            #
            } else {
                $keepfiles{$invfile}{$linecount} =
                    $logfiles{$invfile}{$linecount};
            }


        #
        # If file does not exist - ignore and move on
        #
        } else {
            warn "Warning: File $logfiles{$invfile}{$linecount} does not exist\n";
        }
    }
}


#
# Look for files that have been orphaned from the INV files or are loosely
# associated with them.
#
foreach $invfile (@invfiles) {
    #
    # Build a list of log files we know about for this INV file
    #
    @knownlist = ();
    foreach $linecount (sort {$a<=>$b} keys %{$logfiles{$invfile}}) {
        push(@knownlist,$logfiles{$invfile}{$linecount});
    }


    #
    # Get a list of all files matching the pattern of the INV file name
    # and look for ones that we don't know about.
    #
    if ($invfile =~ /(\S+)\.inv$/) {
        foreach $logfile (<$1_*.log>, <$1_*.pid*>) {
            #
            # If the file we have is not in the known list,
            # check its mod time
            #
            if (not(grep { $_ eq $logfile } @knownlist)) {
                $modtime = stat($logfile)->mtime;
                $filedt = DateTime->from_epoch( epoch => $modtime );
                #
                # If mod time is older than the purge limit date
                # then nothing appears to be actively writing
                # to this log file, so we add it to the purge
                # list.
                #
                                if (DateTime->compare($filedt, $purgelimitdt)
                                    == -1) {
                    push(@purgelist, $logfile);
                }
            }
        }

    } else {
        warn "Warning: Unexpected filename format for INV file: $invfile\n";
    }
}


#
# Remove the files on the purge list
#

$printflag = 0;
print "\n\nFiles being kept:\n";
foreach $invfile (@invfiles) {
    #
    # If the INV file was modified, output the new results
    #
    if ($invmod{$invfile}) {
        if ($printflag) {
            print "\n\t$invfile :\n";

        } else {
            $printflag=1;
            print "\t$invfile :\n";
        }

        $filemode = sprintf("%04o",stat($invfile)->mode & 07777);
        $fileuid  = stat($invfile)->uid;
        $filegid  = stat($invfile)->gid;
        print "\t\t(Mode $filemode, UID $fileuid, GID $filegid)\n";

        open(INVFILE, ">$invfile") ||
            die "Error: Unable to open the INV file $invfile for writing\n$!";

        foreach $linecount (sort {$b<=>$a} keys %{$keepfiles{$invfile}}) {
            print "\t\t$keepfiles{$invfile}{$linecount}\n";
            print INVFILE "$keepfiles{$invfile}{$linecount}\n";
        }

        close (INVFILE);
        chmod (oct($filemode), $invfile);
        chown ($fileuid, $filegid, $invfile);


    #
    # Otherwise do nothing, since we don't need to write out the same
    # file we read in
    #
    } else {
        if ($printflag) {
                        print "\n\t$invfile (Unmodified)\n";

        } else {
            $printflag=1;
             print "\t$invfile (Unmodified)\n";
        }
    }
}


print "\n\nFiles being removed (" . ($#purgelist+1) . "):\n";
foreach $logfile (@purgelist) {
    print "\t$logfile\n";
    unlink($logfile);
}


#
# End of file
#