mirror of
https://github.com/willfarrell/docker-crontab.git
synced 2025-04-08 16:05:14 +02:00
Envsubst allows to use dynamic container name We use image name env substitution with docker-compose and .env to select right image tag for local development Within alpine, envsubst installed with gettext package.
232 lines
6.5 KiB
Bash
Executable File
232 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
if [ -z "$DOCKER_HOST" -a "$DOCKER_PORT_2375_TCP" ]; then
|
|
export DOCKER_HOST='tcp://docker:2375'
|
|
fi
|
|
|
|
# for local testing only
|
|
#HOME_DIR=.
|
|
|
|
if [ "${LOG_FILE}" == "" ]; then
|
|
LOG_DIR=/var/log/crontab
|
|
LOG_FILE=${LOG_DIR}/jobs.log
|
|
mkdir -p ${LOG_DIR}
|
|
touch ${LOG_FILE}
|
|
fi
|
|
|
|
CONFIG=${HOME_DIR}/config.json
|
|
DOCKER_SOCK=/var/run/docker.sock
|
|
CRONTAB_FILE=/etc/crontabs/docker
|
|
|
|
# Ensure dir exist - in case of volume mapping
|
|
mkdir -p ${HOME_DIR}/jobs ${HOME_DIR}/projects
|
|
|
|
# Create docker group using correct gid from host, and add docker user to it
|
|
if ! grep -q "^docker:" /etc/group; then
|
|
DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCK})
|
|
if [ "${DOCKER_GID}" != "0" ]; then
|
|
addgroup -g ${DOCKER_GID} docker
|
|
adduser docker docker
|
|
else
|
|
adduser docker root
|
|
fi
|
|
fi
|
|
|
|
slugify() {
|
|
echo "$@" | iconv -t ascii | sed -r s/[~\^]+//g | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z
|
|
}
|
|
|
|
make_image_cmd() {
|
|
DOCKERARGS=$(echo ${1} | jq -r .dockerargs)
|
|
if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
|
|
IMAGE=$(echo ${1} | jq -r .image | envsubst)
|
|
TMP_COMMAND=$(echo ${1} | jq -r .command)
|
|
echo "docker run ${DOCKERARGS} ${IMAGE} ${TMP_COMMAND}"
|
|
}
|
|
|
|
make_container_cmd() {
|
|
DOCKERARGS=$(echo ${1} | jq -r .dockerargs)
|
|
if [ "${DOCKERARGS}" == "null" ]; then DOCKERARGS=; fi
|
|
SCRIPT_NAME=$(echo ${1} | jq -r .name)
|
|
PROJECT=$(echo ${1} | jq -r .project)
|
|
CONTAINER=$(echo ${1} | jq -r .container | envsubst)
|
|
TMP_COMMAND=$(echo ${1} | jq -r .command)
|
|
|
|
if [ "${PROJECT}" != "null" ]; then
|
|
|
|
# create bash script to detect all running containers
|
|
if [ "${SCRIPT_NAME}" == "null" ]; then
|
|
SCRIPT_NAME=$(cat /proc/sys/kernel/random/uuid)
|
|
fi
|
|
cat << EOF > ${HOME_DIR}/projects/${SCRIPT_NAME}.sh
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
CONTAINERS=\$(docker ps --format '{{.Names}}' | grep -E "^${PROJECT}_${CONTAINER}.[0-9]+")
|
|
for CONTAINER_NAME in \$CONTAINERS; do
|
|
docker exec ${DOCKERARGS} \${CONTAINER_NAME} ${TMP_COMMAND}
|
|
done
|
|
EOF
|
|
echo "/bin/bash ${HOME_DIR}/projects/${SCRIPT_NAME}.sh"
|
|
else
|
|
echo "docker exec ${DOCKERARGS} ${CONTAINER} ${TMP_COMMAND}"
|
|
fi
|
|
}
|
|
|
|
#make_host_cmd() {
|
|
# HOST_BINARY=$(echo ${1} | jq -r .host)
|
|
# TMP_COMMAND=$(echo ${1} | jq -r .command)
|
|
# echo "${HOST_BINARY} ${TMP_COMMAND}"
|
|
#}
|
|
|
|
make_cmd() {
|
|
if [ "$(echo ${1} | jq -r .image)" != "null" ]; then
|
|
make_image_cmd "$1"
|
|
elif [ "$(echo ${1} | jq -r .container)" != "null" ]; then
|
|
make_container_cmd "$1"
|
|
#elif [ "$(echo ${1} | jq -r .host)" != "null" ]; then
|
|
# make_host_cmd "$1"
|
|
else
|
|
echo ${1} | jq -r .command
|
|
fi
|
|
}
|
|
|
|
parse_schedule() {
|
|
case $1 in
|
|
"@yearly")
|
|
echo "0 0 1 1 *"
|
|
;;
|
|
"@annually")
|
|
echo "0 0 1 1 *"
|
|
;;
|
|
"@monthly")
|
|
echo "0 0 1 * *"
|
|
;;
|
|
"@weekly")
|
|
echo "0 0 * * 0"
|
|
;;
|
|
"@daily")
|
|
echo "0 0 * * *"
|
|
;;
|
|
"@midnight")
|
|
echo "0 0 * * *"
|
|
;;
|
|
"@hourly")
|
|
echo "0 * * * *"
|
|
;;
|
|
"@every")
|
|
TIME=$2
|
|
TOTAL=0
|
|
|
|
M=$(echo $TIME | grep -o '[0-9]\+m')
|
|
H=$(echo $TIME | grep -o '[0-9]\+h')
|
|
D=$(echo $TIME | grep -o '[0-9]\+d')
|
|
|
|
if [ -n "${M}" ]; then
|
|
TOTAL=$(($TOTAL + ${M::-1}))
|
|
fi
|
|
if [ -n "${H}" ]; then
|
|
TOTAL=$(($TOTAL + ${H::-1} * 60))
|
|
fi
|
|
if [ -n "${D}" ]; then
|
|
TOTAL=$(($TOTAL + ${D::-1} * 60 * 24))
|
|
fi
|
|
|
|
echo "*/${TOTAL} * * * *"
|
|
;;
|
|
*)
|
|
echo "${@}"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function build_crontab() {
|
|
rm -rf ${CRONTAB_FILE}
|
|
|
|
ONSTART=()
|
|
while read i ; do
|
|
|
|
SCHEDULE=$(jq -r .[$i].schedule ${CONFIG} | sed 's/\*/\\*/g')
|
|
if [ "${SCHEDULE}" == "null" ]; then
|
|
echo "Schedule Missing: $(jq -r .[$i].schedule ${CONFIG})"
|
|
continue
|
|
fi
|
|
SCHEDULE=$(parse_schedule ${SCHEDULE} | sed 's/\\//g')
|
|
|
|
if [ "$(jq -r .[$i].command ${CONFIG})" == "null" ]; then
|
|
echo "Command Missing: $(jq -r .[$i].command ${CONFIG})"
|
|
continue
|
|
fi
|
|
|
|
COMMENT=$(jq -r .[$i].comment ${CONFIG})
|
|
if [ "${COMMENT}" != "null" ]; then
|
|
echo "# ${COMMENT}" >> ${CRONTAB_FILE}
|
|
fi
|
|
|
|
SCRIPT_NAME=$(jq -r .[$i].name ${CONFIG})
|
|
SCRIPT_NAME=$(slugify $SCRIPT_NAME)
|
|
if [ "${SCRIPT_NAME}" == "null" ]; then
|
|
SCRIPT_NAME=$(cat /proc/sys/kernel/random/uuid)
|
|
fi
|
|
|
|
COMMAND="/bin/bash ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh"
|
|
cat << EOF > ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
# TODO find workaround
|
|
# [error] write /dev/stdout: broken pipe <- when using docker commands
|
|
#UUID=\$(cat /proc/sys/kernel/random/uuid)
|
|
#exec > >(read message; echo "\${UUID} \$(date -Iseconds) [info] \$message" | tee -a ${LOG_FILE} )
|
|
#exec 2> >(read message; echo "\${UUID} \$(date -Iseconds) [error] \$message" | tee -a ${LOG_FILE} >&2)
|
|
|
|
echo "Start Cronjob **${SCRIPT_NAME}** ${COMMENT}"
|
|
|
|
$(make_cmd "$(jq -c .[$i] ${CONFIG})")
|
|
EOF
|
|
|
|
|
|
|
|
if [ "$(jq -r .[$i].trigger ${CONFIG})" != "null" ]; then
|
|
while read j ; do
|
|
if [ "$(jq .[$i].trigger[$j].command ${CONFIG})" == "null" ]; then
|
|
echo "Command Missing: $(jq -r .[$i].trigger[$j].command ${CONFIG})"
|
|
continue
|
|
fi
|
|
#TRIGGER_COMMAND=$(make_cmd "$(jq -c .[$i].trigger[$j] ${CONFIG})")
|
|
echo "$(make_cmd "$(jq -c .[$i].trigger[$j] ${CONFIG})")" >> ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh
|
|
#COMMAND="${COMMAND} && ${TRIGGER_COMMAND}"
|
|
done < <(jq -r '.['$i'].trigger|keys[]' ${CONFIG})
|
|
fi
|
|
|
|
echo "echo \"End Cronjob **${SCRIPT_NAME}** ${COMMENT}\"" >> ${HOME_DIR}/jobs/${SCRIPT_NAME}.sh
|
|
|
|
echo "${SCHEDULE} ${COMMAND}" >> ${CRONTAB_FILE}
|
|
|
|
if [ "$(jq -r .[$i].onstart ${CONFIG})" == "true" ]; then
|
|
ONSTART+=("${COMMAND}")
|
|
fi
|
|
done < <(jq -r '.|keys[]' ${CONFIG})
|
|
|
|
echo "##### crontab generation complete #####"
|
|
cat ${CRONTAB_FILE}
|
|
|
|
echo "##### run commands with onstart #####"
|
|
for COMMAND in "${ONSTART[@]}"; do
|
|
echo "${COMMAND}"
|
|
${COMMAND} &
|
|
done
|
|
}
|
|
|
|
if [ "$1" = "crond" ]; then
|
|
if [ -f ${CONFIG} ]; then
|
|
build_crontab
|
|
else
|
|
echo "Unable to find ${HOME_DIR}/config.json"
|
|
fi
|
|
fi
|
|
|
|
echo "$@"
|
|
exec "$@"
|