cwrap.py(1)

NAME
cwrap.py - A cron job wrapper used to suppress output

SYNOPSIS
cwrap.py [options] (command [cmd-arg [cmd-arg ...]] | 'command [cmd-arg [cmd-arg ...]]')

DESCRIPTION
"Obviously, you're not a golfer". But you are probably a sysadmin.

The cwrap.py script is meant to be used as a wrapper for cron jobs. The idea here is that you use this script to wrap whatever would be a normal cronjob for you to perform functions based on what options are specified. I think this is best explained with an example.

I have a cronjob that runs every minute. First, I don't want "overlap", a second instance is run while the first one is still running, if a single run takes a long time. Solved. The nature of my cronjob (just a script that is being run) is such that there will be an occasional failure, but an occasional failure, in this case, can be ignored. Instead, I only want to know when the script has failed 5 times in a row. Solved. By default, cwrap.py will also swallow all the output for the occasional fails, but I at least want a record of those failures so that I can determine whether the intermittent fails are happening more frequently and constitute a different problem. Solved (by turning on the syslog option).

This script may not be useful for everyone, but for some out there, it will save you a lot of time, effort and probably emails in your inbox.

See the EXAMPLE section for a short example

FAILURES
The concept of a failure is simple. The exit code of the script that cwrap.py is running must be non-zero for cwrap.py to call it a "failure".

OPTIONS

  General Options

-h, --help
    display a short help

-V,--version
    Print the version number and exit [default: False]

  State Options

-d PATH, --state-directory=PATH
    The directory to write the state file to. There is a state file created for each command-line that cwrap.py is running. This specifies the directory to create those in. [default: /var/tmp]

-F FILE, --lock-file=FILE
    Set a specific lock file to use. This is useful when running 2 different scripts, or the same script with different command-line opts, that cannot run at the same time. By default, a lock file will be automatically generated. [default: <auto-gen lockfile>]

  Retry Options

-r INT, --num-retries=INT
    The number of times to retry this if a previous instance is running. The script will retry every "-s" seconds if this is greater than zero. This, like all the retry options, only pertains to retries of cwrap.py when it encounters a lock file. The default here is not to retry at all, and instead just die. [default: 0]

-s INT, --retry-seconds=INT
    This is the number of seconds between retries. This only matters if the --num-retries option is set to greater than zero. [default: 10]

-i, --ignore-retry-fails
    Ignore the failures which occur because this tried to run while a previous instance was still running. Basically, an error will not be printed if the --num-retries are exceeded. The default behavior is to treat this as a failure. [default: False]

  Failure Options

-n INT, --num-fails=INT
    The number of consecutive failures that must occur before a report is printed. The behavior of cwrap.py can be set to store all of the failures until this number is reached. At that point, all of the consecutive failures will be printed. [default: 1]

-f, --first-fail
    The default is to print a failure report only when a multiple of the --num-fails threshold is reached. If this is set, a report will also be printed on the first failure. Note that this really only matters if you set the --num-fails greater than 1. [default: False]

  Command Options

-p CMD_PATH, --path=CMD_PATH
    Use this for command path instead of the environment $PATH. This will be set to the environment PATH of whatever user is running this, or whatever the PATH variable is set to in your crontab.

-g, --single-string
    This says that you are passing in a command line as a single string. This means that the entire command (with args) MUST be encased in quotes! This is handy if you want to encapsulate a pipe ("|") in your command to be run:

"cat /tmp/file | grep stuff"

That would be passed directly, as a string, to a subshell for execution. This allows for a lot of flexibility in how you use this. By default, the command is interpretted as it is "seen". [default: False]

-t INT, --timeout=INT
    The number of seconds to allow the your command to run before terminating. Set to zero to disable timeouts. This is the length of time that cwrap.py will allow the command to run before cwrap.py terminates it. The default is to let it run forever. [default: 0]

-q, --quiet
    Only output error reports. If this is set and the command runs successfully, nothing will be printed, even if the command had stdout or stderr output. The default is to print any output from the command. If you are only interested in error output, just set this. [default: False]

  Syslog Options

-S, --syslog
    Turn on syslogging. This will log all failures to syslog. This is useful for diagnosing intermittent issues that don't necessarily reach the --num-fails limit. See -C and -P for facility and priority options [default: False]

-C FACILITY, --syslog-facility=FACILITY
    The syslog facility to use. See the facility section in man syslog for a list of choices. You must use --syslog with this. [default: LOG_LOCAL7]

-P PRIORITY, --syslog-priority=PRIORITY
    Sets the priority for the syslog messages. See the level section in man syslog for a list of choices. You must use --syslog with this. [default: LOG_INFO]

-O, --num-fails-only
    Only log an item when the number of failures is reached. Normally, all failures are logged, but you can use this option to only write to syslog only when --num-fails is reached [default: False]

  Email Options

-M, --send-mail
    Send an email from within cwrap itself. This option is *required* if you wish to use the email options below. Any other email options will be ignored if this option is not specified. Note that this can be used with -N to disable normal output and just use cwrap to send an email [default: False]

-N, --suppress-normal-output
    Suppress the normal output to STDOUT that would normally cause crond to send an email. This can *only* be specified if you are using cwrap to send an email ( -M ). [default: False]

-E EMAIL_ADDR, --email-from=EMAIL_ADDR
    The email address to use as the sending address. It is advised that you set this to a non-default as the default will be your user at localhost.localdomain

-R EMAIL_ADDR, --email-recipient=EMAIL_ADDR
    The recipient(s) to send the email to. This options can be specified multiple times to send to multiple addresses.

-J SUBJECT, --email-subject=SUBJECT
    The subject of the email to be sent [default: cwrap.py failure report]

-X HOSTNAME|IP, --smtp-server=HOSTNAME|IP
    The SMTP server to use to send the email. If this option is not set, the local "sendmail" command will be used instead. Note that the sendmail command must be in your PATH!

-T INT, --smtp-port=INT
    The SMTP port to use [default: 25]

-L, --ssl
    Use SSL for the SMTP server connection

-Z, --starttls
    Use STARTTLS during the SMTP server connection

-U USERNAME, --smtp-username=USERNAME
    An SMTP username to use for auth SMTP.

-W PASSWORD, --smtp-password=PASSWORD
    A password to use with -U for auth SMTP. It is recommended that you use -D instead and set tight read permissions on the creds file. This is generally preferred instead of specifying a username and password on the command-line.

-D FILE, --smtp-creds-file=FILE
    This is recommended instead of specifying a username and password on the command-line when using authenticated SMTP to send email. That way you can set read only access for the user running cwrap and not have to expose the username and password. All you should have in your creds. file is: USERNAME:PASSWORD

EXAMPLE
Here is a short example of how you would run a cron job with cwrap.py.

For the purpose of this example, we'll say that the normal cronjob is run as

cron.sh -a do_stuff

Let's say that we always want to see the first failure in a string of failures (-f). Beyond the first failure, we don't want to be notified until the 10th consecutive failure (-n 10). This script can take a while to run so I want any other runs to retry two times (-r 2), but if it wasn't able to run because another instance was running, I don't want to hear about it (-i). I also don't want to see any normal output from it, but just when it fails (-q). I also want all errors to be logged to syslog (-S) under LOCAL1 (-C LOG_LOCAL1).

On top of that, I want to send an email to (-R bob@example.com) and (-R susie@example.com) with the same output that is going to the configure cron email address. To do that we specify that we will send an email from cwrap itself (-M) and we are going to connect to the local relay server to send the email (-X 192.168.0.2) with the subject set to a custom string (-J "widget failure detected") and this will have the sender email address set (-E widget@example.com) and finally, we will do all of this securely with STARTTLS (-Z). Here would be the example:

cwrap.py -fSiqMZ -n 10 -r 2 -C LOG_LOCAL1 -R bob@example.com \
    -R susie@example.com -J "widget failure detected" \
    -E widget@example.com -X 192.168.0.2 cron.sh -a do_stuff

AUTHOR
Jay Deiman (admin (at) splitstreams.com)

http://stuffivelearned.org

SEE ALSO
cron(8), crontab(1), crontab(5), syslog(3)