Skip to content

Instantly share code, notes, and snippets.

@otherwiseguy
Created April 28, 2026 16:24
Show Gist options
  • Select an option

  • Save otherwiseguy/441ac95e69a7b86f04d11b2f460b4eb4 to your computer and use it in GitHub Desktop.

Select an option

Save otherwiseguy/441ac95e69a7b86f04d11b2f460b4eb4 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Default to 3 day warning time just to give a heads-up before a weekend
WARN_HOURS=${DNEST_WARN_HOURS:-72}
# For testing purposes, let a leading 0 signify minutes so we can warn almost immediately
if [[ "$WARN_HOURS" == 0* ]]; then
WARN_UNIT=minutes
WARN_VAL=${WARN_HOURS#0}
else
WARN_UNIT=hours
WARN_VAL=$WARN_HOURS
fi
# Normalise to minutes for internal scheduling
WARN_MINS=$(( WARN_UNIT == "minutes" ? WARN_VAL : WARN_VAL * 60 ))
ATJOB_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/dnest
mkdir -p "$ATJOB_DIR"
cancel_warning() {
local atjob_file="$ATJOB_DIR/$1"
[ -f "$atjob_file" ] && atrm "$(cat "$atjob_file")" 2>/dev/null && rm -f "$atjob_file"
}
# Schedule a warning at warn_minutes from now
schedule_warning() {
local machine="$1"
local warn_minutes="$2"
cancel_warning "$machine"
if (( warn_minutes > 0 )); then
local job_id
job_id=$(echo "notify-send -u critical 'DevNest Warning' 'Reservation for $machine expires in ${WARN_VAL} ${WARN_UNIT}'" \
| at now + ${warn_minutes} minutes 2>&1 | awk '/^job/ {print $2}')
[ -n "$job_id" ] && echo "$job_id" > "$ATJOB_DIR/$machine"
fi
}
usage() {
cat <<EOF
Usage: dnest [SUBCOMMAND] [OPTIONS] MACHINE
A wrapper around devnest that schedules a GNOME notification before your
reservation expires. All unrecognised subcommands are passed through to devnest.
Subcommands:
reserve (default) Reserve a machine. Same as omitting the subcommand.
extend Extend an existing reservation.
release Release a machine and cancel any pending warning.
<anything else> Passed through directly to devnest.
Options (reserve):
-g GROUP Node group (required by devnest)
-t TIME Reservation length in hours
-j Output node info as JSON
-f Force reserve even if a CI job is running
Options (extend):
-t TIME Number of hours to extend by
Warning behaviour:
A persistent GNOME notification is sent DNEST_WARN_HOURS before the
reservation expires (default: 72h). If you extend or release, any
previously scheduled warning is cancelled and rescheduled as needed.
DNEST_WARN_HOURS Override the warning lead time (default: 72).
A value with a leading zero is treated as minutes,
which is useful for testing, e.g.:
DNEST_WARN_HOURS=059 -> warn 59 minutes before expiry
Examples:
dnest -g network -t 240 myhost
dnest reserve -g network -t 240 myhost
dnest extend -t 120 myhost
dnest release myhost
dnest list -g network
DNEST_WARN_HOURS=059 dnest -g network -t1 myhost # test: warn in 1 min
EOF
}
ACTION="${1}"
case "$ACTION" in
-h | --help)
usage
exit 0
;;
extend)
shift
while getopts ":t:" opt; do
case "$opt" in
t) ;;
esac
done
machine="${@: -1}"
output=$(devnest extend "$@" 2>&1)
echo "$output"
if echo "$output" | grep -q "reserved until"; then
end_time=$(echo "$output" | grep -oP 'reserved until: \K[\d/]+, [\d:]+' | tr '/' '-' | tr -d ',')
end_epoch=$(date -d "$end_time" +%s)
remaining_minutes=$(( (end_epoch - $(date +%s)) / 60 ))
[ -n "$machine" ] && schedule_warning "$machine" $(( remaining_minutes - WARN_MINS ))
fi
;;
reserve | -* | "")
[ "$ACTION" = "reserve" ] && shift
res_time=""
while getopts ":t:g:jf" opt; do
case "$opt" in
t) res_time=$OPTARG ;;
esac
done
machine="${@: -1}"
if devnest reserve "$@"; then
[ -n "$res_time" ] && [ -n "$machine" ] && \
schedule_warning "$machine" $(( res_time * 60 - WARN_MINS ))
fi
;;
release)
machine="${@: -1}"
if devnest "$@"; then
cancel_warning "$machine"
fi
;;
*)
devnest "$@"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment