#cron #jobs #container #user #run #lxc #pid

bin+lib lxcrond

cron and entr/inotify server for lxc containers

2 releases

0.2.1 Apr 8, 2020
0.2.0 Apr 8, 2020

#2 in #lxc

GPL-3.0-only

49KB
1K SLoC

lxcrond - cron for lxc containers

Features

  • Single binary, statically compiled with musl for easy lxc deployment.

  • No requirement for a shell.

  • No external deps, neither sendmail nor syslog.

  • Run deamon as root, jobs run as a lower privileged users.

  • No special editor, or reloading of files.

  • Also an entr/inotify replacement or simple ESB to detect and process incoming files.

  • Can be used as a cron library in rust code.

  • Generates a pid file so can be configured in lxinitd with service /run/lxcrond.pid /sbin/lxcrond

    let cron = Cron::new(some_jobs); std:๐Ÿงต:spawn(move|| { cron.run(); });

File format

full syntax

Single file /etc/lxcrontab is read on start up, unless a different file is specified with -c.

Normal cron format as per /etc/crontab except the command is not a bash line. it is command, plus optionally " quoted args.

# m   h  dom mon dow  user       command
23  1  *   *   *      teknopaul  /usr/bin/linci admin "backup"

Supports all *, & a list of values 5,10,15

Supports standard aliases @daily etc per busybox, and a few others.

Supports absolute file name, if the file is changed or created run the job.

# path                       user       command
/mnt/cipublish/nginx.conf    root       /bin/update-nginx

Support absolute directories, if a file arrives the job is run. The job should delete or move the files or it may get re-run every 60 seconds

# path             user       command
/mnt/uploads       clam       /bin/scan-uploads

Usage

Usage: lxcrond [options]

Options:
-c, --config [conf_file]
                    specify config file, default is /etc/lxcrontab
-h, --help          print this help menu
-v, --verbose       print debug information to stdout
-V, --version       print version number and exit
-f, --filesystem-watch 
                    use filesystem polling every 60 seconds to handle file jobs instead of inotify

If there are no jobs to run lxcrond exits.

Software design

Main loop syncs to run once every 60 seconds at :00, then ask is "now" the time to run any job. File operations use the Linux kernels inotify interface, or as a fallback, checks directories every 60 seconds.

Time considerations

There are many caveats to working with time in computers this program takes a simple approach that presumes time jumps are for a reason that the owner of the machine understands without making presumptions.
If the system time jumps more than one minute its possible that jobs do not fire because that time "did not happen" on this machine. If time jumps backwards jobs may fire twice because that time "happened twice".
Provided time jumps are significantly less than 60 seconds no funny stuff should happen, ntpd ensures time is kept in sync without large time jumps. Thus, if you set a cron to run at 23 12 * * * every day the job will run at 12:23:00, provided that time or any time up to 12:23:59 actually happens on this machine when the main loop triggers.
Main loop triggers once every 60 seconds. This duration time is determined by the same clock that can be manipulated as interpreted by Rust. Rust does a significant amount of interpretation of the system time when considering Duration: specifically it attempts to ensure that Durations do not occur twice, no matter how skewed the system clock is.
see Struct std::time::Instant
If the system is very heavily loaded or the process is excessively niced it is possible that the time happens but no code runs when the time happens.
Time now is calculated once per loop, so if any job runs with a given time spec all jobs withe same time spec are guaranteed to run, even on a very heavily loaded system, so the risk that jobs themselves consume 100% of CPU is mitigated.

TimeZone considerations

N.B. all times are local time. Jobs run in the current timezone so if you travel with a laptop and switch timezones, jobs may not fire or may fire twice.

Daylight Savings considerations

Some times happen twice in the same day if you are unfortunate enough to live in a timezone that does daylight saving. Busybox crond handles this by not re-firing jobs if the time jumps by one hour, lxcrond does not do that. This means you can schedule jobs to run every 5 mins and they will run correctly on daylight savings days.

inotify considerations

If files are polled with inotify there are various caveats, most significantly directories are not polled recursively. There are many other details to inotify that can cause jobs not to run, see man 7 inotify.

TODO see .later

Bugs see .later

LXC considerations

If compiled with cargo build --release --target=x86_64-unknown-linux-musl the only dependencies of this program are the config file /etc/lxcrontab and /etc/passwd.
/etc/passwd is required to determine the user for executing jobs. lxcrond will not continue if /ect/passwd can not be read to avoid accidentally running scripts with no $HOME or and unexpected pwd.

Build

By default make builds with cargo and the musl target for to install this target run

rustup target add x86_64-unknown-linux-musl
make
make deb
make install

author

(c) teknopaul 2020

Dependencies

~4โ€“5.5MB
~85K SLoC