(file) Return to util.pm CVS log (file) (dir) Up to [Development] / JSOC / proj / workflow

File: [Development] / JSOC / proj / workflow / util.pm (download)
Revision: 1.1, Tue Aug 6 22:26:42 2013 UTC (9 years, 4 months ago) by arta
Branch: MAIN
CVS Tags: Ver_LATEST, Ver_9-5, Ver_9-41, Ver_9-4, Ver_9-3, Ver_9-2, Ver_9-1, Ver_9-0, Ver_8-8, Ver_8-7, Ver_8-6, Ver_8-5, Ver_8-4, Ver_8-3, Ver_8-2, Ver_8-12, Ver_8-11, Ver_8-10, Ver_8-1, HEAD
Fix some bugs - orbit and hlzsaa were switched in one place; there was a space in a redirection clause, which resulted in a 1 being appended to a command line; pass in the orbit series name, not the fds series name, to ingestIrisOrbit.pl; was searching through the fds series for an obsdate instead of obsdate_index (use timeslot to get the index value); add the unit field to the ingested keyword.

#!/home/jsoc/bin/linux_x86_64/activeperl

package WriteLog;

use strict;
use warnings;
use Data::Dumper;
use POSIX qw(strftime);

sub new
{
    my($clname) = shift;
    my($fname) = shift;
    my($append) = shift;
    my($mode);

    my($self) =
    {
        _fname => undef,
        _fh => undef
    };

    bless($self, $clname);

    if (defined($fname) && length($fname) > 0 && -e $fname)
    {
        my($fh);
        
        if (defined($append) && $append != 0)
        {
            $mode = ">>";
        }
        else
        {
            $mode = ">";
        }

        if (defined(open($fh, ">$fname")))
        {
            $self->{_fname} = $fname;
            $self->{_fh} = $fh;
        }
        else
        {
            print STDERR "Invalid file path.\n";
            $self = undef;
        }
    }
    else
    {
        print STDERR "Invalid file path.\n";
        $self = undef;
    }

    return $self;
}

sub DESTROY
{
    my($self) = shift;

    $self->close();
}

sub Write
{
    my($self) = shift;
    my($msg) = shift;
    my($nodate) = shift;
    
    my($now);
    my($timestr);
    
    if (!defined($nodate) || $nodate == 0)
    {
        # Start the line with a timestamp
        $now = localtime();
        $timestr = POSIX::strftime("%B %d, %Y [%H:%M:%S %z]", localtime());
        print $self->{_fh} "$timestr"; # Does not end in newline.
        
        if (defined($msg) && length($msg) > 0)
        {
            print $self->{_fh} " - ";
        }
    }

    if (defined($msg && length($msg) > 0)
    {
        print $self->{_fh} "$msg\n";
    }
    else
    {
        print $self->{_fh} "\n";
    }
}

sub Close
{
    my($self) = shift;
    
    if (defined($self->{_fh}))
    {
        $self->{_fh}->close();
        $self->{_fh} = undef;
    }
}

package Cfg;

use strict;
use warnings;

sub new
{
    my($clname, $src, $log) = @_;
    my($self) = 
    {
        _hash => {},
        _log => undef
    };
    
    bless($self, $clname);
    
    if (-e $src)
    {
        # config source is a file
        my($cfg);
        my($cfgH) = {};
        
        if ($self->ParseCFile($src, $cfgH))
        {
            if (defined($log))
            {
                $log->Write("Unable to open configuration file $src.");
            }
            else
            {
                print STDERR "Unable to open configuration file $src.\n"; 
            }
            
            $self = undef;
        }
        else
        {
            $self->{_hash} = $cfgH;
        }
    }
    else
    {
        # config source is a hash array
        $self->{_hash} = $src;
    }
    
    $self->{_log} = $log;
        
    return $self;
}

sub DESTROY
{

}

sub Get
{
    my($self) = shift;
    my($name) = shift;

    if (exists($self->{_hash}->{$name}))
    {
        return $self->{_hash}->{$name};
    }
    else
    {
        if (defined($self->{_log}))
        {
            $self->{_log}->Write("Unknown configuration argument '$name'.");
        }
        else
        {
            print STDERR "Unknown configuration argument '$name'.\n";
        }
        
        return undef;
    }
}

sub ParseCFile
{
    my($self, $conf, $hashref) = @_;
    my(@cfgdata);
    my(%cfgraw);
    my(%cfg);
    my($rv);
    
    $rv = 0;
    
    if (open(CNFFILE, "<$conf"))
    {
        @cfgdata = <CNFFILE>;
        
        # Make key-value pairs of all non-ccomment lines in configuration file.                                             
        %cfgraw = map {
            chomp;
            my($key, $val) = m/^\s*(\w+)\s*=\s*(.*)/;
            defined($key) && defined($val) ? ($key, $val) : ();
        } grep {/=/ and !/^#/} @cfgdata;                                                                                    
            
            close(CNFFILE);
            
            # Expand in-line variables in arguments                                                                             
            %cfg = map {
                my($val) = $cfgraw{$_};
                my($var);
                my($key);
                my($sub);
                
                while ($val =~ /(\${.+?})/)
                {
                    $var = $1;
                    $key = ($var =~ /\${(.+)}/)[0];
                    $sub = $cfgraw{$key};
                    
                    if (defined($var) && defined($sub))
                    {
                        $var = '\${' . $key . '}';
                        $val =~ s/$var/$sub/g;
                    }
                }
                
                ($_, $val);
            } keys(%cfgraw);
        }
        else
        {
            if (defined($self->{_log}))
            {
                $self->{_log}->Write("Unable to open configuration file '$conf'.");
            }
            else
            {
                print STDERR "Unable to open configuration file '$conf'.\n";
            }
            
            $rv = 1;
        }
        
        if ($rv == 0)
        {
            # everything is AOK - copy %cfg to referenced hash array                                                            
            my($hkey);
            my($hval);
            
            foreach $hkey (keys(%cfg))
            {
                $hval = $cfg{$hkey};
                $hashref->{$hkey} = $hval;
            }
        }
        
        return $rv;
    }

package Gate;

use strict;
use warnings;

use constant kStateFNextUpdate   => "nextupdate";
use constant kStateFUpdateDelta  => "updatedelta";
use constant kStateFType         => "type";
use constant kStateFActionTask   => "actiontask";
use constant kStateFGateStatus   => "gatestatus";
use constant kStateFProduct      => "product";
use constant kStateFStatusTask   => "statustask";
use constant kStateFLow          => "low";
use constant kStateFHigh         => "high";

sub new
{
    my($clname, $gatesdir, $gatesubdir, $log) = @_;
    my($self) =
    {
        _name => undef,
        _gatedir => undef,
        _log => undef,
        _nextupdate => undef,
        _updatedelta => undef,
        _type => undef,
        _actiontask => undef,
        _gatestatus => undef,
        _product => undef,
        _statustask => undef,
        _low => undef,
        _high => undef,
        _orig => undef, # The original state that existed when the object was created.
        _tickets => undef
    };
    my($fh);
    
    bless($self, $clname);
    
    if (defined($log))
    {
        $self->{_log} = $log;
    }
    
    if (defined($gatedir) && -d $gatedir)
    {
        # Gate Identification 
        $self->{_name} = $gatesubdir;
        $self->{_gatedir} = "$gatesdir/$gatesubdir";
        
        # Read the contents of all state files.
        $self->LoadState();
        
        # There are additional state files, but they are not accessed by the Gatekeeper (coverage_args, gate_name, key, project, sequence_number).
    }
    else
    {
        $self->WriteLog("Invalid gate directory $gatedir.");
        $self = undef;
    }
    
    return $self;
}
    
sub DESTROY
{
    my($self) = @_;
    my(@tickets);
    
    # Must flush out to state files, if attributes have changed.
    if ($self->{_nextupdate} ne $self->{_orig}->{_nextupdate})
    {
        # NextUpdate is a time string.
        $self->WriteContent(&kStateFNextUpdate, $self->{_nextupdate});
    }
    if ($self->{_updatedelta} != $self->{_orig}->{_updatedelta})
    {
        # UpdateDelta is a number of seconds.
        $self->WriteContent(&kStateFUpdateDelta, $self->{_updatedelta});
    }
    if ($self->{_type} ne $self->{_orig}->{_type})
    {
        # Type is a string (the value could be numeric, but it could also be a string).
        $self->WriteContent(&kStateFType, $self->{_type});
    }
    if ($self->{_actiontask} ne $self->{_orig}->{_actiontask})
    {
        # ActionTask is the name of a script/program, which is a string.
        $self->WriteContent(&kStateFActionTask, $self->{_actiontask});
    }
    if ($self->{_gatestatus} ne $self->{_orig}->{_gatestatus})
    {
        # GateStatus is a string.
        $self->WriteContent(&kStateFGateStatus, $self->{_gatestatus});
    }
    if ($self->{_product} ne $self->{_orig}->{_product})
    {
        # Product is a DRMS data series, which is a string.
        $self->WriteContent(&kStateFProduct, $self->{_product});
    }
    if ($self->{_statustask} ne $self->{_orig}->{_statustask})
    {
        # StatusTask is the name of a script/program, which is a string.
        $self->WriteContent(&kStateFStatusTask, $self->{_statustask});
    }
    
    # Low/High - In general, these state files are updated by the status scripts. But the Gatekeeper
    # itself will set these values on ocassion. The Gatekeeper and the status scripts will read
    # both of these too. So, we better make sure that there is no possibility that the Gatekeeper 
    # does ANYTHING while the status scripts are running. Otherwise, there could be a race condition.
    if ($self->{_low} ne $self->{_orig}->{_low})
    {
        # StatusTask is the name of a script/program, which is a string.
        $self->WriteContent(&kStateFLow, $self->{_low});
    }
    if ($self->{_high} ne $self->{_orig}->{_high})
    {
        # StatusTask is the name of a script/program, which is a string.
        $self->WriteContent(&kStateFHigh, $self->{_high});
    }
    
    # Flush tickets back to disk.
    @tickets = keys(%{$self->{_tickets}});
    foreach my $ticketname (@tickets)
    {
        $ticketO = $self->{_tickets}->{$ticketname};
        $ticket->Flush();
    }
    $self->{_tickets} = undef;
    
    if (defined($self->{_log}))
    {
        $self->{_log} = undef;
    }
}

# Class methods
    
# Member methods
sub LoadState
{
    my($self, $attrib) = @_;
    
    if (defined($attrib) && length($attrib) > 0)
    {
        $self->{"_" . $attrib} = self->ReadContent($attrib);
        
        # Save the original state so we can check for changes when flushing to disk.
        $self->{_orig}->{"_" . $attrib} = $self->{"_" . $attrib};
    }
    else
    {
        $self->{_nextupdate} = $self->ReadContent(&kStateFNextUpdate);
        $self->{_updatedelta} = $self->ReadContent(&kStateFUpdateDelta);
        $self->{_type} = $self->ReadContent(&kStateFType);
        $self->{_actiontask} = $self->ReadContent(&kStateFActionTask);
        $self->{_gatestatus} = $self->ReadContent(&kStateFGateStatus);
        $self->{_product} = $self->ReadContent(&kStateFProduct);
        $self->{_statustask} = $self->ReadContent(&kStateFStatusTask);
        $self->{_low} = $self->ReadContent(&kStateFLow);
        $self->{_high} = $self->ReadContent(&kStateFHigh);
        
        # Save the original state so we can check for changes when flushing to disk.
        $self->{_orig} = {};
        $self->{_orig}->{_nextupdate} = $self->{_nextupdate};
        $self->{_orig}->{_updatedelta} = $self->{_updatedelta};
        $self->{_orig}->{_type} = $self->{_type};
        $self->{_orig}->{_actiontask} = $self->{_actiontask};
        $self->{_orig}->{_gatestatus} = $self->{_gatestatus};
        $self->{_orig}->{_product} = $self->{_product};
        $self->{_orig}->{_statustask} = $self->{_statustask};
        $self->{_orig}->{_low} = $self->{_low};
        $self->{_orig}->{_high} = $self->{_high};
    }
}
    
sub Reload
{
    my($self, $attrib) = @_;
    
    $self->LoadState($attrib);
}
    
sub WriteLog
{
    my($self, $msg) = @_;
    
    if (defined($self->{_log}))
    {
        $self->{_log}->Write($msg);
    }
    else
    {
        print STDERR "$msg\n";
    }
}
    
sub ReadContent
{
    my($self, $statefID) = @_;
    my($sfile) = $self->{_gatedir} . "/"  . $statefID;
    my($fh);
    my($content);

    if (defined(open($fh, "<$sfile")))
    {
        $content = <$fh>;
        $fh->close();
    }
    else
    {
        $self->WriteLog("Unable to open state file $sfile for reading.");
    }
    
    return $content;
}
    
sub WriteContent
{
    my($self, $statefID, $content) = @_;
    
    my($sfile) = $self->{_gatedir} . "/"  . $statefID;
    my($fh);

    if (defined(open($fh, ">$sfile")))
    {
        print $fh $content;
        $fh->close();
    }
    else
    {
        $self->WriteLog("Unable to open state file $sfile for writing.");
    }
}
    
sub OnHold
{
    my($self) = @_;
    
    return ($self->{_gatestatus} =~ /^\s*hold\s*$/i);
}
    
sub Name
{
    my($self) = @_;
    
    return $self->{_name};    
}
    
sub Get
{
    my($self, $attrib) = @_;
    
    return $self->{"_$attrib"};
        
}

sub Set
{
    my($self, $attrib, $val) = @_;
    
    if (exists($self->{"_$attrib"}))
    {
        $self->{"_$attrib"} = $val;
    }
    else
    {
        $self->WriteLog("Unknown gate attribute $attrib.");
    }
}
    
sub ProcessTickets
{
    my($self) = @_;
    
    my($ticketO);
    
    # Load ticket state. First I have to figure out what state is needed by the Gatekeeper
    
    # Create the ticket objects
    foreach my $ticketname (@tickets)
    {
        $ticketO = new Ticket();
        $task = $ticketO->DoTask();
        
        if (!defined($task))
        {
            # Fatal error.
        }
        
        $self->{_tickets} = $ticketO;        
        
    }
}

    
    
package JSOCTime;

use strict;
use warnings;
use DateTime qw(compare);
use DateTime::Format::Strptime;

# Static funcctions
sub Compare
{
    my($t1) = shift;
    my($t2) = shift;
    
    return DateTime->compare($t1, $t2);
}
    
# Non-static member functions
sub new
{
    my($clname) = shift;
    my($str) = shift;
    my($pattern) = shift;
    
    my($self) =
    {
        _dt => undef # a DateTime object
    };
    
    bless($self, $clname);
    
    my($strp) = new DateTime::Format::Strptime(pattern => '$pattern', locale => 'en_US', time_zone => 'UTC');
    
    if (defined($strp))
    {
        my($dt) = $strp->parse_datetime($str);
        
        if (defined($dt))
        {
            $self->{_dt} = $dt;
        }
        else
        {
            $self = undef;
        }
    }
    else
    {
        $self = undef;
    }
    
    return $self;
}
    
sub Copy
{
    my($self) = @_;
    my($classname);
    my($new) =
    {
        _dt => DateTime->from_object(object => $self->{_dt});
    };
    
    $classname = ref($self);

    bless($new, $classname);
    
    return $new;
}
    
sub Cmp
{
    my($self, $other) = @_;
    
    return DateTime->compare($self->{_dt}, $other->{_dt});
}
    
sub GT
{
    my($self, $other) = @_;
    
    my($cmp) = $self->Cmp($other);
    
    return ($cmp == 1);
}
    
sub Add
{
    my($self, $seconds) = @_;
    
    $self->{_dt}->add(DateTime::Duration->new(seconds => $seconds));
}

# Returns the time-string representation of the member DateTime object.
sub TimeString
{
    my($self) = @_;
    
    return $self->{_dt}->strftime("%Y.%m.%d_%H:%M:%S_%Z");
}

Karen Tian
Powered by
ViewCVS 0.9.4