Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


## [Unreleased]

### Added
- [SNAPSHOT] Add an option to snapshot's command in order to delete a specific snapshot

## [1.0.4] - 2025-10-29
### Added
Expand Down
62 changes: 62 additions & 0 deletions usr/local/share/vulture-utils/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,68 @@ clean_old_BEs() {
done
}

# Delete a specific boot environment
delete_BE() {
_be_name="$1"

if [ -z "${_be_name}" ]; then
error "[!] No Boot Environment name provided"
return 1
fi

# Check if BE exists in the list of vulture BEs
_existing_bes="$(get_vlt_BEs | cut -f 1)"
if ! contains_word "${_existing_bes}" "${_be_name}"; then
error "[!] Boot Environment '${_be_name}' not found"
return 1
fi

# Check if BE is currently active (status contains 'N')
_be_status="$(get_BEs | grep "^${_be_name} " | cut -f 2)"
if printf "%s" "${_be_status}" | grep -q "N"; then
error "[!] Cannot delete active Boot Environment '${_be_name}'"
return 1
fi

echo "Destroying Boot Environment: '${_be_name}'"
/sbin/bectl destroy -o "${_be_name}"
return $?
}

# Delete a specific snapshot from datasets
delete_snapshot_from_datasets() {
_datasets="$1" # space-separated list of datasets
_snap_to_delete="$2" # snapshot name to delete
_zpool="$(get_root_zpool_name)"
_deleted_count=0

if [ -z "${_datasets}" ] || [ -z "${_snap_to_delete}" ]; then
error "[!] Missing arguments for snapshot deletion"
return 1
fi

for _dataset in ${_datasets}; do
if zfs_dataset_exists "${_dataset}"; then
_existing_snaps="$(list_snapshots "${_dataset}")"
if contains_word "${_existing_snaps}" "${_snap_to_delete}"; then
echo "Deleting snapshot '${_zpool}/${_dataset}@${_snap_to_delete}'"
if /sbin/zfs destroy "${_zpool}/${_dataset}@${_snap_to_delete}"; then
_deleted_count=$((_deleted_count + 1))
else
error "[!] Failed to delete snapshot '${_zpool}/${_dataset}@${_snap_to_delete}'"
fi
fi
fi
done

if [ "${_deleted_count}" -eq 0 ]; then
warn "[!] No snapshot '${_snap_to_delete}' found in specified datasets"
return 1
fi

return 0
}


############################
## Snapshotting functions ##
Expand Down
37 changes: 34 additions & 3 deletions usr/local/share/vulture-utils/snapshot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ snap_name="${SNAPSHOT_PREFIX}SNAP_$(date -u +%Y%m%d_%H%M%S)"
list_snaps=0
snapshot_system=0
keep_previous_snap=-1
delete_snapshot_mode=0
delete_snapshot_name=""
_mongo_locked=0
_snapshot_datasets_list=""

Expand All @@ -21,6 +23,7 @@ usage() {
echo "This command triggers snapshots on all or specific datasets, those snapshot points are then available for restorations"
echo ""
echo "OPTIONS:"
echo " -h Show this help banner"
echo " -A Snapshot all underlying datasets"
echo " -S Snapshot the system dataset(s)"
echo " -J Snapshot the jail(s) dataset(s)"
Expand All @@ -29,6 +32,7 @@ usage() {
echo " -T Snapshot the tmp/var dataset(s)"
echo " -l Only list datasets"
echo " -k <num> Keep <num> snapshots for the targeted datasets"
echo " -d <name> Delete snapshot <name> from targeted datasets (use with -A, -S, -J, -H, -D, -T)"
exit 1
}

Expand All @@ -38,7 +42,7 @@ if [ "$(/usr/bin/id -u)" != "0" ]; then
exit 1
fi

while getopts 'hASJDHTlk:' opt; do
while getopts 'hASJDHTlk:d:' opt; do
case "${opt}" in
A) _snapshot_datasets_list="SYSTEM JAIL DB HOMES TMPVAR";
snapshot_system=1;
Expand All @@ -58,6 +62,9 @@ while getopts 'hASJDHTlk:' opt; do
;;
k) keep_previous_snap=${OPTARG};
;;
d) delete_snapshot_mode=1;
delete_snapshot_name="${OPTARG}";
;;
h|*) usage;
;;
esac
Expand Down Expand Up @@ -92,13 +99,29 @@ finalize_early() {
finalize 1 "Stopped"
}

if [ "${delete_snapshot_mode}" -gt 0 ]; then
if [ -z "${delete_snapshot_name}" ]; then
error "[!] Snapshot name required with -d option"
usage
fi
if [ "${snapshot_system}" -eq 0 ] && [ -z "${_snapshot_datasets_list}" ]; then
error "[!] Delete mode requires at least one dataset selector (-A, -S, -J, -H, -D, or -T)"
usage
fi
fi

if [ "${list_snaps}" -gt 0 ]; then
_be_list="$(get_vlt_BEs | cut -f 1)"
printf "SYSTEM:\t"
for _be in $_be_list; do
printf "%s\t" "$_be"
done
printf "\n"
elif [ "${delete_snapshot_mode}" -gt 0 ] && [ "$snapshot_system" -gt 0 ]; then
echo "Deleting snapshot '${delete_snapshot_name}' from SYSTEM datasets"
if ! delete_BE "${delete_snapshot_name}"; then
finalize 1 "Failed to delete SYSTEM snapshot '${delete_snapshot_name}'"
fi
elif [ "$snapshot_system" -gt 0 ]; then
echo "making new snapshot for SYSTEM datasets"
/sbin/bectl create "$snap_name"
Expand All @@ -119,7 +142,15 @@ for _type in ${AVAILABLE_DATASET_TYPES}; do
printf "%s\t" "$_snap"
done
printf "\n"
# snapshotting datasets
# Delete snapshots
elif [ "${delete_snapshot_mode}" -gt 0 ]; then
# Ignore datasets not explicitely selected
if ! contains_word "${_snapshot_datasets_list}" "${_type}"; then
continue
fi
echo "Deleting snapshot '${delete_snapshot_name}' from ${_type} datasets"
delete_snapshot_from_datasets "$_type_datasets" "$delete_snapshot_name"
# Snapshotting datasets (normal mode)
else
# Ignore datasets not explicitely selected
if ! contains_word "${_snapshot_datasets_list}" "${_type}"; then
Expand All @@ -138,4 +169,4 @@ for _type in ${AVAILABLE_DATASET_TYPES}; do
fi
done

finalize
finalize