Package:Whenjobs

Revision as of 13:16, 24 June 2014 by Duncan.britton (Talk | contribs)

sys-process/whenjobs


Source Repository:Funtoo Overlay

Summary: A cron daemon replacement that is powerful, yet simple.


Whenjobs

Warning

This document is a work in progress, as we are still investigating whenjobs for funtoo usage. For information about it see Funtoo tickets about whenjobs, initscript, User Feedback and this document.

What are whenjobs?

Whenjobs was written by Richard Jones from RedHat Linux. Whenjobs is designed to be a cron daemon replacement with some improvements over normal cron-jobs. Further, we have added some improvements to Whenjobs. Whenjobs gives users a more simple syntax for jobs to run and, with Funtoo improvements, an effective user-management option for whenjobs -- that way we fixed the default behaviour of whenjobs to not been able to run as root and let us execute the daemon on a per-user basis by default.

Questions for help and testing

We would like to get your feedback to FL-338. So, please test and report your experience with whenjobs.

How to install whenjobs

The installation of sys-process/whenjobs is really easy, just merge it:

# emerge -avt whenjobs

How to get started

As mentioned above, we added a user-management feature. Also, whenjobs has a changed syntax compared to normal cronjobs -- we will discuss that now.

User management

The user management for whenjobs is done with a single file located at /etc/whenjobs.users.conf. Just add a user to that file by a comma seperated list like:

root,user1,user2,user3

where user1-user3 must be system-usernames, as they are checked. Please do not add any other lines to that file, as there is no way for comments in the file. In addition, adding other lines will break whenjobs -- you will not be able to start the daemon later. Currently, there is no initscript, but we are working on one and that initscript will then use that file in the same way.

whenjobs commands

There are some basic commands for whenjobs you should be aware of before we get to explain the script syntax for whenjobs:

To edit/list a job script, use:

# whenjobs -e | --edit
# whenjobs -l | --list

in the above case we added both the short and long version in one line so please use either the -e or the --edit version as there is no piping done at that part. We will use the same syntax for further examples if there are multiple ways of calling the function we need.

Another import part is to set or get variables we want to set or set in whenjobs, that can be done with:

to get a variable:
# whenjobs --get variable
to set a variable or multiple varibles:
# whenjobs --set variable=value [variable=value ...]
and to display all set variables:
# whenjobs --variables

Another important function in whenjobs is the way to start, stop and request the status of the per-user daemon:

# whenjobs --daemon-start
# whenjobs --daemon-stop
# whenjobs --daemon-status
# whenjobs --daemon-restart

Finally we have the ability to inspect running jobs:

# whenjobs --jobs
# whenjobs --cancel serial
# whenjobs --start "name"
# whenjobs --tail serial

How to get started with whenjobs now

First edit the above mentioned whenjobs.users.conf file if not already done and start a daemon on a per-user basis with

# whenjobs --daemon-start

Thats all for starting whenjobs and now we have time to write some whenjobs-scripts. We will use here some basic examples nothing for real time usage but it should be able to give you the impression on how to write your own scripts and use the variables in the later process. First we need to edit our whenjobs-script. This can be done by two ways:

Version A) (manual way, not recommended)
# EDITOR ~/.whenjobs/jobs.ml
Edit the file with the scripts you want to use and save it, but after that you need to upload it so that whenjobs knows about it
# whenjobs --upload
Version B) (automatically by whenjobs, recommended)
# whenjobs -e  | --edit
just save your script now and whenjobs will upload it automatically for you.

So far we are now fine with getting to the scripts, next let us add some basics. We will now start with a periodic call, like if we would like to check out load everyage every 10 minutes we would do it like this:

Warning

A note aside, the scripts are real shell scripts, so parts beginning with a # are comments and parts without are the shell script commands that are executed!

every 10 minutes :
<<
  # Get the current load average.
  load=`awk '{print $1}' /proc/loadavg`
  whenjobs --set --type float load=$load
>>

The power of whenjobs comes in game when you would like to base on a variable you set somewhere else:

when load >= 6 :
<<
  mail -s "ALERT: high load average: $load" MAILADDRESS < /dev/null
>>

That part will notify a user via email when his load average is greater or equal to 6, as when statements are "edge-triggered".

The --type switch above for setting a variable can be one of bool, int, float, string or unit

Periodic expressions

For periodic expressions you have to use the following syntax

every <period> :
<<
  # shell script
>>

where <period> is one of the following period expressions:

<period> Description Special <period> Description
second runs every second X seconds runs every X seconds
minute runs every minute X minutes runs every X minutes
hour runs every hour X hours runs every X hours
day runs every day, at midnight UTC X days runs every X days, at midnight UTC
week runs every week, on a Thursday at midnight UTC X weeks runs every X weeks, on a Thursday at midnight UTC
month runs every month, on the 1st at midnight UTC X months runs every X month, on the 1st at midnight UTC
year runs every year, on the 1/1 at midnight UTC X years runs every X years, on the 1/1 at midnight UTC
decade runs every 10 years X decades runs every X decades
century runs every 100 years X centuries runs every X centuries
millenium runs every 1000 years X millenia runs every X mellenia

When expressions

For dependent jobs you need to use the when-statements with the following syntax:

when <expr> :
<<
  # shell script
>>

where <expr> is a when expression. But don't forget the colon between periods expression or when expression and the shell script.

All in all you can say, that a when-expression is a job which runs, when the described conditions become true.

<expr> meaning <expr> meaning
expr && expr boolean "and" of the two sub-expressions  ! expr boolean negative of expr
expr || expr boolean "or" of the two sub-expressions expr + expr for numeric sub-expression, this performs addition, for strings it performs string concatenation, else it returns an error.
expr < expr evaluates sub-expressions and compares them with the operator expr - expr evaluates sub-expressions and if both are numeric uses operator on them else returns error
expr <= expr evaluates sub-expressions and compares them with the operator expr * expr evaluates sub-expressions and if both are numeric uses operator on them else returns error
expr == expr evaluates sub-expressions and compares them with the operator expr / expr evaluates sub-expressions and if both are numeric uses operator on them else returns error
expr >= expr evaluates sub-expressions and compares them with the operator expr mod expr evaluates sub-expressions and if both are numeric uses operator on them else returns error (infix operator)
expr > expr evaluates sub-expressions and compares them with the operator len expr returns the length of the string in expr
variable returns the value of named variable prev variable returns previous value of named variable
changes variable same as !(prev variabel == variable) increases variable same as prev variable < variable
decreases variable prev variable > variable reloaded () do not use it, it does not what you want (manpage warning)
false constant equals always false true constant equals always true
"any string" empty string in boolean = false, else equals true N any integer, boolean 0=false, non-zero=true
.N | N.N | N.NeN and floating point number, boolean 0=false, non-zero=true

shell scripts

The code between << ... >> is a simple shell script and is executed using $SHELL. If $SHELL is not set, it is executed with /bin/sh

available variable Description
$JOBNAME The name of the job. If the job has been named explicitly, then that name is available through this variable, else it will be some implicit name like job$1.
$JOBSERIAL The serial number of the job. This is simply a variable that increments each time a job is run, and is unique to that run of the job.
$HOME, $LOGNAME etc these are available as normal

The shell scripts run with its current directory set to an temporary directory, that is cleaned up automacically after the job exists. So you don't have to worry about cleaning them up later. If you would like to store some values permanently, save the files to a well-known directory, eg. $HOME, /var etc.

All shell scripts are executed as the ordinary user. They have no special privileges.

Job names

If you like to give a job a unique name use the following syntax:

job "JOBNAME"
every <period> :
<<
  # shell script
>>

OCAML expressions

You can also use OCAML expressions in the code. they are useful for factoring common code or strings, for example:

let prefix = "daily_"
 
job (prefix ^ "virus_scan")
every day :
<<
  # shell script
>>
 
job (prefix ^ "disk_check")
every day :
<<
  # shell script
>>
initial value of variables

Variables are empty until they first get set, you can set a default starting value for a variable if you like with the following code

let () =
  Whentools.set_variable "variable" "value";
  Whentools.set_variable_int "counter" 0
Pre functions

You can let arrange to run a pre function before a job runs. This function may decide to not run the job. One possible usage for that is the that you only want to have one job at time from the same job to run:

job "only one"
pre (Whentools.one ())
every <period> :
<<
  # shell script
>>
Post functions

The same is for stuff after a job has run. This is handled by the post function.

job "talk to me after finished"
post (Whentools.mailto "you@example.com")
every <period> :
<<
  # shell script
>>
Basic available Whentools functions
function Description
whentools.mailto [~only_on_failure:true] [~from:from_address] email_address result This built-in post function sends the result of the script by email to the given email address.

If the optional "~only_on_failure:true" flag is set, then it is only sent out if the script failed.

If the optional "~from" flag is set, then the from address is set accordingly. This is sometimes needed when sending mail.

Note the "result" parameter is passed implicitly by the daemon. You do not need to add it.

Here are some examples of using the mailto function:

job "ex.1"
post (Whentools.mailto "you@example.com")
every 10 seconds :
<<
   # shell script 1
>>
 
job "ex.2"
post (Whentools.mailto ~only_on_failure:true "you@example.com")
every 10 seconds :
<<
  # shell script 2
>>
 
let from = "me@example.com"
let to_addr = "you@example.com"
 
job "ex.3"
post (Whentools.mailto ~from to_addr)
every 10 seconds :
<<
  # shell script 3
>>
Whentools.max n This built-in pre function ensures that a maximum of n instances of the job are running.

It checks the list of running jobs, and if n or more instances are already running, then it returns "false", which ensures that the new job is not started.

Whentools.one () This built-in pre function ensures that only one instance of the job is running. It is the same as calling: Whentools.max 1
Whentools.set_variable name string Set variable name to the string
Whentools.set_variable_bool name b Set variable name to the boolean value b
Whentools.set_variable_int name i Set variable name to the integer value i
Whentools.set_variable_string name s Set variable name to the string value . This is the same as Whentools.set_variable
Whentools.set_variable_float name f Set variable name to the floating point value f

For the preinfo passed to the pre functions and results for the post functions have a view in the manpage.

Examples

Finally here are some examples to which questions came up, hope you find them helpful for your first own tries... :)

every 1 minute :
<<
  testtime=`date +%H%M`
  whenjobs --set --type int test=${testtime}
  whenjobs --set --type int runtime=0016
>>
 
when test == 0017 :
<<
  echo `date` >\> ~/test.log 
>>
 
when test == runtime
<<
  whenjobs --get runtime >\> ~/test.log
>>

The above whenjobs have the need to run each day at a specific time, so we show you here two ways of doing it.

First we define a variable test for whenjobs based on the date with the HHMM output what would for example result in 0017 for 12:17am and 1428 for 2:28pm. then in the first when expression we test if our variable equals 0017 and if yes it runs, the second version is to define a second variable called runtime and then do like the second test does a test for it based on comparing both variables.

But now enough with that long doc, happy whenjobing for all of you... :)