aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Christian Pohle2021-04-19 01:19:53 +0200
committerMax Christian Pohle2021-04-19 01:19:53 +0200
commit1c561dc5e324cf82dcf70a91b681967b2fd35874 (patch)
tree066844e9b85494ba2d160920165abfe10198f9a3
parentb4136430d7408a0b26f8662c6387e78ac2c04cb6 (diff)
downloadzfs-bash-tools-1c561dc5e324cf82dcf70a91b681967b2fd35874.tar.bz2
zfs-bash-tools-1c561dc5e324cf82dcf70a91b681967b2fd35874.zip
Improved version of the squash scriptHEADmaster
-rwxr-xr-xzfs-squash-datasets.sh191
1 files changed, 68 insertions, 123 deletions
diff --git a/zfs-squash-datasets.sh b/zfs-squash-datasets.sh
index 3623edf..0e6d602 100755
--- a/zfs-squash-datasets.sh
+++ b/zfs-squash-datasets.sh
@@ -1,139 +1,84 @@
1#!/usr/local/bin/bash 1#!/bin/sh
2 2# This script expects a source dataset and a target dataset as arguments. It
3# DO NOT USE THIS SCRIPT 3# will then copy each snapshot of the source dataset into the target as a
4# It is in a state of hot garbage and will probably be deleted soon 4# subfolder with the name of the dataset. This is being archived by cloning the
5 5# source-dataset first into a sub-dataset of the source dataset named after the
6 6# snapshot. From there rsync is used to copy files into the target location.
7print_help_and_exit() { 7# After that finishes a snapshot will be created in the target with the original
8 echo "Please run this program with a source and a target dataset name as arguments" 8# snapshot-name and a suffix, which is the last part of the source dataset.
9 echo "e.g. $0 zpool/dataset1 zpool/dataset2" 9#
10 exit 10# Known Bugs:
11#
12# * This script will immidiatly stop when any command returns an error and it
13# will not clean up automatically the clones it created. But these clones are
14# not promoted by the script and can be deleted without altering the source
15# dataset and in order to re-execute the script after fixing the reason for the
16# error.
17#
18# * There is currently no sanity checking. Please do not copy files from a
19# dataset, which is a child of the source dataset.
20
21#
22# Example:
23#
24# ./zfs-squash-datasets.sh zpool/software zpool/projects
25#
26# would create a folder /zpool/projects/software within the dataset
27# zpool/projects
28
29
30
31set -o errexit
32
33getMountPoint() {
34 zfs get -H -o value mountpoint "$1" ||\
35 (echo "mountpoint for dataset '$1' not found" ; exit 1)
11} 36}
12 37
13SIMULATION=0 38listAllSnapshots() {
14 39 zfs list -H -o name -tsnap -r "$1" ||\
15args=$(getopt n $*) 40 (echo "Could not find snapshots under $1" ; exit 2)
16test $? == 0 || print_help_and_exit 41}
17
18set -- $args
19
20while :; do
21 sleep 1
22 echo $1
23 case "$1" in
24 --) shift; break ;;
25 -n) SIMULATION=1 ; shift ;;
26 esac
27done
28 42
29DATASET_ROOT=$1 43DATASET=$1
44DATASET_NAME=`basename $DATASET`
30DATASET_TARGET=$2 45DATASET_TARGET=$2
46TARGET_PATH=`basename $DATASET_TARGET`
31 47
32if ! zfs get mountpoint $DATASET_TARGET >/dev/null; then 48MP_TARGET=`getMountPoint $2`
33 echo "Dataset $DATASET_TARGET does not exist and will be created."
34 echo "You have 10 seconds to abort this with CTRL-C"
35 sleep 10
36 if ! $SIMULATION; then
37 zfs create $DATASET_TARGET
38 fi
39fi
40
41if zfs get -H -t filesystem -o name,value -r snapdir zeus/data/projects | grep -v visible >/dev/null; then
42 echo Please make all snapdirs visible:
43 zfs get -H -t filesystem -o name,value -r snapdir zeus/data/projects
44 exit 2
45fi
46
47
48MOUNTPOINT_TARGET=$(zfs get -o value -H mountpoint $DATASET_TARGET)
49test ${SIMULATION:0} = 1 && test $MOUNTPOINT_TARGET == "" && MOUNTPOINT_TARGET="datapool/simulation"
50
51test -d "$MOUNTPOINT_TARGET" || print_help_and_exit
52 49
53# make sure, that ctrl-c also works in the inner loops 50test -d "$MP_TARGET" || (echo "failed to find mountpoint for $DATASET_TARGET: Its not $MP_TARGET" ; exit 3)
54trap exit INT
55 51
56# recursively contains all snapshot names (the part after the @) from root on, sorted and only once 52for i in `listAllSnapshots $DATASET`; do
57SNAPSHOTS=$(zfs list -H -oname -tsnap -r $DATASET_ROOT | cut -d@ -f2 | sort -u) 53 SNAPSHOT=`echo "$i" | cut -d@ -f2`
58DATASETS=$(zfs list -H -oname -t filesystem -r $DATASET_ROOT)
59 54
60test "${SIMULATION:-0}" = 1 && echo "SIMULATION MODE" 55 CLONETMP="$DATASET/$SNAPSHOT"
61 56
62$DATASETS 57 zfs clone "$i" "$CLONETMP" ||\
58 (echo "Failed to create clone" ; exit 4)
63 59
60 MP_CLONE=`getMountPoint $CLONETMP`
64 61
65echo "We are going to flatten the hierachy of this dataset:" 62 test -d "$MP_CLONE" ||\
66printf "\t%s\n" $DATASETS 63 (echo "$CLONETMP: clones mount point not found" ; exit 5)
67echo -e "into the dataset with the name:"
68echo -e "\t$DATASET_TARGET"
69echo -e "mounted under:"
70echo -e "\t$MOUNTPOINT_TARGET"
71echo -e "with the following snapshots:"
72printf "\t%s\n" $SNAPSHOTS
73echo ""
74echo "You have 10 seconds to abort this with CTRL-C"
75sleep 10
76 64
77set -- $SNAPSHOTS
78SNAPSHOTS_TOTAL=$#
79SNAPSHOT_CURRENT=0
80 65
81set -- $DATASETS 66 # copy all files to the target location
82shift 67 (set -x ; rsync -ahox --info=progress2 --delete "$MP_CLONE/" "$MP_TARGET/$TARGET_PATH" ||\
83SUBDATASETS=$@ 68 (echo "rsync exit status was $?" ; exit 6)
69 )
70
71 (set -x ; zfs snap "$DATASET_TARGET@$SNAPSHOT-$DATASET_NAME" ||\
72 (echo "failed to create a snapshot $DATASET_TARGET: $SNAPSHOT-$DATASET_NAME" ; exit 7)
73 )
84 74
85for SNAPSHOT in $SNAPSHOTS; do 75 # move clone out of the source dataset, so that we can resume
86 echo "" 76 # zfs promote "$CLONETMP" ||\
87 echo "" 77 # (echo "Failed to promote clone '$CLONETMP'" ; exit 8)
88 SNAPSHOT_CURRENT=$((SNAPSHOT_CURRENT + 1)) 78 zfs destroy "$CLONETMP" ||\
89 echo "[$SNAPSHOT_CURRENT/$SNAPSHOTS_TOTAL] Next snapshot is: $SNAPSHOT" 79 (echo "Failed to destroy clone '$CLONETMP'" ; exit 8)
90 80
91 for DATASET in $SUBDATASETS; do 81 # for better readability add two blank lines...
92 82 echo
93 DATASET_RELATIVE=${DATASET##$DATASET_ROOT} 83 echo
94
95 MOUNTPOINT=$(zfs get -H -o value mountpoint $DATASET)
96 echo "RELATIVE=$DATASET_RELATIVE"
97
98 if [[ $MOUNTPOINT == "legacy" ]]; then
99 MOUNTPOINT=$(findmnt -n -o target $DATASET)
100 if test -d $MOUNTPOINT; then
101 >&2 echo "Dataset has a legacy mountpoint, but was not found in the fstab: $DATASET"
102 continue
103 fi
104 fi
105
106 if [[ $MOUNTPOINT == "-" ]]; then
107 >&2 echo "Dataset does not have a mount point or is a vdev: $DATASET"
108 continue
109 fi
110
111 SNAPDIR=$MOUNTPOINT/.zfs/snapshot/$SNAPSHOT
112 if test -d $SNAPDIR; then
113
114 TARGET_DIR="${MOUNTPOINT_TARGET}${DATASET_RELATIVE}"
115
116 echo -e \\trsync --info=stats3 --delete -a "$SNAPDIR/" "$TARGET_DIR/"
117 if test "${SIMULATION:-0}" = 0; then
118
119 mkdir -p "$TARGET_DIR"
120
121 if ! rsync --info=stats3 --delete -a "$SNAPDIR/" "$TARGET_DIR/" ; then
122 >&2 echo "rsync could not entirely copy from $SNAPDIR to $DATASET_TARGET"
123 fi
124 fi
125 else
126 echo -e "\tSKIP: Snapshot $SNAPSHOT does not exist for dataset $DATASET"
127 fi
128 done
129
130 NEW_SNAPSHOT="$DATASET_TARGET@$SNAPSHOT"
131 echo ""
132 echo -e "\t> Concluding snapshot: ${NEW_SNAPSHOT} <"
133 echo ""
134
135 if test "${SIMULATION:-0}" = 0; then
136 zfs snap $NEW_SNAPSHOT
137 fi
138done 84done
139
..