From 2d35e5960c7a3f7cfd6c1639bf0d631cb53aa29f Mon Sep 17 00:00:00 2001 From: tschettervictor <85497460+tschettervictor@users.noreply.github.com> Date: Fri, 9 May 2025 12:09:47 -0600 Subject: [PATCH] zfs: Support jailing and unjailing --- usr/local/share/bastille/zfs.sh | 140 +++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 21 deletions(-) diff --git a/usr/local/share/bastille/zfs.sh b/usr/local/share/bastille/zfs.sh index bddd675a..0a81e498 100644 --- a/usr/local/share/bastille/zfs.sh +++ b/usr/local/share/bastille/zfs.sh @@ -33,7 +33,10 @@ . /usr/local/share/bastille/common.sh usage() { - error_notify "Usage: bastille zfs TARGET [set|get|snap|destroy_snap|df|usage] [key=value|date]" + error_notify "Usage: bastille zfs TARGET [destroy_snap|df|get|set|(snap|snapshot)|usage] [key=value|date]" + error_notify " [jail pool/dataset /jail/path]" + error_notify " [unjail pool/dataset]" + cat << EOF Options: @@ -44,42 +47,130 @@ EOF exit 1 } +zfs_jail_dataset() { + + # Validate jail state + check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${_jail}" + else + info "\n[${_jail}]:" + error_notify "Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail." + fi + + info "\n[${_jail}]:" + + # Exit if MOUNT or DATASET is empty + if [ -z "${MOUNT}" ] || [ -z "${DATASET}" ]; then + usage + # Exit if datset does not exist + elif ! zfs list "${DATASET}" >/dev/null 2>/dev/null; then + error_exit "[ERROR]: Dataset does not exist: ${DATASET}" + fi + + # Ensure dataset is not already present in *zfs.conf* + if grep -hoqsw "${DATASET}" ${bastille_jailsdir}/*/zfs.conf; then + error_exit "[ERROR]: Dataset already assigned." + fi + + # Add necessary config variables to jail + bastille config ${_jail} set enforce_statfs 1 + bastille config ${_jail} set allow.mount + bastille config ${_jail} set allow.mount.devfs + bastille config ${_jail} set allow.mount.zfs + + # Add dataset to zfs.conf + echo "${DATASET} ${MOUNT}" >> "${bastille_jailsdir}/${_jail}/zfs.conf" + + if [ "${AUTO}" -eq 1 ]; then + bastille start "${_jail}" + fi +} + +zfs_unjail_dataset() { + + # Validate jail state + check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${_jail}" + else + info "\n[${_jail}]:" + error_notify "Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail." + fi + + info "\n[${_jail}]:" + + # Exit if DATASET is empty + if [ -z "${DATASET}" ]; then + usage + # Warn if datset does not exist + elif ! zfs list "${DATASET}" >/dev/null 2>/dev/null; then + warn "[WARNING]: Dataset does not exist: ${DATASET}" + fi + + # Remove dataset from zfs.conf + if ! grep -hoqsw "${DATASET}" ${bastille_jailsdir}/${_jail}/zfs.conf; then + error_exit "[ERROR]: Dataset not present in zfs.conf." + else + sed -i '' "\#.*${DATASET}.*#d" "${bastille_jailsdir}/${_jail}/zfs.conf" + fi + + if [ "${AUTO}" -eq 1 ]; then + bastille start "${_jail}" + fi +} + zfs_snapshot() { + info "\n[${_jail}]:" # shellcheck disable=SC2140 zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" } zfs_destroy_snapshot() { + info "\n[${_jail}]:" # shellcheck disable=SC2140 zfs destroy -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" } zfs_set_value() { + info "\n[${_jail}]:" zfs "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" } zfs_get_value() { + info "\n[${_jail}]:" zfs get "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" } zfs_disk_usage() { + info "\n[${_jail}]:" zfs list -t all -o name,used,avail,refer,mountpoint,compress,ratio -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" } - # Handle options. +AUTO=0 while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) usage ;; + -a|--auto) + AUTO=1 + shift + ;; -x|--debug) enable_debug shift ;; - -*) - error_notify "[ERROR]: Unknown Option: \"${1}\"" - usage + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + a) AUTO=1 ;; + x) enable_debug ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + esac + done + shift ;; *) break @@ -87,7 +178,7 @@ while [ "$#" -gt 0 ]; do esac done -if [ "$#" -lt 2 ]; then +if [ "$#" -lt 2 ] || [ "$#" -gt 4 ]; then usage fi @@ -111,21 +202,7 @@ for _jail in ${JAILS}; do ( - info "\n[${_jail}]:" - case "${ACTION}" in - set) - ATTRIBUTE="${3}" - zfs_set_value - ;; - get) - ATTRIBUTE="${3}" - zfs_get_value - ;; - snap|snapshot) - TAG="${3}" - zfs_snapshot - ;; destroy_snap|destroy_snapshot) TAG="${3}" zfs_destroy_snapshot @@ -133,6 +210,27 @@ for _jail in ${JAILS}; do df|usage) zfs_disk_usage ;; + get) + ATTRIBUTE="${3}" + zfs_get_value + ;; + jail) + DATASET="${3}" + MOUNT="${4}" + zfs_jail_dataset + ;; + unjail) + DATASET="${3}" + zfs_unjail_dataset + ;; + set) + ATTRIBUTE="${3}" + zfs_set_value + ;; + snap|snapshot) + TAG="${3}" + zfs_snapshot + ;; *) usage ;; @@ -143,4 +241,4 @@ for _jail in ${JAILS}; do bastille_running_jobs "${bastille_process_limit}" done -wait \ No newline at end of file +wait