root/manageBE/manageBE

Revision 99, 12.2 KB (checked in by cryx, 3 months ago)

Import some stuff of my head-version
- add src-upgrade option
- add freebsd-update update and upgrade option
- support child-filesystems in BEs by using fstab
- use the current active BE as the default source
- some minor fixes

Line 
1#!/bin/sh
2
3# manageBE [activate|create|delete|list|src-upgrade|freebsd-update|freebsd-upgrade] {params}
4
5if [ `uname -r |cut -d '.' -f1` -lt "8" ]; then
6    echo "Sorry, only FreeBSD starting with 8.0 is supported."
7fi
8
9type=$1
10
11mgm="manageBE"
12usage_activate="Usage: ${mgm} activate -n <BE> -p <pool>"
13usage_create="Usage: ${mgm} create -n <newBE> -s <sourceBE> -p <pool>"
14usage_delete="Usage: ${mgm} delete -n <BE> -p <pool> -o [yes|no]"
15usage_src_upgrade="Usage: ${mgm} src-upgrade -n <BE> -p <pool>"
16usage_freebsd_update="Usage: ${mgm} freebsd-update -n <BE> -p <pool>"
17usage_freebsd_upgrade="Usage: ${mgm} freebsd-upgrade -n <BE> -p <pool> -r <release>"
18not_supported="Sorry, your FreeBSD version does not support this option"
19
20error_delete="If filesystem has dependent clones, please promote them via 'zfs promote <filesystem>' and re-run ${mgm} delete"
21
22# define our bail out shortcut
23exerr () { echo -e "$*" >&2 ; exit 1; }
24
25check_for_be_existence () {
26    be_status=`/sbin/zfs list -H -o freebsd:boot-environment ${pool}/ROOT/${bootfs} 2> /dev/null` 
27    if [ "${be_status}" != "1" ]; then
28        echo "Sorry, ${bootfs} is no valid boot-environment"
29        exit
30    fi
31}
32
33case ${type} in
34    activate)
35        # activate a boot-environment
36
37        shift; while getopts :n:p: arg; do case ${arg} in
38            n) bootfs=${OPTARG};;
39            p) pool=${OPTARG};;
40            ?) exerr ${usage_activate};;
41        esac; done; shift $(( ${OPTIND} - 1 ))
42
43        [ "${bootfs}" -a "${pool}" ] || exerr ${usage_activate}
44
45        check_for_be_existence
46
47        old_bootfs=`/sbin/zpool list -H -o bootfs ${pool} |/usr/bin/sed s:^$pool/ROOT/::`
48        /sbin/zpool set bootfs=${pool}/ROOT/${bootfs} ${pool}
49
50        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${bootfs}`; do
51          /sbin/zfs promote ${filesystem}
52        done
53    ;;
54    create)
55        # create a boot-environment
56
57        shift; while getopts :n:s:p: arg; do case ${arg} in
58            n) new_bootfs=${OPTARG};;
59            s) bootfs=${OPTARG};;
60            p) pool=${OPTARG};;
61            ?) exerr ${usage_create};;
62        esac; done; shift $(( ${OPTIND} - 1 ))
63
64        [ "${new_bootfs}" -a "${pool}" ] || exerr ${usage_create}
65       
66        if [ -z "${bootfs}" ]; then
67            bootfs=`/sbin/zpool list -H -o bootfs ${pool} | /usr/bin/sed s:${pool}/ROOT/::`
68        fi
69
70        check_for_be_existence
71
72        # create snapshot of the source BE and clone the snapshot to create the new BE
73        /sbin/zfs snapshot -r ${pool}/ROOT/${bootfs}@${new_bootfs}
74        /sbin/zfs clone ${pool}/ROOT/${bootfs}@${new_bootfs} ${pool}/ROOT/${new_bootfs}
75
76        # clone the children snapshot to create the new BE children, mark the filesystem as not being BEs
77        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${bootfs} | /usr/bin/sed s:${pool}/ROOT/${bootfs}:: | /usr/bin/sed s:^/:: | /usr/bin/xargs`; do
78          /sbin/zfs clone ${pool}/ROOT/${bootfs}/${filesystem}@${new_bootfs} ${pool}/ROOT/${new_bootfs}/${filesystem}
79          /sbin/zfs set freebsd:boot-environment=0 ${pool}/ROOT/${new_bootfs}/${filesystem}
80        done
81
82        # mark the BE as boot-environment and mount the freebsd-update dir in the correct path
83        /sbin/zfs set freebsd:boot-environment=1 ${pool}/ROOT/${new_bootfs}
84
85        grep -v '^vfs.root.mountfrom' /boot/loader.conf > /${pool}/ROOT/${new_bootfs}/boot/loader.conf
86        echo vfs.root.mountfrom=\"zfs:${pool}/ROOT/${new_bootfs}\" >> /${pool}/ROOT/${new_bootfs}/boot/loader.conf
87       
88        # fill the fstab with the mounts of the BE children
89        grep -v ${pool}/ROOT/${bootfs} /etc/fstab > /${pool}/ROOT/${new_bootfs}/etc/fstab
90        echo "# Automatically generated by manageBE (${pool}/ROOT/${new_bootfs})" >> /${pool}/ROOT/${new_bootfs}/etc/fstab
91        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${new_bootfs} | /usr/bin/sed s:${pool}/ROOT/${new_bootfs}:: | /usr/bin/sed s:^/:: | /usr/bin/xargs`; do
92          echo "${pool}/ROOT/${new_bootfs}/${filesystem} /${filesystem} zfs rw 0 0" >> /${pool}/ROOT/${new_bootfs}/etc/fstab
93        done
94
95        echo "The new Boot-Environment is ready to be updated and/or activated."
96    ;;
97    delete)
98        # delete a boot-environment
99
100        shift; while getopts :n:p:o: arg; do case ${arg} in
101            n) bootfs=${OPTARG};;
102            p) pool=${OPTARG};;
103            o) delete_origin=${OPTARG};;
104            ?) exerr ${usage_delete};;
105        esac; done; shift $(( ${OPTIND} - 1 ))
106
107        [ "${bootfs}" -a "${pool}" -a "${delete_origin}" ] || exerr ${usage_delete}
108
109        check_for_be_existence
110
111        current_bootfs=`/sbin/zpool list -H -o bootfs ${pool}`
112
113        if [ ! "${pool}/ROOT/${bootfs}" = "${current_bootfs}" ]; then
114            if [ "${delete_origin}" = "yes" ]; then
115               origin=`/sbin/zfs list -H -o origin ${pool}/ROOT/${bootfs}`
116            fi
117            /sbin/zfs destroy -r ${pool}/ROOT/${bootfs} || exerr ${error_delete}
118            if [ "${delete_origin}" = "yes" -a "${origin}" ]; then
119                /sbin/zfs destroy -r ${origin}
120            fi
121        else
122            echo "${bootfs} is ZFS bootfs, unable to delete!"
123        fi
124    ;;
125    list)
126        shift; while getopts :v: arg; do
127            verbose="YES";
128        done; shift $(( ${OPTIND} - 1 ))
129
130    rootfs=`mount | head -n1 | grep 'on / ' |cut -d ' ' -f1`
131    for pool in `/sbin/zpool list -H -o name`; do
132        echo "Poolname: $pool"
133        zpool_bootfs=`/sbin/zpool list -H -o bootfs ${pool}`
134
135        if [ "${zpool_bootfs}" = "-" ]; then
136            echo "No BE setup"
137            echo
138            continue
139        fi
140
141        mountpoint_length=`/sbin/zfs list -H -o mountpoint -r $pool/ROOT | tail +2 |wc -L`
142        if [ "$mountpoint_length" -lt "10" ]; then
143            mountpoint_length=10
144        fi
145        name_length=`/sbin/zfs list -H -o name -r $pool/ROOT | tail +2 | /usr/bin/sed s:^$pool/ROOT/:: |wc -L`
146        if [ "$name_length" -lt "4" ]; then
147            name_length=4
148        fi
149        space_length=`/sbin/zfs list -H -o referenced -r $pool/ROOT | tail +2 |wc -L`
150        if [ "$space_length" -lt "5" ]; then
151            space_length=5
152        fi
153        snapshot_length=`/sbin/zfs list -t snapshot -H -o name -r $pool/ROOT | /usr/bin/sed s:^$pool/ROOT/::  | wc -L`
154
155        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" BE Active Active Mountpoint Space
156        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" Name Now Reboot - Used
157        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" ---- ------ ------ ---------- -----
158
159        for be_filesystem in `/sbin/zfs list -H -S creation -o name -r $pool/ROOT |grep -v "^$pool/ROOT\$"`; do
160
161            if [ `/sbin/zfs list -H -o freebsd:boot-environment ${be_filesystem}` -eq 1 ]; then
162                be_name=`echo ${be_filesystem}|/usr/bin/sed s:^$pool/ROOT/::`
163
164                be_active='no' 
165                if [ "${be_filesystem}" = "${rootfs}" ]; then
166                    be_active='yes'     
167                fi
168                be_nextboot='no'
169                if [ "${be_filesystem}" = "${zpool_bootfs}" ]; then
170                    be_nextboot='yes'
171                fi
172
173                if [ "${be_active}" = "yes" -a "${be_nextboot}" = "yes" ]; then
174                  used_by_snapshots=`/sbin/zfs list -H -o usedbysnapshots $be_filesystem`
175                  be_space=`/sbin/zfs list -H -o referenced $be_filesystem`
176                  be_mountpoint='/'
177                elif [ "${be_active}" = "no" -a "${be_nextboot}" = "yes" ]; then
178                  used_by_snapshots=`/sbin/zfs list -H -o usedbysnapshots $be_filesystem`
179                  be_space=`/sbin/zfs list -H -o referenced $be_filesystem`
180                  be_mountpoint=`/sbin/zfs list -H -o mountpoint $be_filesystem`
181                elif [ "${be_active}" = "yes" -a "${be_nextboot}" = "no" ]; then
182                  be_origin=`/sbin/zfs list -H -o origin ${be_filesystem}`
183                  be_space=`/sbin/zfs list -H -t snapshot -o used $be_origin`
184                  be_mountpoint='/'
185                else
186                  be_origin=`/sbin/zfs list -H -o origin ${be_filesystem}`
187                  be_space=`/sbin/zfs list -H -t snapshot -o used $be_origin`
188                  be_mountpoint=`/sbin/zfs list -H -o mountpoint $be_filesystem`
189                fi
190                printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %${space_length}s\\n" $be_name $be_active $be_nextboot $be_mountpoint $be_space
191
192                if [ "$verbose" = "YES" ]; then
193                    be_created=`/sbin/zfs list -H -S creation -o creation $be_filesystem`
194                    echo
195                    printf "\t%-${snapshot_length}s %-21s\\n" Name Created
196                    printf "\t%-${snapshot_length}s %-21s\\n" $be_name "$be_created"
197                    for snapshot_name in `/sbin/zfs list -t snapshot -H -r -o name $pool/ROOT/$be_name|/usr/bin/sed s:^$pool/ROOT/::`; do
198                        snapshot_created=`/sbin/zfs list -t snapshot -H -S creation -o creation $pool/ROOT/$snapshot_name`
199                        printf "\t%-${snapshot_length}s %-21s\\n" $snapshot_name "$snapshot_created"
200                    done
201                    echo
202                fi
203            fi
204        done
205        echo
206        echo "Used by BE snapshots: ${used_by_snapshots}"
207        echo
208    done
209    ;;
210    src-upgrade)
211        # upgrade a boot-environment
212
213        shift; while getopts :n:p: arg; do case ${arg} in
214            n) bootfs=${OPTARG};;
215            p) pool=${OPTARG};;
216            ?) exerr ${usage_src_upgrade};;
217        esac; done; shift $(( ${OPTIND} - 1 ))
218
219        [ "${bootfs}" -a "${pool}" ] || exerr ${usage_src_upgrade}
220
221        check_for_be_existence
222
223        mount -t nullfs -o ro /usr/src /${pool}/ROOT/${bootfs}/usr/src
224        mount -t nullfs -o ro /usr/obj /${pool}/ROOT/${bootfs}/usr/obj
225
226        echo '#!/bin/sh
227mount -t devfs devfs /dev
228cd /usr/src
229make -s installkernel
230make -s installworld
231/usr/sbin/mergemaster -U
232umount /dev' > /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
233
234        chmod +x /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
235        chroot /${pool}/ROOT/${bootfs}/ /tmp/manageBE-upgrade.sh
236        rm /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
237        umount /${pool}/ROOT/${bootfs}/usr/obj
238        umount /${pool}/ROOT/${bootfs}/usr/src
239       
240        echo "Please activate ${bootfs} via manageBE and reboot."
241    ;;
242    freebsd-update)
243        [ `uname -r | cut -d '-' -f1,2` = "8.0-RELEASE" ] && exerr ${not_supported}
244        # update a boot-environment using freebsd-update
245
246        shift; while getopts :n:p: arg; do case ${arg} in
247            n) bootfs=${OPTARG};;
248            p) pool=${OPTARG};;
249            ?) exerr ${usage_freebsd_upgrade};;
250        esac; done; shift $(( ${OPTIND} - 1 ))
251
252        [ "${bootfs}" -a "${pool}" -a ${release} ] || exerr ${usage_freebsd_update}
253
254        check_for_be_existence
255       
256        chroot /${bootfs} mount -t devfs devfs /dev
257        chroot /${bootfs} /usr/sbin/freebsd-update fetch
258        chroot /${bootfs} /usr/sbin/freebsd-update install > /dev/null
259        chroot /${bootfs} umount /dev
260
261        echo "Please activate ${bootfs} via manageBE and reboot."
262    ;;
263    freebsd-upgrade)
264        [ `uname -r | cut -d '-' -f1,2` = "8.0-RELEASE" ] && exerr ${not_supported}
265        # upgrade a boot-environment using freebsd-update
266
267        shift; while getopts :n:p:r: arg; do case ${arg} in
268            n) bootfs=${OPTARG};;
269            p) pool=${OPTARG};;
270            r) release=${OPTARG};;
271            ?) exerr ${usage_freebsd_upgrade};;
272        esac; done; shift $(( ${OPTIND} - 1 ))
273
274        [ "${bootfs}" -a "${pool}" -a ${release} ] || exerr ${usage_freebsd_upgrade}
275
276        check_for_be_existence
277       
278        chroot /${bootfs} mount -t devfs devfs /dev
279        chroot /${bootfs} /usr/sbin/freebsd-update upgrade -r ${release}
280        chroot /${bootfs} /usr/sbin/freebsd-update install > /dev/null
281        chroot /${bootfs} umount /dev
282
283        echo "Please activate ${bootfs} via manageBE and reboot. After rebooting, freebsd-update needs to be run again to install the new userland components, and the system needs to be rebooted again"
284    ;;
285    *)
286        echo echo "Usage: ${mgm} [activate|create|delete|list|src-upgrade|freebsd-update|freebsd-upgrade] {params}"
287    ;;
288esac
Note: See TracBrowser for help on using the browser.