From efc9fbf80347183ec2f57a13e6d1d92ad8601632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Tue, 1 Mar 2022 18:47:44 +0100 Subject: [PATCH 1/9] format --- libexec/kiwi-cron/run_cron | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libexec/kiwi-cron/run_cron b/libexec/kiwi-cron/run_cron index 8bfe7eb..826eb93 100755 --- a/libexec/kiwi-cron/run_cron +++ b/libexec/kiwi-cron/run_cron @@ -1,5 +1,8 @@ #!/bin/sh +# commands +crond_exe="$(command -v crond)" + # set timezone export TZ="${TZ:-Etc/UTC}" ln -sf "/usr/share/zoneinfo/${TZ}" "/etc/localtime" @@ -22,7 +25,6 @@ shift "$(( OPTIND - 1 ))" # CLI arguments rc_executable="${1}" - if [ -n "${rc_dry_run}" ]; then # verbose, dry run set -x @@ -39,6 +41,6 @@ fi | crontab - # hand over to crond -exec crond -fd 8 +exec "${crond_exe}" -fd 8 exit 0 \ No newline at end of file From 9522abec3c4e0cf41dd968f09fac181afa0da03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Tue, 1 Mar 2022 18:53:53 +0100 Subject: [PATCH 2/9] image maintainer --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 57569c9..cffd36d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ FROM alpine:latest +LABEL maintainer="jmm@yavook.de" ENV TZ=Etc/UTC From 351c46fe66dd84f80bdfa71c9f9f175572a80786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Wed, 2 Mar 2022 18:54:58 +0100 Subject: [PATCH 3/9] rename scheduler --- Dockerfile | 2 +- bin/kiwi-cron | 2 +- libexec/kiwi-cron/{schedule_dirs => scheduler} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename libexec/kiwi-cron/{schedule_dirs => scheduler} (100%) diff --git a/Dockerfile b/Dockerfile index cffd36d..220c5c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,4 +25,4 @@ RUN set -ex; \ COPY bin /usr/local/bin/ COPY libexec /usr/local/libexec/ -CMD [ "kiwi-cron" ] \ No newline at end of file +CMD [ "kiwi-cron" ] diff --git a/bin/kiwi-cron b/bin/kiwi-cron index c1e2707..3c8b748 100755 --- a/bin/kiwi-cron +++ b/bin/kiwi-cron @@ -2,4 +2,4 @@ exec /usr/local/libexec/kiwi-cron/run_cron \ "${@}" \ - /usr/local/libexec/kiwi-cron/schedule_dirs + /usr/local/libexec/kiwi-cron/scheduler diff --git a/libexec/kiwi-cron/schedule_dirs b/libexec/kiwi-cron/scheduler similarity index 100% rename from libexec/kiwi-cron/schedule_dirs rename to libexec/kiwi-cron/scheduler From 038aecad4c6dab82f9aaec055a34df958e134d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Wed, 2 Mar 2022 18:55:29 +0100 Subject: [PATCH 4/9] little refactorings --- libexec/kiwi-cron/create_schedule | 2 +- libexec/kiwi-cron/print_crontab | 20 ++++---------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/libexec/kiwi-cron/create_schedule b/libexec/kiwi-cron/create_schedule index 34ed88c..5a09075 100755 --- a/libexec/kiwi-cron/create_schedule +++ b/libexec/kiwi-cron/create_schedule @@ -4,7 +4,7 @@ cs_every="${1:-1}" cs_units="${2}" cs_command="${3}" -if [ "${cs_every}" -eq 1 ]; then +if [ "${cs_every}" = "1" ]; then cs_every="" else cs_every="/${cs_every}" diff --git a/libexec/kiwi-cron/print_crontab b/libexec/kiwi-cron/print_crontab index a2c6a29..0647be6 100755 --- a/libexec/kiwi-cron/print_crontab +++ b/libexec/kiwi-cron/print_crontab @@ -1,28 +1,16 @@ #!/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 echo '# crontab generated by kiwi-cron' echo '# generation time: '"$(date)" echo '#' # short documentation line -print_cron_schedule \ +printf '%-8s%-8s%-8s%-8s%-8s%s\n' \ "# min" "hour" "day" "month" "weekday" "command" # schedules -while read -r pc_min pc_hour pc_day pc_month pc_weekday pc_command; do - print_cron_schedule \ - "${pc_min}" "${pc_hour}" "${pc_day}" "${pc_month}" "${pc_weekday}" "${pc_command}" +while read -r pc_minute pc_hour pc_day pc_month pc_weekday pc_command; do + printf '%-8s%-8s%-8s%-8s%-8s%s\n' \ + "${pc_minute}" "${pc_hour}" "${pc_day}" "${pc_month}" "${pc_weekday}" "${pc_command}" done From 02605d20a4b4b555e7999f458785441700a6f4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Wed, 2 Mar 2022 19:02:16 +0100 Subject: [PATCH 5/9] newline --- libexec/kiwi-cron/run_cron | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/kiwi-cron/run_cron b/libexec/kiwi-cron/run_cron index 826eb93..9386c1a 100755 --- a/libexec/kiwi-cron/run_cron +++ b/libexec/kiwi-cron/run_cron @@ -43,4 +43,4 @@ fi # hand over to crond exec "${crond_exe}" -fd 8 -exit 0 \ No newline at end of file +exit 0 From 7ae0325a2d19a6866b599090d89b3706ac213263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:05:14 +0100 Subject: [PATCH 6/9] externalize schedule randomization --- libexec/kiwi-cron/create_schedule | 30 ++++++---------------------- libexec/kiwi-cron/randomize_schedule | 25 +++++++++++++++++++++++ libexec/kiwi-cron/scheduler | 29 +++++++++++++++++++++------ 3 files changed, 54 insertions(+), 30 deletions(-) create mode 100755 libexec/kiwi-cron/randomize_schedule diff --git a/libexec/kiwi-cron/create_schedule b/libexec/kiwi-cron/create_schedule index 5a09075..2d31a64 100755 --- a/libexec/kiwi-cron/create_schedule +++ b/libexec/kiwi-cron/create_schedule @@ -13,41 +13,23 @@ 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 minute) - echo "*${cs_every}" "*" "*" "*" "*" "${cs_command}" + echo "*${cs_every} * * * * ${cs_command}" ;; hour) - echo "${cs_rand_min}" "*${cs_every}" "*" "*" "*" "${cs_command}" + echo "R *${cs_every} * * * ${cs_command}" ;; day) - echo "${cs_rand_min}" "${cs_rand_hour}" "*${cs_every}" "*" "*" "${cs_command}" + echo "R R *${cs_every} * * ${cs_command}" ;; week) - echo "${cs_rand_min}" "${cs_rand_hour}" "*" "*" "${cs_rand_weekday}" "${cs_command}" + echo "R R * * R ${cs_command}" ;; month) - echo "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "*${cs_every}" "*" "${cs_command}" + echo "R R R *${cs_every} * ${cs_command}" ;; year) - echo "${cs_rand_min}" "${cs_rand_hour}" "${cs_rand_day}" "${cs_rand_month}" "*" "${cs_command}" + echo "R R R R * ${cs_command}" ;; esac diff --git a/libexec/kiwi-cron/randomize_schedule b/libexec/kiwi-cron/randomize_schedule new file mode 100755 index 0000000..c5e938a --- /dev/null +++ b/libexec/kiwi-cron/randomize_schedule @@ -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 % 7) % 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}" diff --git a/libexec/kiwi-cron/scheduler b/libexec/kiwi-cron/scheduler index e9b79aa..aca5381 100755 --- a/libexec/kiwi-cron/scheduler +++ b/libexec/kiwi-cron/scheduler @@ -1,5 +1,7 @@ #!/bin/sh +# shellcheck disable=SC3001 # process substitution are defined in alpine's /bin/sh + this_script="$( readlink -f "${0}" )" this_dir="${this_script%/*}" @@ -42,7 +44,7 @@ schedule_dirs="$( )" for schedule_dir in ${schedule_dirs}; do - # ignore if no files + # ignore dirs without files if dir_has_no_files "${schedule_dir}"; then continue fi @@ -52,7 +54,9 @@ for schedule_dir in ${schedule_dirs}; do units="${dir_name%ly}" 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 # check dirs in "/kiwi-cron/every" directory @@ -61,16 +65,29 @@ every_schedule_dirs="$( )" for schedule_dir in ${every_schedule_dirs}; do - # ignore if no files + # ignore dirs without files if dir_has_no_files "${schedule_dir}"; then continue fi # infer schedule params by directory name dir_name="${schedule_dir##*/}" - every="$( echo "${dir_name}" | awk -F_ '{print $1}' )" - units="$( echo "${dir_name}" | awk -F_ '{print $2}' )" + case "${dir_name}" in + *_*) # 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}" - "${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 From beb8d1230235ecfaeb694bac4eae78352d92412d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:25:45 +0100 Subject: [PATCH 7/9] README --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fe0507d..46cc4c6 100644 --- a/README.md +++ b/README.md @@ -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. 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 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: - `/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/monthly` runs once every month (random nighttime value on a random day) -- `/kiwi-cron/yearly` and `/kiwi-cron/annually` runs once a year (random nighttime value on a random day in January or February) +- `/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 <= 28 in January or February) Cron schedules are regenerated once on each startup, only for directories that have files. -## 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". - -## Finer granularity: The `/kiwi-cron/every` directory +## Granularity: The `/kiwi-cron/every` directory 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. -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 From e415d0b7e01e0ec806f37cfc11bd927341db41b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:26:36 +0100 Subject: [PATCH 8/9] bug: "7" included hour 3, i.e. times up until 3:59 am --- libexec/kiwi-cron/randomize_schedule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libexec/kiwi-cron/randomize_schedule b/libexec/kiwi-cron/randomize_schedule index c5e938a..e46eb93 100755 --- a/libexec/kiwi-cron/randomize_schedule +++ b/libexec/kiwi-cron/randomize_schedule @@ -8,7 +8,7 @@ read -r rs_minute rs_hour rs_day rs_month rs_weekday rs_command rs_minute=$(( RANDOM % 60 )) [ "${rs_hour}" = "R" ] && \ - rs_hour=$(( (21 + RANDOM % 7) % 24 )) # prefer nighttime + rs_hour=$(( (21 + RANDOM % 6) % 24 )) # prefer nighttime # rs_hour=$(( RANDOM % 24 )) # don't prefer nighttime [ "${rs_day}" = "R" ] && \ From ff334bc60322da243a2cae99ddaf0ba4c25483fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:26:50 +0100 Subject: [PATCH 9/9] cleanup --- libexec/kiwi-cron/create_schedule | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libexec/kiwi-cron/create_schedule b/libexec/kiwi-cron/create_schedule index 2d31a64..e92b2ca 100755 --- a/libexec/kiwi-cron/create_schedule +++ b/libexec/kiwi-cron/create_schedule @@ -5,29 +5,26 @@ cs_units="${2}" cs_command="${3}" if [ "${cs_every}" = "1" ]; then - cs_every="" + cs_every="*" else - cs_every="/${cs_every}" + cs_every="*/${cs_every}" fi -# generate valid random schedule values -# generally, "nighttime" and "weekend" will be preferred. - case "${cs_units}" in minute) - echo "*${cs_every} * * * * ${cs_command}" + echo "${cs_every} * * * * ${cs_command}" ;; hour) - echo "R *${cs_every} * * * ${cs_command}" + echo "R ${cs_every} * * * ${cs_command}" ;; day) - echo "R R *${cs_every} * * ${cs_command}" + echo "R R ${cs_every} * * ${cs_command}" ;; week) echo "R R * * R ${cs_command}" ;; month) - echo "R R R *${cs_every} * ${cs_command}" + echo "R R R ${cs_every} * ${cs_command}" ;; year) echo "R R R R * ${cs_command}"