1
0
Fork 0
mirror of https://github.com/yavook/kiwi-cron.git synced 2024-11-24 00:13:00 +00:00

Merge branch 'release/0.2.0'

This commit is contained in:
Jörn-Michael Miehe 2022-03-03 00:27:11 +01:00
commit 6f48f18c01
8 changed files with 81 additions and 69 deletions

View file

@ -1,4 +1,5 @@
FROM alpine:latest FROM alpine:latest
LABEL maintainer="jmm@yavook.de"
ENV TZ=Etc/UTC ENV TZ=Etc/UTC
@ -24,4 +25,4 @@ RUN set -ex; \
COPY bin /usr/local/bin/ COPY bin /usr/local/bin/
COPY libexec /usr/local/libexec/ COPY libexec /usr/local/libexec/
CMD [ "kiwi-cron" ] CMD [ "kiwi-cron" ]

View file

@ -14,6 +14,12 @@ Just drop your scripts into the relevant directory under `/kiwi-cron`, that's it
You will likely want to automate some tasks regarding your `docker` infrastructure. You will likely want to automate some tasks regarding your `docker` infrastructure.
That's why the `kiwi-cron` images package a current `docker-cli` you can just mount your `docker.sock` in its containers and use `docker` commands normally. That's why the `kiwi-cron` images package a current `docker-cli` you can just mount your `docker.sock` in its containers and use `docker` commands normally.
## Time Zones
`kiwi-cron` images include the `tzdata` package and automatically handle `/etc/localtime` on startup. By default, "Etc/UTC" is set as the container time zone.
To use a different time zone, change the container environment variable `TZ` to your liking, e.g. "Europe/Berlin".
## Simple jobs ## Simple jobs
On startup, `kiwi-cron` checks for possible job files in the `/kiwi-cron` directory structure. On startup, `kiwi-cron` checks for possible job files in the `/kiwi-cron` directory structure.
@ -21,27 +27,21 @@ On startup, `kiwi-cron` checks for possible job files in the `/kiwi-cron` direct
For each subdirectory, a random valid cron schedule is generated, so that: For each subdirectory, a random valid cron schedule is generated, so that:
- `/kiwi-cron/hourly` runs once every hour (random minute) - `/kiwi-cron/hourly` runs once every hour (random minute)
- `/kiwi-cron/daily` runs once every day (random nighttime value) - `/kiwi-cron/daily` runs once every day (random nighttime value between 9 pm and 3 am)
- `/kiwi-cron/weekly` runs once every weekend (random nighttime value on Saturday or Sunday) - `/kiwi-cron/weekly` runs once every weekend (random nighttime value on Saturday or Sunday)
- `/kiwi-cron/monthly` runs once every month (random nighttime value on a random day) - `/kiwi-cron/monthly` runs once every month (random nighttime value on a random day <= 28)
- `/kiwi-cron/yearly` and `/kiwi-cron/annually` runs once a year (random nighttime value on a random day in January or February) - `/kiwi-cron/yearly` and `/kiwi-cron/annually` runs once a year (random nighttime value on a random day <= 28 in January or February)
Cron schedules are regenerated once on each startup, only for directories that have files. Cron schedules are regenerated once on each startup, only for directories that have files.
## Time Zones ## Granularity: The `/kiwi-cron/every` directory
`kiwi-cron` images include the `tzdata` package and automatically handle `/etc/localtime` on startup. By default, "Etc/UTC" is set as the container time zone.
To use a different time zone, change the container environment variable `TZ` to your liking, e.g. "Europe/Berlin".
## Finer granularity: The `/kiwi-cron/every` directory
Directories like `/kiwi-cron/every/5_minutes` will run scripts every 5 minutes. Directories like `/kiwi-cron/every/5_minutes` will run scripts every 5 minutes.
`kiwi-cron` picks up on that format and generates valid `cron` schedules on startup. `kiwi-cron` picks up on that format and generates valid `cron` schedules on startup.
You can define schedules to be run every N minutes, hours, days, or months by creating the corresponding directories. This way, you can define schedules to be run every N minutes, hours, days, or months by creating the corresponding directories.
Scheduling for every N weeks (or years) doesn't work that way; jobs in those directories will instead be run every week (or every year). Scheduling for every N weeks (or years) doesn't work though; jobs in those directories will instead be run every week (or every year).
## Inspection ## Inspection

View file

@ -2,4 +2,4 @@
exec /usr/local/libexec/kiwi-cron/run_cron \ exec /usr/local/libexec/kiwi-cron/run_cron \
"${@}" \ "${@}" \
/usr/local/libexec/kiwi-cron/schedule_dirs /usr/local/libexec/kiwi-cron/scheduler

View file

@ -4,50 +4,29 @@ cs_every="${1:-1}"
cs_units="${2}" cs_units="${2}"
cs_command="${3}" cs_command="${3}"
if [ "${cs_every}" -eq 1 ]; then if [ "${cs_every}" = "1" ]; then
cs_every="" cs_every="*"
else else
cs_every="/${cs_every}" cs_every="*/${cs_every}"
fi fi
# generate valid random schedule values
# generally, "nighttime" and "weekend" will be preferred.
# shellcheck disable=SC3028 # RANDOM is defined in alpine's /bin/sh
cs_rand_min=$(( RANDOM % 60 ))
# shellcheck disable=SC3028
# cs_rand_hour=$(( RANDOM % 24 ))
cs_rand_hour=$(( (21 + RANDOM % 7) % 24 ))
# shellcheck disable=SC3028
cs_rand_day=$(( RANDOM % 31 + 1 ))
# shellcheck disable=SC3028
# cs_rand_weekday=$(( RANDOM % 7 ))
cs_rand_weekday=$(( (6 + RANDOM % 2) % 7 ))
# shellcheck disable=SC3028
# cs_rand_month=$(( RANDOM % 12 + 1 ))
cs_rand_month=$(( RANDOM % 2 + 1 ))
case "${cs_units}" in case "${cs_units}" in
minute) minute)
echo "*${cs_every}" "*" "*" "*" "*" "${cs_command}" echo "${cs_every} * * * * ${cs_command}"
;; ;;
hour) hour)
echo "${cs_rand_min}" "*${cs_every}" "*" "*" "*" "${cs_command}" echo "R ${cs_every} * * * ${cs_command}"
;; ;;
day) day)
echo "${cs_rand_min}" "${cs_rand_hour}" "*${cs_every}" "*" "*" "${cs_command}" echo "R R ${cs_every} * * ${cs_command}"
;; ;;
week) week)
echo "${cs_rand_min}" "${cs_rand_hour}" "*" "*" "${cs_rand_weekday}" "${cs_command}" echo "R R * * R ${cs_command}"
;; ;;
month) month)
echo "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "*${cs_every}" "*" "${cs_command}" echo "R R R ${cs_every} * ${cs_command}"
;; ;;
year) year)
echo "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "${cs_rand_month}" "*" "${cs_command}" echo "R R R R * ${cs_command}"
;; ;;
esac esac

View file

@ -1,28 +1,16 @@
#!/bin/sh #!/bin/sh
print_cron_schedule () {
pcs_minute="${1}"
pcs_hour="${2}"
pcs_day="${3}"
pcs_month="${4}"
pcs_weekday="${5}"
pcs_command="${6}"
printf '%-8s%-8s%-8s%-8s%-8s%s\n' \
"${pcs_minute}" "${pcs_hour}" "${pcs_day}" "${pcs_month}" "${pcs_weekday}" "${pcs_command}"
}
# header # header
echo '# crontab generated by kiwi-cron' echo '# crontab generated by kiwi-cron'
echo '# generation time: '"$(date)" echo '# generation time: '"$(date)"
echo '#' echo '#'
# short documentation line # short documentation line
print_cron_schedule \ printf '%-8s%-8s%-8s%-8s%-8s%s\n' \
"# min" "hour" "day" "month" "weekday" "command" "# min" "hour" "day" "month" "weekday" "command"
# schedules # schedules
while read -r pc_min pc_hour pc_day pc_month pc_weekday pc_command; do while read -r pc_minute pc_hour pc_day pc_month pc_weekday pc_command; do
print_cron_schedule \ printf '%-8s%-8s%-8s%-8s%-8s%s\n' \
"${pc_min}" "${pc_hour}" "${pc_day}" "${pc_month}" "${pc_weekday}" "${pc_command}" "${pc_minute}" "${pc_hour}" "${pc_day}" "${pc_month}" "${pc_weekday}" "${pc_command}"
done done

View file

@ -0,0 +1,25 @@
#!/bin/sh
# shellcheck disable=SC3028 # RANDOM is defined in alpine's /bin/sh
read -r rs_minute rs_hour rs_day rs_month rs_weekday rs_command
[ "${rs_minute}" = "R" ] && \
rs_minute=$(( RANDOM % 60 ))
[ "${rs_hour}" = "R" ] && \
rs_hour=$(( (21 + RANDOM % 6) % 24 )) # prefer nighttime
# rs_hour=$(( RANDOM % 24 )) # don't prefer nighttime
[ "${rs_day}" = "R" ] && \
rs_day=$(( RANDOM % 28 + 1 )) # don't mess with February 31st
[ "${rs_month}" = "R" ] && \
rs_month=$(( RANDOM % 2 + 1 )) # prefer January & February
# rs_month=$(( RANDOM % 12 + 1 )) # don't prefer January & February
[ "${rs_weekday}" = "R" ] && \
rs_weekday=$(( (6 + RANDOM % 2) % 7 )) # prefer weekends
# rs_weekday=$(( RANDOM % 7 )) # don't prefer weekends
echo "${rs_minute} ${rs_hour} ${rs_day} ${rs_month} ${rs_weekday} ${rs_command}"

View file

@ -1,5 +1,8 @@
#!/bin/sh #!/bin/sh
# commands
crond_exe="$(command -v crond)"
# set timezone # set timezone
export TZ="${TZ:-Etc/UTC}" export TZ="${TZ:-Etc/UTC}"
ln -sf "/usr/share/zoneinfo/${TZ}" "/etc/localtime" ln -sf "/usr/share/zoneinfo/${TZ}" "/etc/localtime"
@ -22,7 +25,6 @@ shift "$(( OPTIND - 1 ))"
# CLI arguments # CLI arguments
rc_executable="${1}" rc_executable="${1}"
if [ -n "${rc_dry_run}" ]; then if [ -n "${rc_dry_run}" ]; then
# verbose, dry run # verbose, dry run
set -x set -x
@ -39,6 +41,6 @@ fi
| crontab - | crontab -
# hand over to crond # hand over to crond
exec crond -fd 8 exec "${crond_exe}" -fd 8
exit 0 exit 0

View file

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
# shellcheck disable=SC3001 # process substitution are defined in alpine's /bin/sh
this_script="$( readlink -f "${0}" )" this_script="$( readlink -f "${0}" )"
this_dir="${this_script%/*}" this_dir="${this_script%/*}"
@ -42,7 +44,7 @@ schedule_dirs="$(
)" )"
for schedule_dir in ${schedule_dirs}; do for schedule_dir in ${schedule_dirs}; do
# ignore if no files # ignore dirs without files
if dir_has_no_files "${schedule_dir}"; then if dir_has_no_files "${schedule_dir}"; then
continue continue
fi fi
@ -52,7 +54,9 @@ for schedule_dir in ${schedule_dirs}; do
units="${dir_name%ly}" units="${dir_name%ly}"
units="$( dir_to_unit "${units}" )" units="$( dir_to_unit "${units}" )"
"${this_dir}/create_schedule" "1" "${units}" "run-parts '${schedule_dir}'" "${this_dir}/create_schedule" \
"1" "${units}" "run-parts '${schedule_dir}'" \
| "${this_dir}/randomize_schedule"
done done
# check dirs in "/kiwi-cron/every" directory # check dirs in "/kiwi-cron/every" directory
@ -61,16 +65,29 @@ every_schedule_dirs="$(
)" )"
for schedule_dir in ${every_schedule_dirs}; do for schedule_dir in ${every_schedule_dirs}; do
# ignore if no files # ignore dirs without files
if dir_has_no_files "${schedule_dir}"; then if dir_has_no_files "${schedule_dir}"; then
continue continue
fi fi
# infer schedule params by directory name # infer schedule params by directory name
dir_name="${schedule_dir##*/}" dir_name="${schedule_dir##*/}"
every="$( echo "${dir_name}" | awk -F_ '{print $1}' )" case "${dir_name}" in
units="$( echo "${dir_name}" | awk -F_ '{print $2}' )" *_*) # looks like: every/5_minutes
read -r every units < \
<( echo "${dir_name}" | tr '_' ' ' )
;;
*) # probably looks like: every/day
every="1"
units="${dir_name}"
;;
esac
# remove trailing "s" if present
units="${units%s}" units="${units%s}"
"${this_dir}/create_schedule" "${every}" "${units}" "run-parts '${schedule_dir}'" "${this_dir}/create_schedule" \
"${every}" "${units}" "run-parts '${schedule_dir}'" \
| "${this_dir}/randomize_schedule"
done done