Software Audit

Description of software-audit.pl


#!/usr/bin/perl -w

#
# submit-audit.pl -- Submit a Software Audit to Rush
#
# Name          Vers Date       Comments
# Greg Ercolano 1.00 08/06/08 - Initial implementation
# xxx           x.xx xx/xx/xx - xxx
#
# (C) Copyright 2008, 2016 Seriss Corporation. All Rights Reserved.
# Do not remove this header or copyright notice. You may use and change
# this software for internal use, but may not re-distribute it.
# If you make changes, please add your name/version/date to the list
# above using the format shown.
#

use strict;
$|=1;
umask(0);
Start of program.

Here we enforce perl's strict syntax checking, make sure output is unbuffered ($|=1), and set the umask to zero, to prevent unix permission problems for the files we create.


### MODIFIABLE VARIABLES: START ####

my $audit_file = "//meade/net/tmp/software-audit.txt";    # output audit file
my $audit_log  = "//meade/net/tmp/software-audit.log";    # error logs
Change these to be appropriate paths on your file server.
software-audit.txt is where the resulting audit info gets written.
software-audit.log is a directory that will contain the Rush frame logs.


### SOFTWARE TO AUDIT -- MODIFY TO TASTE 
my %soft =
(
    ############
    ### MAYA ###
    ############
    "maya2008x64" =>
    {
        "win" => "c:/Program Files/Autodesk/Maya2008-x64",
	"osx" => "",
    },
    "maya2008" =>
    {
        "win" => "c:/Program Files/Autodesk/Maya2008",
	"osx" => "/Applications/Autodesk/maya2008",
    },
    "maya8.5x64" =>
    {
        "win" => "c:/Program Files/Autodesk/Maya8.5-x64",
	"osx" => "",
    },
    "maya8.5" =>
    {
        "win" => "c:/Program Files/Autodesk/Maya8.5",
	"osx" => "/Applications/Autodesk/maya8.5",
    },
    "maya8.0" =>
    {
        "win" => "c:/Program Files/Alias/Maya8.0",
	"osx" => "/Applications/Alias/maya8.0",
    },

    ###############
    ### AFTERFX ###
    ###############
    "AE-CS3" =>
    {
        "win" => "c:/Program Files/Adobe/After Effects CS3",
	"osx" => "/Applications/Adobe After Effects CS3",
    },
    "AE-7.0" =>
    {
        "win" => "c:/Program Files/Adobe/After Effects 7.0",
	"osx" => "/Applications/Adobe After Effects 7.0",
    },
    "AE-6.5" =>
    {
        "win" => "c:/Program Files/Adobe/After Effects 6.5",
	"osx" => "/Applications/Adobe After Effects 6.5",
    },

    # ETC..
);

### MODIFIABLE VARIABLES: END ####

Change these to specify the software applications and directories to check for.

The format of this section is perl hash syntax, which should be
in the form of:

    "app_name" =>
    {
        "platform_1" => "/some/path/platform_1",
	"platform_2" => "/other/path/platform_2",
    },
You can specify as many app_names and platforms as you like.

All paths specified will be tested on each machine; if any match,
an 'X' will appear in the software-audit.txt file's column for that 'app_name'.



# SUBMIT
if ( ! defined($ARGV[0]) ) {
    $G::self = $0; $G::self =~ s%\\%/%g;    # \\foo\x -> //foo/x

    # PREVENT 'NETWORK WORM' STYLE RECURSION
    if ( defined($ENV{RUSH_ISDAEMON}) ) { exit(1); }     

    # CREATE LOGDIR
    if ( ! -d $audit_log ) {
        unless(mkdir($audit_log, 0777)) {
            print STDERR "mkdir $audit_log: $!\n"; exit(1);
        }
    }

    # CREATE AUDIT FILE
    unless(open(AUDIT, ">$audit_file"))
        { print STDERR "ERROR: $audit_file: $!\n"; exit(1); }
    print AUDIT "*** SOFTWARE AUDIT ***\n\n";

    # CREATE COLUMN HEADINGS
    print AUDIT sprintf("%-16s ", "Hostname");
    foreach my $name ( sort ( keys(%soft) ) )
	{ print AUDIT "$name "; }
    print AUDIT "\n";
    print AUDIT "-"x16 . " ";
    foreach my $name ( sort ( keys(%soft) ) )
        { print AUDIT "-"x(length($name))." "; }
    print AUDIT "\n";
    close(AUDIT);

    # DEBUG
    #   system("cat $audit_file");
    #   exit(0);

    # SUBMIT JOB
    unless( open(SUBMIT, "|rush -submit") )
        { print STDERR "rush -submit: $!\n"; exit(1); }
    print SUBMIT <<"EOF";
    title       SOFTWARE_AUDIT
    ram         1
    frames      1-500
    logdir      $audit_log
    command     perl $0 -render
    cpus        +any=10.1\@1
EOF
    close(SUBMIT);

    # Non-zero exit indicates submit failed
    if ( $? >> 8 ) 
        { print STDERR "--- Submit failed\n"; exit(1); }   # Submit Failed
    exit(0);                                               # Submit OK
}
This section submits the job.

It handles creating the log directory if it doesn't exist, clearing out the audit log's previous data by truncating it, and writing new column headers at the top.

Later on, when the script runs on the machines, they will append their findings to the audit log in whatever order the machines are available.


# RENDERING ON REMOTE MACHINE?
if ( $ARGV[0] eq "-render" ) {
    print "--- Working on frame host $ENV{RUSH_HOSTNAME}\n";

    # REMOVE THIS HOST FROM JOB (SO IT DOESN'T RUN AGAIN)
    system("rush -an $ENV{RUSH_HOSTNAME} -fu");

    # BUILD AN AUDIT LINE FOR THIS MACHINE
    my $out = sprintf("%-16.16s ", $ENV{RUSH_HOSTNAME});
    foreach my $name ( sort( keys(%soft) ) )
    {
        my $found = 0;
        foreach my $path ( sort ( keys( %{ $soft{$name} } ) ) )
        {
            if ( $soft{$name}{$path} ne "" && -d $soft{$name}{$path} )
	        { $found = 1; }
        }
	$out .= sprintf("%-*s ", length($name), ($found==1 ? "X" : "-"));
    }
    $out .= "\n";

    # APPEND LINE TO AUDIT FILE WITH SINGLE "ATOMIC WRITE"
    unless(open(AUDIT, ">>$audit_file"))
        { print STDERR "ERROR: $audit_file: $!\n"; exit(1); }
    else
        { syswrite(AUDIT, $out, length($out)); close(AUDIT); }
    print "--- DONE\n";
    exit(0);
}
This is the section that runs on each machine.

The first thing it does is add this machine's hostname to the job's 'neverhost' list so that this machine doesn't try to run the script again. (We only want to run once on each machine)

Next, the script checks all the paths you specified to see if they exist. Any that do, it puts an "X" in that column.

Finally, the constructed line is "appended" to the audit log using a single atomic write operation, which should ensure the data doesn't get "intermingled" with data being written concurrently by other machines.