docker-crontab/entrypoint.sh

264 lines
8.1 KiB
Bash
Raw Normal View History

2022-08-07 08:14:21 -07:00
#!/bin/bash
2017-02-12 16:28:53 -07:00
set -e
2022-07-16 08:33:41 -07:00
DOCKER_SOCK=/var/run/docker.sock
CRONTAB_FILE=/etc/crontabs/docker
2023-03-04 18:31:55 -08:00
if [ -z "${HOME_DIR}" ] && [ -n "${TEST_MODE}" ]; then
HOME_DIR=/tmp/crontab-docker-testing
CRONTAB_FILE=${HOME_DIR}/test
elif [ -z "${HOME_DIR}" ]; then
2022-07-16 08:38:01 -07:00
echo "HOME_DIR not set."
exit 1
fi
2022-07-16 08:33:41 -07:00
# Ensure dir exist - in case of volume mapping.
mkdir -p "${HOME_DIR}"/jobs
2022-07-16 08:33:41 -07:00
2022-07-16 08:43:14 -07:00
if [ -z "${DOCKER_HOST}" ] && [ -a "${DOCKER_PORT_2375_TCP}" ]; then
2022-07-16 10:53:34 -07:00
export DOCKER_HOST="tcp://docker:2375"
2017-02-15 10:58:57 -07:00
fi
normalize_config() {
2022-07-16 08:28:20 -07:00
JSON_CONFIG={}
if [ -f "${HOME_DIR}/config.json" ]; then
2022-07-16 08:28:20 -07:00
JSON_CONFIG="$(cat "${HOME_DIR}"/config.json)"
elif [ -f "${HOME_DIR}/config.toml" ]; then
2022-07-16 08:28:20 -07:00
JSON_CONFIG="$(rq -t <<< "$(cat "${HOME_DIR}"/config.toml)")"
elif [ -f "${HOME_DIR}/config.yml" ]; then
2022-07-16 08:28:20 -07:00
JSON_CONFIG="$(rq -y <<< "$(cat "${HOME_DIR}"/config.yml)")"
elif [ -f "${HOME_DIR}/config.yaml" ]; then
2022-07-16 08:28:20 -07:00
JSON_CONFIG="$(rq -y <<< "$(cat "${HOME_DIR}"/config.yaml)")"
fi
jq -S -r '."~~shared-settings" as $shared | del(."~~shared-settings") | to_entries | map_values(.value + { name: .key } + $shared)' <<< "${JSON_CONFIG}" > "${HOME_DIR}"/config.working.json
}
ensure_docker_socket_accessible() {
if ! grep -q "^docker:" /etc/group; then
# Ensure 'docker' user has permissions for docker socket (without changing permissions).
DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCK})
if [ "${DOCKER_GID}" != "0" ]; then
if ! grep -qE "^[^:]+:[^:]+:${DOCKER_GID}:" /etc/group; then
# No group with such gid exists - create group 'docker'.
2022-07-16 08:13:11 -07:00
addgroup -g "${DOCKER_GID}" docker
adduser docker docker
else
# Group with such gid exists - add user 'docker' to this group.
2022-07-16 08:15:18 -07:00
DOCKER_GROUP_NAME=$(getent group "${DOCKER_GID}" | awk -F':' '{{ print $1 }}')
2022-07-16 08:43:14 -07:00
adduser docker "${DOCKER_GROUP_NAME}"
fi
else
# Docker socket belongs to 'root' group - add user 'docker' to this group.
adduser docker root
fi
fi
}
2017-11-14 13:54:20 -07:00
slugify() {
2022-07-16 08:43:14 -07:00
echo "${@}" | iconv -t ascii | sed -r s/[~^]+//g | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr '[:upper:]' '[:lower:]'
2017-11-14 13:54:20 -07:00
}
2017-02-12 16:28:53 -07:00
make_image_cmd() {
2022-07-16 08:13:11 -07:00
DOCKERARGS=$(echo "${1}" | jq -r .dockerargs)
ENVIRONMENT=$(echo "${1}" | jq -r 'select(.environment != null) | .environment | map("--env " + .) | join(" ")')
EXPOSE=$(echo "${1}" | jq -r 'select(.expose != null) | .expose | map("--expose " + .) | join(" ")' )
2022-07-16 08:13:11 -07:00
NAME=$(echo "${1}" | jq -r 'select(.name != null) | .name')
2023-05-21 11:43:46 -07:00
NETWORKS=$(echo "${1}" | jq -r 'select(.networks != null) | .networks | map("--network " + .) | join(" ")')
PORTS=$(echo "${1}" | jq -r 'select(.ports != null) | .ports | map("--publish " + .) | join(" ")')
VOLUMES=$(echo "${1}" | jq -r 'select(.volumes != null) | .volumes | map("--volume " + .) | join(" ")')
if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
DOCKERARGS+=" "
if [ -n "${ENVIRONMENT}" ]; then DOCKERARGS+="${ENVIRONMENT} "; fi
if [ -n "${EXPOSE}" ]; then DOCKERARGS+="${EXPOSE} "; fi
if [ -n "${NAME}" ]; then DOCKERARGS+="--name ${NAME} "; fi
2023-05-21 11:43:46 -07:00
if [ -n "${NETWORKS}" ]; then DOCKERARGS+="${NETWORKS} "; fi
if [ -n "${PORTS}" ]; then DOCKERARGS+="${PORTS} "; fi
if [ -n "${VOLUMES}" ]; then DOCKERARGS+="${VOLUMES} "; fi
2022-07-16 08:13:11 -07:00
IMAGE=$(echo "${1}" | jq -r .image | envsubst)
if [ "${IMAGE}" == "null" ]; then return; fi
COMMAND=$(echo "${1}" | jq -r .command)
echo "docker run ${DOCKERARGS} ${IMAGE} ${COMMAND}"
2017-02-12 16:28:53 -07:00
}
make_container_cmd() {
2022-07-16 08:13:11 -07:00
DOCKERARGS=$(echo "${1}" | jq -r .dockerargs)
2017-02-12 16:28:53 -07:00
if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
2022-07-16 08:13:11 -07:00
CONTAINER=$(echo "${1}" | jq -r .container | envsubst)
if [ "${CONTAINER}" == "null" ]; then return; fi
2017-02-12 16:28:53 -07:00
COMMAND=$(echo "${1}" | jq -r .command )
if [ "${COMMAND}" == "null" ]; then return; fi
2017-06-17 20:10:47 -06:00
echo "docker exec ${DOCKERARGS} ${CONTAINER} ${COMMAND}"
2017-02-12 16:28:53 -07:00
}
make_cmd() {
2022-07-16 08:13:11 -07:00
if [ "$(echo "${1}" | jq -r .image)" != "null" ]; then
2022-07-16 08:43:14 -07:00
make_image_cmd "${1}"
2022-07-16 08:13:11 -07:00
elif [ "$(echo "${1}" | jq -r .container)" != "null" ]; then
2022-07-16 08:43:14 -07:00
make_container_cmd "${1}"
2017-02-12 16:28:53 -07:00
else
2022-07-16 08:13:11 -07:00
echo "${1}" | jq -r .command
2017-02-12 16:28:53 -07:00
fi
}
parse_schedule() {
IFS=" "
read -a params <<< "$@"
case ${params[0]} in
"@yearly" | "@annually")
echo "0 0 1 1 *"
2017-02-12 16:28:53 -07:00
;;
"@monthly")
echo "0 0 1 * *"
2017-02-12 16:28:53 -07:00
;;
"@weekly")
echo "0 0 * * 0"
2017-02-12 16:28:53 -07:00
;;
"@daily")
echo "0 0 * * *"
2017-02-12 16:28:53 -07:00
;;
"@midnight")
echo "0 0 * * *"
2017-02-12 16:28:53 -07:00
;;
"@hourly")
echo "0 * * * *"
2017-02-12 16:28:53 -07:00
;;
2023-03-04 18:31:55 -08:00
"@random")
M="*"
H="*"
D="*"
for when in "${params[@]:1}"
2023-03-04 18:31:55 -08:00
do
case $when in
"@m")
M=$(shuf -i 0-59 -n 1)
2023-03-04 18:31:55 -08:00
;;
"@h")
H=$(shuf -i 0-23 -n 1)
;;
"@d")
D=$(shuf -i 0-6 -n 1)
;;
esac
done
echo "${M} ${H} * * ${D}"
;;
2017-02-12 16:28:53 -07:00
*)
echo "${params[@]}"
2017-02-12 16:28:53 -07:00
;;
esac
}
function build_crontab() {
2023-03-04 18:31:55 -08:00
rm -rf "${CRONTAB_FILE}"
2017-02-14 07:18:25 -07:00
ONSTART=()
2022-07-16 08:17:17 -07:00
while read -r i ; do
KEY=$(jq -r .["$i"] "${CONFIG}")
SCHEDULE=$(echo "${KEY}" | jq -r '.schedule' | sed 's/\*/\\*/g')
2017-02-12 16:28:53 -07:00
if [ "${SCHEDULE}" == "null" ]; then
echo "'schedule' missing: '${KEY}"
2017-02-12 16:28:53 -07:00
continue
fi
2022-07-16 08:13:11 -07:00
SCHEDULE=$(parse_schedule "${SCHEDULE}" | sed 's/\\//g')
2017-02-12 16:28:53 -07:00
COMMAND=$(echo "${KEY}" | jq -r '.command')
2022-07-16 08:51:38 -07:00
if [ "${COMMAND}" == "null" ]; then
echo "'command' missing: '${KEY}'"
2017-02-12 16:28:53 -07:00
continue
fi
COMMENT=$(echo "${KEY}" | jq -r '.comment')
2017-02-15 13:42:35 -07:00
SCRIPT_NAME=$(echo "${KEY}" | jq -r '.name')
2022-07-16 08:43:14 -07:00
SCRIPT_NAME=$(slugify "${SCRIPT_NAME}")
if [ "${SCRIPT_NAME}" == "null" ]; then
SCRIPT_NAME=$(cat /proc/sys/kernel/random/uuid)
fi
CRON_COMMAND=$(make_cmd "${KEY}")
SCRIPT_PATH="${HOME_DIR}/jobs/${SCRIPT_NAME}.sh"
touch "${SCRIPT_PATH}"
chmod +x "${SCRIPT_PATH}"
2017-06-17 20:55:56 -06:00
{
echo "#\!/usr/bin/env bash"
echo "set -e"
echo ""
echo "echo \"start cron job __${SCRIPT_NAME}__\""
echo "${CRON_COMMAND}"
2023-03-04 18:31:55 -08:00
} > "${SCRIPT_PATH}"
TRIGGER=$(echo "${KEY}" | jq -r '.trigger')
2022-07-16 08:51:38 -07:00
if [ "${TRIGGER}" != "null" ]; then
2022-07-16 08:17:17 -07:00
while read -r j ; do
TRIGGER_KEY=$(echo "${KEY}" | jq -r .trigger["$j"])
TRIGGER_COMMAND=$(echo "${TRIGGER_KEY}" | jq -r '.command')
2022-07-16 08:51:38 -07:00
if [ "${TRIGGER_COMMAND}" == "null" ]; then
2017-02-12 16:28:53 -07:00
continue
fi
make_cmd "${TRIGGER_KEY}" >> "${SCRIPT_PATH}"
done < <(echo "${KEY}" | jq -r '.trigger | keys[]')
2017-02-12 16:28:53 -07:00
fi
echo "echo \"end cron job __${SCRIPT_NAME}__\"" >> "${SCRIPT_PATH}"
2017-06-17 20:55:56 -06:00
if [ "${COMMENT}" != "null" ]; then
2023-03-04 18:31:55 -08:00
echo "# ${COMMENT}" >> "${CRONTAB_FILE}"
fi
2023-03-04 18:31:55 -08:00
echo "${SCHEDULE} ${SCRIPT_PATH}" >> "${CRONTAB_FILE}"
2017-02-14 07:18:25 -07:00
ONSTART_COMMAND=$(echo "${KEY}" | jq -r '.onstart')
if [ "${ONSTART_COMMAND}" == "true" ]; then
ONSTART+=("${SCRIPT_PATH}")
2017-02-14 07:18:25 -07:00
fi
done < <(jq -r '. | keys[]' "${CONFIG}")
2017-02-12 16:28:53 -07:00
printf "##### crontab generated #####\n"
2023-03-04 18:31:55 -08:00
cat "${CRONTAB_FILE}"
2017-02-14 07:18:25 -07:00
printf "##### run commands with onstart #####\n"
for ONSTART_COMMAND in "${ONSTART[@]}"; do
printf "%s\n" "${ONSTART_COMMAND}"
${ONSTART_COMMAND} &
2017-02-14 07:18:25 -07:00
done
printf "##### cron running #####\n"
2017-02-12 16:28:53 -07:00
}
start_app() {
normalize_config
2022-07-16 08:28:20 -07:00
export CONFIG=${HOME_DIR}/config.working.json
if [ ! -f "${CONFIG}" ]; then
printf "missing generated %s. exiting.\n" "${CONFIG}"
2022-07-16 08:28:20 -07:00
exit 1
2017-02-12 16:57:19 -07:00
fi
2022-07-16 08:43:14 -07:00
if [ "${1}" == "crond" ]; then
2022-07-16 08:28:20 -07:00
build_crontab
fi
printf "%s\n" "${@}"
2022-07-16 08:43:14 -07:00
exec "${@}"
}
2017-02-12 16:28:53 -07:00
2023-03-04 18:31:55 -08:00
if [ -z "${TEST_MODE}" ]; then
ensure_docker_socket_accessible
fi
2022-08-07 08:14:21 -07:00
printf "✨ starting crontab container ✨\n"
2022-07-16 08:43:14 -07:00
start_app "${@}"