You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
8.2 KiB
236 lines
8.2 KiB
# -*- mode: shell-script -*-
|
|
|
|
cron:get_config() {
|
|
local cfg="$1" env_hash="$2"
|
|
local cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$@")" \
|
|
type value
|
|
local k v E E1 title command lock_opts schedule
|
|
if [ -e "$cache_file" ]; then
|
|
debug "$FUNCNAME: SESSION cache hit $1"
|
|
cat "$cache_file"
|
|
return 0
|
|
fi
|
|
type=$(e "$cfg" | shyaml -q get-type 2>/dev/null) || true
|
|
case "$type" in
|
|
"sequence")
|
|
while read-0-err E s; do
|
|
cron:get_config "$s" "$env_hash" || return 1
|
|
done < <(e "$cfg" | p-err shyaml -q get-values-0 -y)
|
|
if [ "$E" != 0 ]; then
|
|
err "Failed to parse sequence while reading config."
|
|
return 1
|
|
fi
|
|
;;
|
|
"struct")
|
|
while read-0-err E k v; do
|
|
while read-0-err E1 schedule lock_opts title command; do
|
|
if [ -n "$title" ]; then
|
|
err "Unexpected label specified in struct."
|
|
echo " Using struct, the key will be used as label." >&2
|
|
echo " So you can't specify a label inner value(s)." >&2
|
|
return 1
|
|
fi
|
|
p0 "$schedule" "$lock_opts" "$k" "$command"
|
|
done < <(p-err cron:get_config "$v" "$env_hash")
|
|
if [ "$E1" != 0 ]; then
|
|
err "Failed to parse value of key '$k' in struct config."
|
|
return 1
|
|
fi
|
|
done < <(e "$cfg" | p-err shyaml -q key-values-0 -y)
|
|
if [ "$E" != 0 ]; then
|
|
err "Failed to parse key values while reading config."
|
|
return 1
|
|
fi
|
|
;;
|
|
"str")
|
|
## examples:
|
|
## (*/5 * * * *) {-k} bash -c "foo bla bla"
|
|
## (@daily) {-p 10 -D} bash -c "foo bla bla"
|
|
value=$(e "$cfg" | yaml_get_values) || {
|
|
err "Failed to parse str while reading config."
|
|
return 1
|
|
}
|
|
if ! [[ "$value" =~ ^[[:space:]]*([a-zA-Z0-9_-]+)?[[:space:]]*"("([^\)]+)")"[[:space:]]+\{([^\}]*)\}[[:space:]]*(.*)$ ]]; then
|
|
err "Invalid syntax, expected: 'LABEL (SCHEDULE) {LOCK_OPTIONS} COMMAND'."
|
|
echo " With LABEL being a possible empty string." >&2
|
|
echo " Received: '$value'" >&2
|
|
return 1
|
|
fi
|
|
printf "%s\0" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "${BASH_REMATCH[1]}" "${BASH_REMATCH[4]}"
|
|
;;
|
|
NoneType|"")
|
|
:
|
|
;;
|
|
*)
|
|
value=$(e "$cfg" | yaml_get_interpret) || {
|
|
err "Failed to parse value while reading config."
|
|
return 1
|
|
}
|
|
if [[ "$value" == "$cfg" ]]; then
|
|
err "Unrecognized type '$type'."
|
|
return 1
|
|
fi
|
|
cron:get_config "$value" "$env_hash" || return 1
|
|
;;
|
|
esac > "$cache_file.tmp"
|
|
|
|
mv "$cache_file.tmp" "$cache_file" >&2
|
|
|
|
## if cache file is empty, this is an error
|
|
if [ ! -s "$cache_file" ]; then
|
|
err "Unexpected empty relation options."
|
|
echo " - check that you don't overwrite default options with an empty relation" >&2
|
|
echo " - check your charm is setting default options" >&2
|
|
echo " Original value: '$cfg'" >&2
|
|
rm -f "$cache_file"
|
|
return 1
|
|
fi
|
|
|
|
cat "$cache_file"
|
|
}
|
|
|
|
|
|
|
|
cron:entries_from_service() {
|
|
local service="$1" relation_cfg="$2" \
|
|
cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$@")" \
|
|
label schedule lock_opts title command full_label H
|
|
if [ -e "$cache_file" ]; then
|
|
debug "$FUNCNAME: SESSION cache hit $1"
|
|
cat "$cache_file"
|
|
return 0
|
|
fi
|
|
|
|
## XXXvlab; should factorize this with compose-core to setup relation env
|
|
export BASE_SERVICE_NAME=$service
|
|
MASTER_BASE_SERVICE_NAME=$(get_top_master_service_for_service "$service") || return 1
|
|
MASTER_BASE_CHARM_NAME=$(get_service_charm "$MASTER_BASE_SERVICE_NAME") || return 1
|
|
BASE_CHARM_NAME=$(get_service_charm "$service") || return 1
|
|
BASE_CHARM_PATH=$(charm.get_dir "$BASE_CHARM_NAME") || return 1
|
|
export MASTER_BASE_{CHARM,SERVICE}_NAME BASE_CHARM_{PATH,NAME}
|
|
|
|
|
|
H=$(
|
|
env_vars=(MASTER_BASE_{CHARM,SERVICE}_NAME BASE_CHARM_{PATH,NAME} BASE_SERVICE_NAME)
|
|
values=()
|
|
for v in "${env_vars[@]}"; do
|
|
values+=("${!v}")
|
|
done
|
|
H "${values[@]}"
|
|
)
|
|
|
|
label="launch-$service"
|
|
while read-0-err E schedule lock_opts title command; do
|
|
lock_opts=($lock_opts)
|
|
if ! [[ "$schedule" =~ ^(([0-9/,*-]+[[:space:]]+){4,4}[0-9/,*-]+|@[a-z]+)$ ]]; then
|
|
err "Unrecognized schedule '$schedule'."
|
|
return 1
|
|
fi
|
|
## Check that label is only a simple identifier
|
|
if ! [[ "$title" =~ ^[a-zA-Z0-9_-]*$ ]]; then
|
|
err "Unexpected title '$title', please use only alphanumeric, underscore or dashes (can be empty)."
|
|
return 1
|
|
fi
|
|
if ! lock_opts=($(cron:lock_opts "${lock_opts[@]}")); then
|
|
err "Failed to parse lock options."
|
|
return 1
|
|
fi
|
|
if [ -z "$command" ]; then
|
|
err "Unexpected empty command."
|
|
return 1
|
|
fi
|
|
|
|
full_label="$label"
|
|
[ -n "$title" ] && full_label+="-$title"
|
|
|
|
## escape double-quotes
|
|
command=${command//\"/\\\"}
|
|
|
|
p0 "$schedule lock ${full_label} ${lock_opts[*]} -c \"$command\" 2>&1 | awk '{ print strftime(\"%Y-%m-%d %H:%M:%S %Z\"), \$0; fflush(); }' >> /var/log/cron/${full_label}_script.log"
|
|
|
|
done < <(p-err cron:get_config "$relation_cfg" "$H") > "$cache_file.tmp"
|
|
mv "$cache_file.tmp" "$cache_file" >&2
|
|
if [ "$E" != 0 ]; then
|
|
rm -f "$cache_file"
|
|
err "Failed to get ${DARKYELLOW}$service${NORMAL}--${DARKBLUE}schedule-command${NORMAL}-->${DARKYELLOW}$SERVICE_NAME${NORMAL}'s config."
|
|
return 1
|
|
fi
|
|
|
|
cat "$cache_file"
|
|
}
|
|
|
|
|
|
cron:lock_opts() {
|
|
local cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$@")" \
|
|
label schedule lock_opts title
|
|
if [ -e "$cache_file" ]; then
|
|
#debug "$FUNCNAME: SESSION cache hit $1"
|
|
cat "$cache_file"
|
|
return 0
|
|
fi
|
|
lock_opts=()
|
|
while [ "$1" ]; do
|
|
case "$1" in
|
|
"-D"|"-k")
|
|
lock_opts+=("$1")
|
|
;;
|
|
"-p")
|
|
## check that the value is a number
|
|
if ! [[ "$2" =~ ^[0-9]+$ ]]; then
|
|
err "Unexpected value for priority '$2' (expected an integer)."
|
|
return 1
|
|
fi
|
|
lock_opts+=(-p "$2")
|
|
shift
|
|
;;
|
|
"-*"|"--*")
|
|
err "Unrecognized lock option '$1'."
|
|
return 1
|
|
;;
|
|
*)
|
|
err "Unexpected lock argument '$1'."
|
|
return 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
printf "%s\n" "${lock_opts[@]}" > "$cache_file"
|
|
|
|
cat "$cache_file"
|
|
}
|
|
|
|
|
|
cron:entries() {
|
|
if [ -z "$SUBSET_ALL_RELATIONS_HASH" ]; then
|
|
err "Expected \$SUBSET_ALL_RELATIONS_HASH to be set."
|
|
return 1
|
|
fi
|
|
|
|
local cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$SERVICE_NAME" "$SUBSET_ALL_RELATIONS_HASH")"
|
|
local s rn ts rc td E
|
|
if [ -e "$cache_file" ]; then
|
|
#debug "$FUNCNAME: SESSION cache hit $1"
|
|
cat "$cache_file"
|
|
return 0
|
|
fi
|
|
|
|
export TARGET_SERVICE_NAME="$SERVICE_NAME"
|
|
while read-0-err E service relation_cfg; do
|
|
debug "service: '$service' relation_cfg:" >&2
|
|
e "$relation_cfg" | prefix " | " >&2
|
|
echo "" >&2
|
|
|
|
cron:entries_from_service "$service" "$relation_cfg" || {
|
|
err-d "Failed to get entries from service '$service'."
|
|
return 1
|
|
}
|
|
done < <(p-err get_service_incoming_relations "$SERVICE_NAME" "schedule-command") > "$cache_file.tmp"
|
|
if [ "$E" != 0 ]; then
|
|
rm -f "$cache_file.tmp"
|
|
err "Failed to get ${DARKYELLOW}*${NORMAL}--${DARKBLUE}schedule-command${NORMAL}-->${DARKYELLOW}$SERVICE_NAME${NORMAL}'s relations."
|
|
return 1
|
|
fi
|
|
mv "$cache_file"{.tmp,} >&2
|
|
cat "$cache_file"
|
|
}
|
|
export -f cron:entries
|