mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-19 19:01:42 +00:00
207 lines
8.5 KiB
Bash
207 lines
8.5 KiB
Bash
#!/bin/sh
|
|
# rds-datadir — select, authorize, prepare, and mount the exact data volume
|
|
# assigned by the control plane before rds-init touches the engine's datadir.
|
|
#
|
|
# Shared by every RDS image preset. The mount point and the OS user that owns it
|
|
# are the one engine-specific pair here, and both are supplied by the preset's
|
|
# own service rather than defaulted, so no image can inherit another's layout.
|
|
set -eu
|
|
|
|
DATA_MOUNT="${RDS_DATA_MOUNT:-}"
|
|
ENGINE_USER="${RDS_ENGINE_USER:-}"
|
|
SYS_BLOCK="${RDS_SYS_BLOCK:-/sys/block}"
|
|
DEV_DIR="${RDS_DEV_DIR:-/dev}"
|
|
MOUNTS_FILE="${RDS_MOUNTS_FILE:-/proc/mounts}"
|
|
WAIT_SECS="${RDS_DATA_VOLUME_WAIT:-120}"
|
|
FS_LABEL="${RDS_DATA_FS_LABEL:-rds-data}"
|
|
HANDOFF_ENV="${RDS_HANDOFF_ENV:-${RDS_HANDOFF_DIR:-/run/spinifex-rds}/bootstrap.env}"
|
|
|
|
log() { echo "[rds-datadir] $*"; }
|
|
fail() { echo "[rds-datadir] ERROR: $*" >&2; exit 1; }
|
|
|
|
load_handoff() {
|
|
[ -f "${HANDOFF_ENV}" ] || fail "no bootstrap handoff at ${HANDOFF_ENV}; refusing to discover or format a volume"
|
|
# Root-owned content written with shell-safe quoting by rds-agent.
|
|
# shellcheck disable=SC1090
|
|
. "${HANDOFF_ENV}"
|
|
|
|
RDS_DATA_VOLUME_ID="${RDS_DATA_VOLUME_ID:-}"
|
|
RDS_DATA_VOLUME_SERIAL="${RDS_DATA_VOLUME_SERIAL:-}"
|
|
RDS_VM_GENERATION="${RDS_VM_GENERATION:-}"
|
|
RDS_FORMAT_AUTHORIZED="${RDS_FORMAT_AUTHORIZED:-false}"
|
|
|
|
[ -n "${RDS_DATA_VOLUME_ID}" ] || fail "bootstrap handoff has no RDS_DATA_VOLUME_ID"
|
|
[ -n "${RDS_DATA_VOLUME_SERIAL}" ] || fail "bootstrap handoff has no RDS_DATA_VOLUME_SERIAL"
|
|
case "${RDS_VM_GENERATION}" in
|
|
''|*[!0-9]*|0) fail "bootstrap handoff has invalid RDS_VM_GENERATION '${RDS_VM_GENERATION}'" ;;
|
|
esac
|
|
case "${RDS_FORMAT_AUTHORIZED}" in
|
|
true|false) ;;
|
|
*) fail "bootstrap handoff has invalid RDS_FORMAT_AUTHORIZED '${RDS_FORMAT_AUTHORIZED}'" ;;
|
|
esac
|
|
}
|
|
|
|
mounted_source() {
|
|
awk -v mnt="${DATA_MOUNT}" '$2 == mnt { print $1; found = 1; exit } END { exit !found }' "${MOUNTS_FILE}"
|
|
}
|
|
|
|
# Only an exact serial match is a candidate; other vol* devices are unrelated
|
|
# attachments and are deliberately ignored. The loop status must not depend on
|
|
# the last device examined, or set -e would abort the caller's wait and report.
|
|
data_disks() {
|
|
for _p in "${SYS_BLOCK}"/*; do
|
|
[ -r "${_p}/serial" ] || continue
|
|
_serial=$(cat "${_p}/serial" 2>/dev/null || true)
|
|
if [ "${_serial}" = "${RDS_DATA_VOLUME_SERIAL}" ]; then
|
|
basename "${_p}"
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
await_data_disk() {
|
|
_waited=0
|
|
while :; do
|
|
_found=$(data_disks)
|
|
_count=$(printf '%s\n' "${_found}" | grep -c . || true)
|
|
if [ "${_count}" -gt 1 ]; then
|
|
fail "found ${_count} devices with expected serial ${RDS_DATA_VOLUME_SERIAL}; refusing to choose one"
|
|
fi
|
|
# Sysfs appears before the device node. A probe cannot classify a node
|
|
# that is not present yet, so both must exist before the wait ends.
|
|
if [ "${_count}" = "1" ] && [ -e "${DEV_DIR}/${_found}" ]; then
|
|
printf '%s\n' "${_found}"
|
|
return 0
|
|
fi
|
|
if [ "${_waited}" -ge "${WAIT_SECS}" ]; then
|
|
fail "volume ${RDS_DATA_VOLUME_ID} with serial ${RDS_DATA_VOLUME_SERIAL} was not attached after ${WAIT_SECS}s"
|
|
fi
|
|
sleep 1
|
|
_waited=$((_waited + 1))
|
|
done
|
|
}
|
|
|
|
has_partitions() {
|
|
for _part in "${SYS_BLOCK}/$1/$1"*; do
|
|
[ -d "${_part}" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
consume_format_authorization() {
|
|
[ "${RDS_FORMAT_AUTHORIZED}" = "true" ] || return 0
|
|
_tmp="${HANDOFF_ENV}.consume.$$"
|
|
if ! awk '!/^RDS_FORMAT_AUTHORIZED=/' "${HANDOFF_ENV}" > "${_tmp}"; then
|
|
rm -f "${_tmp}"
|
|
fail "could not remove the consumed format authorization from ${HANDOFF_ENV}"
|
|
fi
|
|
chmod 0600 "${_tmp}" || {
|
|
rm -f "${_tmp}"
|
|
fail "could not secure the rewritten bootstrap handoff"
|
|
}
|
|
mv -f "${_tmp}" "${HANDOFF_ENV}" || {
|
|
rm -f "${_tmp}"
|
|
fail "could not install the bootstrap handoff without its consumed format authorization"
|
|
}
|
|
RDS_FORMAT_AUTHORIZED=false
|
|
}
|
|
|
|
main() {
|
|
# An unset layout is a broken image, not something to guess at: mounting the
|
|
# customer's volume where the engine is not looking would read as an empty
|
|
# datadir and bootstrap a second, empty database beside their data.
|
|
[ -n "${DATA_MOUNT}" ] ||
|
|
fail "RDS_DATA_MOUNT is not set; refusing to guess where this engine's datadir belongs"
|
|
[ -n "${ENGINE_USER}" ] ||
|
|
fail "RDS_ENGINE_USER is not set; refusing to guess which user owns this engine's datadir"
|
|
|
|
load_handoff
|
|
|
|
command -v blkid >/dev/null 2>&1 ||
|
|
fail "blkid is not installed; refusing to classify the expected volume"
|
|
|
|
_disk=$(await_data_disk)
|
|
_dev="${DEV_DIR}/${_disk}"
|
|
log "volume ${RDS_DATA_VOLUME_ID} generation ${RDS_VM_GENERATION} attached as ${_dev}"
|
|
|
|
if _mounted=$(mounted_source 2>/dev/null); then
|
|
[ "${_mounted}" = "${_dev}" ] ||
|
|
fail "${DATA_MOUNT} is mounted from ${_mounted}, not expected device ${_dev}"
|
|
consume_format_authorization
|
|
log "${DATA_MOUNT} is already mounted from the expected device"
|
|
return 0
|
|
fi
|
|
|
|
# Low-level probing exposes partition tables and returns a distinct failure
|
|
# for ambiguous signatures. Exit 2 also covers read failures, so stderr must
|
|
# be empty before it can be treated as a signature-free device.
|
|
_probe_err="${HANDOFF_ENV}.blkid.$$"
|
|
umask 077
|
|
# A redirection that cannot be created leaves blkid unrun and returns the
|
|
# shell's own status, which some shells report as the blank-device exit 2.
|
|
# `true` is a regular builtin, so the failure is catchable rather than fatal.
|
|
true > "${_probe_err}" ||
|
|
fail "could not create the probe error capture at ${_probe_err}; refusing to classify ${_dev}"
|
|
if _probe=$(blkid -p -o export "${_dev}" 2>"${_probe_err}"); then
|
|
_probe_rc=0
|
|
else
|
|
_probe_rc=$?
|
|
fi
|
|
_probe_stderr=$(cat "${_probe_err}" 2>/dev/null || true)
|
|
rm -f "${_probe_err}"
|
|
if [ "${_probe_rc}" -eq 2 ] && [ -n "${_probe_stderr}" ]; then
|
|
fail "could not read ${_dev} while probing it; refusing to classify it as blank"
|
|
fi
|
|
|
|
case "${_probe_rc}" in
|
|
0)
|
|
_pttype=$(printf '%s\n' "${_probe}" | awk -F= '$1 == "PTTYPE" { print $2 }')
|
|
_types=$(printf '%s\n' "${_probe}" | awk -F= '$1 == "TYPE" { print $2 }')
|
|
_type_count=$(printf '%s\n' "${_types}" | grep -c . || true)
|
|
if [ -n "${_pttype}" ] || has_partitions "${_disk}"; then
|
|
fail "${_dev} carries a partition table or partitions; refusing to mount or format it"
|
|
fi
|
|
[ "${_type_count}" = "1" ] ||
|
|
fail "${_dev} has conflicting or incomplete filesystem signatures; refusing to use it"
|
|
case "${_types}" in
|
|
ext4|xfs) _fstype="${_types}" ;;
|
|
*) fail "${_dev} holds unsupported filesystem ${_types}; refusing to use it" ;;
|
|
esac
|
|
# A grant left after mkfs but before local consumption must not
|
|
# survive once the newly recognizable filesystem is observed.
|
|
consume_format_authorization
|
|
log "${_dev} already holds a supported ${_fstype} filesystem"
|
|
;;
|
|
2)
|
|
if has_partitions "${_disk}"; then
|
|
fail "${_dev} carries partitions but no supported whole-disk filesystem; refusing to format it"
|
|
fi
|
|
[ "${RDS_FORMAT_AUTHORIZED}" = "true" ] ||
|
|
fail "${_dev} has no recognizable filesystem and this boot has no matching format authorization"
|
|
log "formatting authorized volume ${RDS_DATA_VOLUME_ID} as ext4"
|
|
mkfs.ext4 -q -L "${FS_LABEL}" -m 0 "${_dev}" ||
|
|
fail "mkfs.ext4 failed on ${_dev}"
|
|
# Consume before mount. If mounting later fails, the next run sees
|
|
# ext4 and mounts it without receiving another chance to format.
|
|
consume_format_authorization
|
|
_fstype=ext4
|
|
;;
|
|
8)
|
|
fail "${_dev} has ambiguous or conflicting signatures; refusing to use it"
|
|
;;
|
|
*)
|
|
fail "could not probe ${_dev} (blkid exit ${_probe_rc}); refusing to classify it as blank"
|
|
;;
|
|
esac
|
|
|
|
mount -t "${_fstype}" "${_dev}" "${DATA_MOUNT}" ||
|
|
fail "could not mount ${_dev} at ${DATA_MOUNT}"
|
|
chown "${ENGINE_USER}:${ENGINE_USER}" "${DATA_MOUNT}" ||
|
|
fail "could not set ${ENGINE_USER} ownership on ${DATA_MOUNT}"
|
|
chmod 0750 "${DATA_MOUNT}"
|
|
|
|
log "${DATA_MOUNT} ready on ${_dev}"
|
|
}
|
|
|
|
main "$@"
|