Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

assert - checking up on other scripts

by sflitman (Hermit)
on Jul 22, 2010 at 06:45 UTC ( #850783=CUFP: print w/replies, xml ) Need Help??

So...I have a temperature log running on a secure room at my day job. I foolishly commented out its cronjob while working on its script, and left it commented out, so I missed some data points. Ouch, mea culpa, back to the Perl drawing board. I hacked up this little script to sit in the crontab and run periodically to make a 'shell assertion' that a particular file is up to date, and to email if not. I used Safe to provide some security for the supplied expression and also provided a little quoting for the file. If the email is left out, it just prints when it fails, and if the email is 'result', it prints what the expression evaluates to.

#!/usr/bin/perl # script: assert # SSF 072110 tests a perl expression (like a file test) and emails you + if false # Copyright (C) 2010 Xenoscience - released under GPLv3 - All rights r +eserved use strict; use warnings; use vars qw/$cmdMail $host/; use LWP::MediaTypes qw(guess_media_type read_media_types); use MIME::Entity; use Safe; BEGIN { $cmdMail='/usr/lib/sendmail'; # location of your sendmail $host=`whoami`.'@'.`hostname`; # who am I read_media_types('/etc/mime.types'); # location of your mime.types + file } sub sendmail { # returns undef or error my ($from,$to,$subject,$body,@attachments)=@_; my $ret; my $top=build MIME::Entity From => $from, 'Reply-to' => $from, To => $to, Subject => $subject, Data => $body; if (@attachments) { for my $path (@attachments) { my $type=guess_media_type($path); $top->attach( Path => $path, Type => $type, Encoding => '-SUGGEST' ); } } $top->sync_headers(Length=>'COMPUTE') if @attachments; if (open(MAIL,"| $cmdMail -t -i")) { $top->print(\*MAIL); close MAIL; } else { $ret="Mail to $to failed: $!"; } $ret; } my ($expr,$file,$email,$msg)=@ARGV; die "usage: assert 'expr' [file|1] [email] [message]\n" unless $expr; $file||=1; $expr=~s/:f:/q{$file}/g; my $cpt=Safe->new('eval_safe'); # only one dungeon $cpt->permit(':filesys_read'); my $value=$cpt->reval($expr); die "eval_safe { $expr }:\n$@\n" if $@; if ($email=~/result/i) { my $result=defined $value ? $value : 'undef'; print "$expr evaluated to $result\n"; } unless ($value) { $msg||="{ $expr } is false"; if ($email=~/[@]/) { my $err=sendmail($host,$email,'Assertion failed',$msg); die $err if $err; } else { print $msg,"\n"; } } exit;

and the cronjob that invokes it
# ASSERTIONS - sanity checks 38 23 * * * assert '-r :f: && -M :f: < 1.0' /home/admin/www/templog/ +index.htm 'Check the templog!'
All comments greatly appreciated!


Replies are listed 'Best First'.
Re: assert - checking up on other scripts
by moritz (Cardinal) on Jul 22, 2010 at 09:09 UTC

    It seems all of that code could be avoided if you had a proper deployment system.

    I foolishly commented out its cronjob while working on its script, and left it commented out, so I missed some data points.

    That's the problem: You edit stuff on a production machine.

    Here's my understanding on how things should go:

    • You have a source repository for the script
    • You have a test suite for the script
    • When you need to do a change, you do it on your local developement machine, and run the test suite
    • When you're convinced that your changes are good, you check them in
    • You check out the new version on the production system. The process of checking out should be only a few seconds, no need to disable any cron job
    • For additional safety, you can install hooks in your version control system that prevent check-ins that make the test suite fail

    Maybe I misunderstood what you're doing, but it seems you're only adding layers of sanity checks for non-existing deployment solutions. See also: Technical debt.

    Perl 6 - links to (nearly) everything that is Perl 6.
      Thank you, I am going to have to adopt your methodology. I have been a one-man shop for too long and need to modernize. Which version control system would be best? I've used Subversion a little.


        I personally prefer git (or any decentralized version control system) over svn, but it's a bit hard to get started with.

        Any version control system will be much better than none, though.

        Perl 6 - links to (nearly) everything that is Perl 6.
Re: assert - checking up on other scripts
by mojotoad (Monsignor) on Jul 22, 2010 at 08:11 UTC
    The less you have to put into a crontab, the better. There's no reason to pass code fragments into a script via command line, much less an automated one.

    You're on the right track, however, by generalizing the problem and anticipating future uses for your notification script.

    The larger problem you're confronting is three things:

    1. detect
    2. select
    3. deliver

    Once you have removed the liver from your selected recipients, your task is complete.

    Seriously, though. Break the tasks down and, if not put them into their own modules, at least put them into their own subroutines.

    For example, rather than passing code fragments into your script via command line, use a hash for dispatching to the correct test routine; that way you can pass a parameter called "day_stale" and not worry about the quarantine and sanitization of arbitrary code.

    Finally, why not consider the unix way of things? If find -ctime 1 myfilename comes up empty, your file has been dead for a day.


      Thank you for your insights, that makes a lot of sense.
      (I have also wondered why deliver doesn't mean 'de-liver')

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://850783]
Approved by Corion
Front-paged by Arunbear
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2017-04-23 09:28 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (430 votes). Check out past polls.