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.
 
 

210 lines
7.4 KiB

# -*- mode: shell-script -*-
cron:get_config() {
local cfg="$1"
local cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$@")" \
type value
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" || 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")
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" || return 1
;;
esac > "$cache_file.tmp"
mv -v "$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
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}
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") > "$cache_file"
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 command full_label
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() {
local cache_file="$CACHEDIR/$FUNCNAME.cache.$(H "$SERVICE_NAME" "$ALL_RELATIONS")" \
s rn ts rc td
if [ -e "$cache_file" ]; then
#debug "$FUNCNAME: SESSION cache hit $1"
cat "$cache_file"
return 0
fi
if [ -z "$ALL_RELATIONS" ]; then
err "Expected \$ALL_RELATIONS to be set."
exit 1
fi
export TARGET_SERVICE_NAME=$SERVICE_NAME
while read-0 service relation_cfg; do
debug "service: '$service' relation_cfg: '$relation_cfg'"
cron:entries_from_service "$service" "$relation_cfg" || return 1
done < <(get_service_incoming_relations "$SERVICE_NAME" "schedule-command") > "$cache_file"
cat "$cache_file"
}
export -f cron:entries