daemon: Implement 'test_variables'.
[whenjobs.git] / tools / whenjobs.pod
1 =encoding utf8
2
3 =head1 NAME
4
5 whenjobs - A powerful but simple cron replacement
6
7 =head1 SYNOPSIS
8
9 Editing the jobs script:
10
11  whenjobs -e | --edit
12  whenjobs -l | --list
13
14 Get and set variables:
15
16  whenjobs --get variable
17  whenjobs --set variable=value [variable=value ...]
18  whenjobs --variables
19
20 Start and stop the per-user daemon:
21
22  whenjobs --daemon-start
23  whenjobs --daemon-stop
24  whenjobs --daemon-status
25  whenjobs --daemon-restart
26
27 Examine running jobs:
28
29  whenjobs --jobs
30  whenjobs --cancel serial
31  whenjobs --start "name"
32  whenjobs --tail serial
33
34 =head1 DESCRIPTION
35
36 Whenjobs is a powerful but simple replacement for cron.  It lets you
37 run jobs periodically like cron, but it also lets you trigger jobs to
38 run when user-defined variables are set or change value.
39
40 Periodic jobs are written like this:
41
42  every 10 minutes :
43  <<
44    # Get the current load average.
45    load=`awk '{print $1}' /proc/loadavg`
46    whenjobs --set --type float load=$load
47  >>
48
49 When-statements let you create jobs that run based on variables set
50 elsewhere:
51
52  when load >= 6 :
53  <<
54    mail -s "ALERT: high load average: $load" $LOGNAME < /dev/null
55  >>
56
57 (When statements are "edge-triggered", meaning that this job will only
58 run when the load goes from under 6 to E<ge> 6).
59
60 Like L<crontab(5)>, whenjobs are controlled by a jobs file which can
61 be edited from the command line:
62
63  $ whenjobs -e
64
65 Whenjobs uses a daemon called L<whenjobsd(8)>.  Unlike crond, this
66 daemon runs as the same user.  Each user who wants to use whenjobs
67 starts their own daemon:
68
69  $ whenjobs --daemon-start
70
71 You can also have the daemon start as you when the machine boots by
72 adding the following line to a boot file such as C</etc/rc.local>.
73 Replace C<username> with your username:
74
75  su username -c /usr/sbin/whenjobsd
76
77 Variables are the key to expressing dependencies between whenjobs.
78 Variables are stored (per-user) in the daemon.  You can use the
79 command line tool to examine and set variables:
80
81  $ whenjobs --variables
82  load=0.9
83  $ whenjobs --set cat=sushi
84  $ whenjobs --get cat
85  sushi
86
87 The act of setting a variable (using I<--set>) can trigger jobs to run.
88
89 =head1 OPTIONS
90
91 =over 4
92
93 =item B<--cancel> serial
94
95 Cancel the job with the given serial number.
96
97 Use I<--jobs> to list running jobs along with their serial numbers.
98 The serial number is also available in the job script (as
99 C<$JOBSERIAL>) and in the log file.
100
101 =item B<--daemon-start>
102
103 =item B<--daemon-stop>
104
105 Start and stop the per-user daemon.
106
107 =item B<--daemon-status>
108
109 Prints the status of the daemon: C<up> or C<down>.
110
111 =item B<--daemon-restart>
112
113 Restart the daemon.  (If it is not running, then this command
114 starts it).
115
116 =item B<-e>
117
118 =item B<--edit>
119
120 Edit the jobs script.  If you make changes to the jobs script, then it
121 is automatically uploaded to the daemon.
122
123 The C<$EDITOR> environment variable is used for editing.  If not set,
124 C<vi> is used.
125
126 =item B<--get> variable
127
128 Print the value of a variable.
129
130 =item B<--job-names>
131
132 List the names of all loaded jobs (whether they are running or not).
133 Use I<--jobs> to list running jobs.
134
135 =item B<--jobs>
136
137 List all running jobs.
138
139 Note that it is possible for the same job to be running more than once
140 (for example, a periodic job that takes longer than the period to run).
141
142 =item B<-l>
143
144 =item B<--list>
145
146 List the jobs script.
147
148 =item B<--lib> directory
149
150 Set the library directory which needs to contain the auxiliary files
151 C<pa_when.cmo> and C<whenlib.cma>.  Normally you do not need to
152 specify this.  However if you are running whenjobs without installing
153 it, then you need to point this to the C<lib/> directory from the
154 source, eg:
155
156  whenjobs --lib $builddir/lib -e
157
158 =item B<--set> variable=value [variable=value ...]
159
160 =item B<--type> bool|int|float|string|unit
161
162 I<--set> sets the variable named C<variable> to the new C<value>.  The
163 variable is created if it does not already exist.  Note that setting a
164 variable can cause jobs to run immediately.
165
166 To unset a variable, set it to the empty string like this:
167
168  whenjobs --set var=
169
170 By default variables are strings.  You can also set the type of a
171 variable when setting it by adding the optional I<--type> parameter.
172 The I<--type> parameter should come I<before> the variable
173 declaration, like this:
174
175  whenjobs --set --type int free_space=10000
176
177 See the discussion of variable types in the L</REFERENCE> section
178 below.
179
180 You can set multiple variables.  When setting multiple variables in a
181 single command, the values are all changed in a single atomic
182 operation.
183
184  whenjobs --set cat=sushi food=fish
185
186 When using I<--type> and multiple variables, the type changes the
187 remaining command line parameters until the next I<--type>, eg:
188
189  whenjobs --set cat=sushi --type float weight=3.5 --type string food=fish
190
191 (C<cat> and C<food> are strings, and C<weight> is a float).
192
193 =item B<--start> "job name"
194
195 Start the job immediately and unconditionally.
196
197 This runs the job even if its normal preconditions are not met.  This
198 may cause unexpected results, so use with caution.
199
200 =item B<--tail> serial
201
202 Tail the output of the running job identified by its serial number.
203 Use the I<--jobs> flag to get a list of running jobs.
204
205 =item B<--upload>
206
207 Compile the jobs script and upload it to the daemon, without editing.
208 Note that the I<--edit> option does this automatically.  Furthermore,
209 when the daemon is started it checks for a jobs script and loads it if
210 found.
211
212 =item B<--variables>
213
214 Display all the variables and their values, in the format C<name=value>.
215
216 =item B<-V>
217
218 =item B<--version>
219
220 Display the name and version of the program and exit.
221
222 =item B<-help>
223
224 =item B<--help>
225
226 Display brief usage and exit.
227
228 =back
229
230 =head1 REFERENCE
231
232 A whenjobs file consists of a series of one or more "every" or "when"
233 statements.
234
235 Comments in the file can be written using C<(* ... *)>.  Comments
236 may be nested.
237
238 Shell script fragments are written using C<E<lt>E<lt> ... E<gt>E<gt>>.
239 Within shell script fragments, use C<#> for comments (as in ordinary
240 shell scripts).  Because C<E<gt>E<gt>> has a special meaning, it
241 cannot be used in the shell script (ie. for redirection).  You have to
242 write C<E<gt>\E<gt>> instead which is replaced with C<E<gt>E<gt>> when
243 the shell script is parsed.
244
245 =head2 EVERY STATEMENTS (PERIODIC JOBS)
246
247 An every statement has the form:
248
249  every <period> :
250  <<
251    # shell script
252  >>
253
254 where C<E<lt>periodE<gt>> is a I<period expression>, which may take
255 one of the forms below.  Don't forget the colon character between the
256 period expression and the shell script.
257
258 An every statement is a job which runs periodically.
259
260 =head3 PERIOD EXPRESSIONS
261
262 =over 4
263
264 =item B<every second>
265
266 The job runs every second.
267
268 =item B<every minute>
269
270 The job runs every minute.
271
272 =item B<every hour>
273
274 The job runs every hour.
275
276 =item B<every day>
277
278 The job runs every day, at midnight UTC.
279
280 =item B<every week>
281
282 The job runs every week, on a Thursday at midnight UTC.
283
284 =item B<every month>
285
286 The job runs every month, on the first of the month at midnight UTC.
287
288 =item B<every year>
289
290 The job runs every year, on the first day of the year at midnight UTC.
291
292 =item B<every decade>
293
294 =item B<every century>
295
296 =item B<every millenium>
297
298 The job runs every 10, 100 or 1000 years.
299
300 =item B<every I<N> seconds>
301
302 The job runs every I<N> seconds (I<N> is any number E<ge> 1).
303
304 =item B<every I<N> minutes>
305
306 The job runs every I<N> minutes.
307
308 =item B<every I<N> hours>
309
310 The job runs every I<N> hours.
311
312 =item B<every I<N> days>
313
314 The job runs every I<N> days.
315
316 =item B<every I<N> weeks>
317
318 The job runs every I<N> weeks.
319
320 =item B<every I<N> months>
321
322 The job runs every I<N> months.
323
324 =item B<every I<N> years>
325
326 =item B<every I<N> decades>
327
328 =item B<every I<N> centuries>
329
330 =item B<every I<N> millenia>
331
332 The job runs every I<N>, I<10*N>, I<100*N> or I<1000*N> years.
333
334 =back
335
336 =head2 WHEN STATEMENTS (DEPENDENT JOBS)
337
338 A when statement has the form:
339
340  when <expr> :
341  <<
342    # shell script
343  >>
344
345 where C<E<lt>exprE<gt>> is a I<when expression>, described below.
346 Don't forget the colon character between the period expression and the
347 shell script.
348
349 A when statement is a job which runs when the conditions described in
350 its when-expression become true.
351
352 When jobs are I<edge triggered>.  This means that they run when the
353 condition changes from false to true (or in the case where the
354 expression has not been evaluated before, when it evaluates initially
355 to true).
356
357 =head3 WHEN EXPRESSIONS
358
359 When expressions are fully recursive expressions constructed from the
360 following elements:
361
362 =over 4
363
364 =item I<expr> B<&&> I<expr>
365
366 =item I<expr> B<||> I<expr>
367
368 The boolean "and" or "or" of the two sub-expressions.
369
370 =item I<expr> B<E<lt>> I<expr>
371
372 =item I<expr> B<E<lt>=> I<expr>
373
374 =item I<expr> B<==> I<expr>
375
376 =item I<expr> B<E<gt>=> I<expr>
377
378 =item I<expr> B<E<gt>> I<expr>
379
380 The two sub-expressions are evaluated and the usual comparison
381 operator is performed.
382
383 If the sub-expressions are numeric, then numeric comparison is done.
384 If either sub-expression is non-numeric, then both expressions are
385 converted (if necessary) to strings and string comparison is done.
386
387 =item B<!> I<expr>
388
389 Boolean negative of I<expr>.
390
391 =item I<expr> B<+> I<expr>
392
393 For numeric sub-expressions, this performs addition.
394
395 If both sub-expressions are strings, this performs string
396 concatenation.
397
398 Other types give an error.
399
400 =item I<expr> B<-> I<expr>
401
402 =item I<expr> B<*> I<expr>
403
404 =item I<expr> B</> I<expr>
405
406 =item I<expr> B<mod> I<expr>
407
408 Both sub-expressions are evaluated, and if both are numeric, then the
409 result is subtraction, multiplication, division or modulo.
410
411 Other types give an error.  Note that I<mod> really is an infix
412 operator.
413
414 =item B<len> I<expr>
415
416 If I<expr> is a string, this returns the length of the string.
417
418 =item I<variable>
419
420 The value of the named variable.
421
422 Previously undefined variables are automatically initialized to the
423 empty string.
424
425 =item B<prev> I<variable>
426
427 The I<previous> value of the named variable.  This means, the value
428 that it had last time this when-job ran.
429
430 If the when-job has not run yet, then this returns C<"">.
431
432 Job state is preserved across file reloads, but I<only> for jobs that
433 are explicitly named.  If you find that jobs using C<prev>, C<changes>
434 etc are running unnecessarily when the jobs file is edited or
435 uploaded, try giving the jobs an explicit name.
436
437 =item B<changes> I<variable>
438
439 If the named variable has changed since this job last ran, then this
440 evaluates to true, else false.
441
442 This is the same as writing C<prev variable == variable>.
443
444 =item B<increases> I<variable>
445
446 If the named variable has changed and increased since this job last
447 ran, then this evaluates to true, else false.
448
449 This is the same as writing C<prev variable E<lt> variable>.
450
451 =item B<decreases> I<variable>
452
453 If the named variable has changed and decreased since this job last
454 ran, then this evaluates to true, else false.
455
456 This is the same as writing C<prev variable E<gt> variable>.
457
458 B<Note:> There is a subtle gotcha with the I<decreases> operator: The
459 first time the expression is evaluated, the job has (by definition)
460 not yet run.  Therefore C<prev variable> evaluates to C<""> (see
461 definition of I<prev> above).  Since it is always true that
462
463  "" < anything
464
465 the I<decreases> operator evaluates to false, and since this usually
466 means the job does not run, the operator always evaluates to false.
467
468 To fix this, ensure that the variable is initialized (see
469 L</SETTING THE INITIAL VALUE OF VARIABLES> below).
470
471 =item B<reloaded ()>
472
473 This evaluates to true the first time the expression is evaluated
474 after the jobs file has been reloaded or the daemon restarted.
475 Thereafter it evaluates to false.
476
477 Don't use this to initialize variables: it won't do what you mean.
478
479 =item B<false>
480
481 =item B<true>
482
483 Constants that evaluate to boolean false or true respectively.
484
485 =item I<"any string">
486
487 Any string.
488
489 In a boolean context, the empty string evaluates to false, and
490 non-empty strings evaluate to true.
491
492 =item I<N>
493
494 Any integer.  (Arbitrarily large integers are supported.)
495
496 In a boolean context, 0 evaluates to false, and non-zero evaluates to
497 true.
498
499 =item I<N.>
500
501 =item I<.N>
502
503 =item I<N.N>
504
505 =item I<N.NeN>
506
507 Any floating point number.
508
509 In a boolean context, 0 evaluates to false, and non-zero evaluates to
510 true.
511
512 =back
513
514 =head2 SHELL SCRIPTS
515
516 The code between C<E<lt>E<lt> ... E<gt>E<gt>> is a shell script.  It
517 is executed using C<$SHELL>, or if that environment variable is not
518 set then C</bin/sh>.
519
520 =head3 SHELL SCRIPT VARIABLES
521
522 Every variable that has been set (using the whenjobs I<--set> option)
523 is exported to the script, so you can simply get the value of any
524 variable by writing C<$name>.
525
526 In addition, there are some special variables available:
527
528 =over 4
529
530 =item C<$JOBNAME>
531
532 The name of the job.  If the job has been named explicitly, then that
533 name is available through this variable, else it will be some implicit
534 name like C<job$1>.
535
536 =item C<$JOBSERIAL>
537
538 The serial number of the job.  This is simply a variable that
539 increments each time a job is run, and is unique to that run of the
540 job.
541
542 =back
543
544 Other environment variables such as C<$HOME>, C<$LOGNAME> etc are
545 available as normal.
546
547 =head3 SHELL SCRIPT TEMPORARY CURRENT DIRECTORY
548
549 The shell script runs with its current directory set to a temporary
550 directory.  The temporary directory is removed when the shell script
551 exits.  Therefore you can write temporary files here without worrying
552 about cleaning them up.
553
554 If you want to store permanent state, then you have to save it to a
555 well-known directory, eg. C<$HOME>, C</var> etc.
556
557 =head3 SHELL SCRIPT USER
558
559 The shell script runs as the ordinary user.  It has no special
560 privileges.
561
562 =head2 JOB NAMES
563
564 Jobs are given implicit names (C<job$1>, C<job$2> etc.).  You can also
565 name jobs explicitly by preceeding the "every" or "when" statement
566 with C<job "name">:
567
568  job "poll source"
569  every 10 seconds :
570  <<
571    # ...
572  >>
573
574 The job name is passed to the shell script in the C<$JOBNAME>
575 environment variable.
576
577 =head2 OCAML EXPRESSIONS
578
579 As well as simple "every" and "when" expressions, advanced users may
580 want to use arbitrary OCaml expressions, functions, etc in the jobs
581 script.  These are useful for factoring common code or strings, for
582 setting the initial values of variables, or for defining pre and post
583 functions.
584
585 A simple example of an OCaml expression is:
586
587  let prefix = "daily_"
588  
589  job (prefix ^ "virus_scan")
590  every day :
591  <<
592    # ...
593  >>
594  
595  job (prefix ^ "disk_check")
596  every day :
597  <<
598    # ...
599  >>
600
601 which creates two jobs called C<"daily_virus_scan"> and
602 C<"daily_disk_check"> (C<^> is the OCaml string concatenation
603 operator).
604
605 OCaml expressions have access to a library of functions called
606 B<Whentools> which is described below.  It lets you set variables,
607 create jobs algorithmically, etc.
608
609 The OCaml expressions run once, when the jobs file is being loaded or
610 reloaded.
611
612 =head3 SETTING THE INITIAL VALUE OF VARIABLES
613
614 Variables are created when they are referenced, and until set they
615 have the value empty string (just like the shell).  Across file
616 reloads, the previous values of variables are preserved.
617
618 To initialize a variable to a known value when the jobs file is
619 loaded, call one of the C<Whentools.set_variable*> functions as in
620 this example:
621
622  let () =
623    Whentools.set_variable "name" "Richard";
624    Whentools.set_variable_int "counter" 0
625
626 =head3 PRE FUNCTIONS
627
628 Before a job runs, you can arrange that a C<pre> function is called.
629 This function may decide not to run the job (by returning C<false>).
630
631 One use for this is to prevent a particular job from running if there
632 is already an instance of the same job running:
633
634  job "only one"
635  pre (Whentools.one ())
636  every 10 seconds :
637  <<
638    # Takes longer than 10 seconds to run, but 'Whentools.one ()'
639    # will ensure only one is ever running.
640    sleep 11
641  >>
642
643 When using pre functions, jobs must be given an explicit name, ie.
644 you must use the C<job> statement.
645
646 A number of pre functions are available in the library; see below.
647
648 You can also write your own post functions (in OCaml).  The function
649 is passed one argument which is a C<Whentools.preinfo> struct, defined
650 below.  It should return a boolean: C<true> if the job should run, and
651 C<false> if the job should not run.
652
653 Note that a fresh serial number (see L</JOBSERIAL>) is assigned to
654 each run, whether or not the job actually runs because of
655 preconditions.
656
657 =head3 POST FUNCTIONS
658
659 After a job runs, you can control what happens to its output by
660 writing a C<post> function.  To write a post function you have to
661 name the job (ie. have an explicit C<job> statement).  Put C<post ...>
662 after the job name like this:
663
664  job "poll source"
665  post (Whentools.mailto "you@example.com")
666  every 10 seconds :
667  <<
668    # ...
669  >>
670
671 A number of post functions are available in the library; see below.
672
673 You can also write your own post functions (in OCaml).  The
674 function is passed one argument which is a C<Whentools.result> struct,
675 defined below.
676
677 =head3 WHENTOOLS LIBRARY
678
679 =head4 Functions
680
681 =over 4
682
683 =item B<Whentools.mailto> [I<~only_on_failure:true>]
684 [I<~from:from_address>] I<email_address> I<result>
685
686 This built-in post function sends the result of the script by email to
687 the given email address.
688
689 If the optional C<~only_on_failure:true> flag is set, then it is only
690 sent out if the script failed.
691
692 If the optional C<~from> flag is set, then the from address is set
693 accordingly.  This is sometimes needed when sending mail.
694
695 Note the C<result> parameter is passed implicitly by the daemon.  You
696 do not need to add it.
697
698 Here are some examples of using the mailto function:
699
700  job "ex.1"
701  post (Whentools.mailto "you@example.com")
702  every 10 seconds :
703  <<
704    # do something
705  >>
706
707  job "ex.2"
708  post (Whentools.mailto ~only_on_failure:true
709                         "you@example.com")
710  every 10 seconds :
711  <<
712    # do something
713  >>
714
715  let from = "me@example.com"
716  let to_addr = "you@example.com"
717  
718  job "ex.3"
719  post (Whentools.mailto ~from to_addr)
720  every 10 seconds :
721  <<
722    # do something
723  >>
724
725 =item B<Whentools.max> I<n>
726
727 This built-in pre function ensures that a maximum of I<n> instances of
728 the job are running.
729
730 It checks the list of running jobs, and if I<n> or more instances are
731 already running, then it returns C<false>, which ensures that the new
732 job is not started.
733
734 =item B<Whentools.one> I<()>
735
736 This built-in pre function ensures that only one instance of the job
737 is running.  It is the same as calling:
738
739  Whentools.max 1
740
741 =item B<Whentools.set_variable> I<name> I<string>
742
743 Set variable I<name> to the string.
744
745 =item B<Whentools.set_variable_bool> I<name> I<b>
746
747 Set variable I<name> to the boolean value I<b>.
748
749 =item B<Whentools.set_variable_int> I<name> I<i>
750
751 Set variable I<name> to the integer value I<i>.
752
753 =item B<Whentools.set_variable_string> I<name> I<s>
754
755 Set variable I<name> to the string value <s>.  This is
756 the same as I<Whentools.set_variable>.
757
758 =item B<Whentools.set_variable_float> I<name> I<f>
759
760 Set variable I<name> to the floating point value I<f>.
761
762 =back
763
764 =head4 Structures
765
766 =over 4
767
768 =item B<Whentools.preinfo>
769
770 This structure is passed to pre functions.  It has the following
771 fields:
772
773  type preinfo = {
774    pi_job_name : string;           # Job name.
775    pi_serial : Big_int.big_int;    # Job serial number.
776    pi_variables : (string * variable) list; # Variables set in job.
777    pi_running : preinfo_running_job list;   # List of running jobs.
778  }
779  and preinfo_running_job = {
780    pirun_job_name : string;        # Running job name.
781    pirun_serial : Big_int.big_int; # Running job serial number.
782    pirun_start_time : float;       # Running job start time.
783    pirun_pid : int;                # Running job process ID.
784  }
785
786 =item B<Whentools.result>
787
788 This structure is passed to post functions.  It has the following
789 fields:
790
791  type result = {
792    res_job_name : string;  # job name
793    res_serial : big_int;   # job serial (same as $JOBSERIAL)
794    res_code : int;         # return code from the shell script
795    res_tmpdir : string;    # temporary directory script ran in
796    res_output : string;    # filename of stdout/stderr output
797    res_start_time : float; # when the job started
798  }
799
800 =back
801
802 =head1 FILES
803
804
805
806 =head1 ENVIRONMENT VARIABLES
807
808
809
810 =head1 SEE ALSO
811
812 L<whenjobsd(8)>
813
814 =head1 AUTHOR
815
816 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
817
818 =head1 COPYRIGHT
819
820 Copyright (C) 2012 Red Hat Inc.
821
822 This program is free software; you can redistribute it and/or modify
823 it under the terms of the GNU General Public License as published by
824 the Free Software Foundation; either version 2 of the License, or
825 (at your option) any later version.
826
827 This program is distributed in the hope that it will be useful,
828 but WITHOUT ANY WARRANTY; without even the implied warranty of
829 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
830 GNU General Public License for more details.
831
832 You should have received a copy of the GNU General Public License
833 along with this program; if not, write to the Free Software
834 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.