diff options
Diffstat (limited to 'usr/src/cmd/svc/milestone/fs-joyent')
-rwxr-xr-x | usr/src/cmd/svc/milestone/fs-joyent | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/usr/src/cmd/svc/milestone/fs-joyent b/usr/src/cmd/svc/milestone/fs-joyent new file mode 100755 index 0000000000..0a9dc065a3 --- /dev/null +++ b/usr/src/cmd/svc/milestone/fs-joyent @@ -0,0 +1,312 @@ +#!/bin/bash +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Joyent, Inc. +# + +set -o xtrace + +fatal() +{ + echo "Error: $1" + exit $SMF_EXIT_ERR_FATAL +} + +. /lib/svc/share/smf_include.sh +. /lib/svc/share/fs_include.sh +. /lib/sdc/usb-key.sh + +# first of all, if we aren't the global zone this doesn't make any sense to run + +smf_is_globalzone || exit $SMF_EXIT_OK + +# We need the links to /dev/dsk. Rather than trying to play games with manually +# invoking syseventd ask devfsadm to do some work. +/usr/sbin/devfsadm -c disk + +function destroy_zpools +{ + for pool in $(zpool list -p -o name | grep -v NAME) ; do + zpool destroy -f ${pool} + done +} + +function mount_zfs +{ + local dataset=$1 + local mountpoint=$2 + local output= + + # + # Try to mount the ZFS dataset. If the mountpoint is busy, wait five + # seconds and try again. Fail if the mount attempt returns EBUSY three + # consecutive times. + # + for i in {1..3}; do + output=$(mount -F zfs ${dataset} ${mountpoint} 2>&1) + if [[ $? -eq 0 ]]; then + break + fi + + if [ "${output}" == "mount failed: Device busy" ]; then + sleep 5 + else + echo ${output} 1>&2 + return + fi + done + + # The mount attempt must have failed + echo ${output} 1>&2 +} + +function unlock_pool +{ + local pool=$1 + + # If the key is already loaded, don't bother trying again + local keystatus="$(zfs get -Hpo value keystatus $pool)" + if [[ "$keystatus" == "available" ]]; then + return + fi + + kbmadm unlock $pool && return + + echo "Failed to unlock $pool; recovery may be required" | \ + tee -a /dev/console >&2 + + exit $SMF_EXIT_ERR_FATAL +} + +/bin/bootparams | grep "^noimport=true" >/dev/null +if [ $? -ne 0 ]; then + # If the zpool doesn't exist, then there's nothing to mount. + + # Assume the system zpool is zones, but if a different system pool + # identifies itself (by virtue of the .system_pool file being present in the + # pool's root dataset), then use that system pool instead. + SYS_ZPOOL=zones + + # Import specified zpools, or all zpools available + pools=$(/bin/bootparams | egrep "^zpools?=" | cut -d= -f2 | tr , ' ') + if [ -z ${pools} ]; then + pools=$(zpool import | grep "pool:" | awk '{print $2}') + fi + + for pool in $pools; do + zpool import -f $pool || continue + + is_encr="$(zfs get -Hpo value encryption $pool)" + + [[ "$is_encr" != "off" ]] && unlock_pool $pool + + # Due to early, failed attempts to support the filesystem_limits + # feature we now need to ensure the dependent feature is enabled. + zpool set feature@extensible_dataset=enabled $pool + if [[ -f /$pool/.system_pool ]]; then + SYS_ZPOOL=$pool + [[ "$is_encr" != "off" ]] && kbmadm set-syspool $pool + fi + done + + svccfg -s svc:/system/smartdc/init setprop \ + config/zpool=${SYS_ZPOOL} + svccfg -s svc:/system/smartdc/init:default refresh + + # If the destroy_zpools boot parameter is set, destroy all zpools + /bin/bootparams | grep "^destroy_zpools=true" >/dev/null + if [ $? -eq 0 ]; then + destroy_zpools + fi + + # A machine is reset to its original unsetup state (i.e. a 'factory reset') + # when the smartdc:factoryreset ZFS user property is set on the var dataset. + reset=$(zfs get -H -o value smartdc:factoryreset ${SYS_ZPOOL}/var) + if [ "${reset}" == "yes" ]; then + destroy_zpools + fi + + # Capture the zpool's status output in the method's log file for + # troubleshooting. + # + # Note: It is critical that we do not run 'status -v'. If there are errors + # in the zpool error log and the zpool is large (e.g. > 200TB), then the + # lookup for the error file names can take a very long time (several hours). + # This would block the system boot until it completed. + zpool status ${SYS_ZPOOL} + if [ $? -eq 0 ]; then + + # Stash the SUNWdefault.xml file so we can update the + # persistent version after mounting zones/config. + cp /etc/zones/SUNWdefault.xml /tmp/ + + # Mount and configure all system datasets + mount_zfs ${SYS_ZPOOL}/var /var + mount_zfs ${SYS_ZPOOL}/config /etc/zones + mount_zfs ${SYS_ZPOOL}/opt /opt + + # Update the the persistent SUNWdefault.xml file to match the + # contents on ramdisk now that zones/config is mounted. + cp /tmp/SUNWdefault.xml /etc/zones/ + rm -f /tmp/SUNWdefault.xml + + # + # We include a manifest of all files shipped in the platform image, + # along with an MD5 hash of their contents. This was originally + # shipped as "/var/log/manifest", but once a machine is set up, "/var" + # now comes from the pool. The upshot of this is that every SmartOS + # machine has the manifest from the platform at setup time stored in + # "/var/log/manifest". Now that the manifest has moved to an + # accessible location, we should remove this file and replace it with a + # symbolic link. + # + if [[ -f '/var/log/manifest' && ! -L '/var/log/manifest' && + ! -e '/var/log/manifest.original' ]]; then + mv '/var/log/manifest' '/var/log/manifest.original' + ln -s '../../usr/share/smartos/manifest' '/var/log/manifest' + fi + + if [[ -z $(/bin/bootparams | grep '^smartos=true') ]]; then + mkdir -p /opt/smartdc/agents/smf + mount -O -F lofs /var/svc/manifest/site /opt/smartdc/agents/smf + fi + + if [[ -n $(/bin/bootparams | grep '^headnode=true') || \ + -n $(/bin/bootparams | grep '^smartos=true') ]]; then + mkdir /usbkey + mount_zfs ${SYS_ZPOOL}/usbkey /usbkey + fi + + if [[ -n $(/bin/bootparams | grep '^smartos=true') ]]; then + mount -F lofs /usbkey/shadow /etc/shadow + mount -F lofs /usbkey/ssh /etc/ssh + fi + + swap -a /dev/zvol/dsk/${SYS_ZPOOL}/swap || \ + fatal "failed to configure swap device" + + # + # Configure the dump device on top of a ZFS volume. In addition to the + # usual dumpadm(1m) call, there are two prerequisites for using this + # volume as a dump device: (1) that zvol must be using the noparity + # checksum algorithem, and (2) the MULTI_VDEV_CRASH_DUMP ZFS feature + # must be enabled. Prerequisite (1) is necessary since the exact + # on-disk value for ZIO_CHECKSUM_NOPARITY has changed, so to avoid a + # flag day on all systems, this service just sets that property again + # every time. + # + zfs set checksum=noparity ${SYS_ZPOOL}/dump || \ + fatal "failed to set checksum=noparity on dump zvol" + zpool set feature@multi_vdev_crash_dump=enabled ${SYS_ZPOOL} || \ + fatal "failed to enable multi_vdev_crash_dump ZFS feature" + dumpadm -y -d /dev/zvol/dsk/${SYS_ZPOOL}/dump || \ + fatal "failed to configure dump device" + + zfs list -H -o name ${SYS_ZPOOL}/cores/global >/dev/null 2>&1 + if [ $? -ne 0 ]; then + # Booting for the first time on a CN whose cores dataset is setup + # in the 6.x style. Convert to the new style. + zfs destroy -r ${SYS_ZPOOL}/cores + zfs create -o compression=gzip -o mountpoint=none ${SYS_ZPOOL}/cores + zfs create -o quota=10g -o mountpoint=/${SYS_ZPOOL}/global/cores \ + ${SYS_ZPOOL}/cores/global + fi + + ln -s /${SYS_ZPOOL}/global/cores /cores + + [[ -f /${SYS_ZPOOL}/currbooted ]] && \ + mv /${SYS_ZPOOL}/currbooted /${SYS_ZPOOL}/lastbooted + uname -v >/${SYS_ZPOOL}/currbooted + fi +fi + + +# The rest only applies to the headnode +/bin/bootparams | grep "^headnode=true" >/dev/null || exit $SMF_EXIT_OK + +# If we rebooted during an upgrade, we're in deep trouble. +if [ -d /var/upgrade_in_progress ]; then + echo "ERROR: An upgrade was in progress when the system rebooted." \ + >/dev/console + echo " The system is in an indeterminate state, unable to continue." \ + >/dev/console + exit $SMF_EXIT_ERR_FATAL +fi + +COPYINPOINT=`svcprop -p "joyentfs/usb_copy_path" ${SMF_FMRI}` +DEBUG=`svcprop -p "joyentfs/debug" ${SMF_FMRI}` + +if [[ -d /mnt ]]; then + chown root:root /mnt + chmod 700 /mnt +else + mkdir -m 700 /mnt +fi + +function make_usb_copy_if_possible +{ + [[ -n "${SYS_ZPOOL}" ]] || fatal "don't know system zpool name" + + zpool list -Ho name | grep "^${SYS_ZPOOL}\$" + if [[ $? != 0 ]]; then + echo "skipping USB copy setup: no ${SYS_ZPOOL} zpool" >/dev/console + # Still return OK, because this is the expected case for first headnode + # boot. + return 0 + fi + + USBDATASET=${SYS_ZPOOL}/usbkey + if ! zfs list -Ho name | grep "^${USBDATASET}\$" >/dev/null; then + echo "skipping USB copy setup: no zones/usbkey dataset" >/dev/console + # Still return OK, because as of HEAD-2343 a CN being converted to a HN + # will not yet have this dataset on its first boot as an HN. + return 0 + fi + + echo "" > /dev/console + echo "Moving files from USB boot device onto disk storage." > /dev/console + echo "This may take several minutes. Please note the time..." > /dev/console + echo "" > /dev/console + echo "" > /dev/console + + mkdir ${COPYINPOINT} + mount_zfs ${USBDATASET} ${COPYINPOINT} + + (cd ${USBMOUNTPOINT}; rsync -av --log-file=/dev/console --exclude private --exclude os * ${COPYINPOINT}) + if [[ -d ${USBMOUNTPOINT}/os ]]; then + (cd ${USBMOUNTPOINT}/os ; \ + for dir in $(ls -d *); do + # source comes from pcfs which we've got lowering the case + # of everything, but we normally use capital T and Z for + # buildstamp, so fix it here. + source_dir=${dir} + target_dir=$(echo ${dir} | tr "[:lower:]" "[:upper:]") + mkdir -p ${COPYINPOINT}/os + echo "Copying: ${source_dir}/ ${COPYINPOINT}/os/${target_dir}" > /dev/console + rsync -a ${source_dir}/ ${COPYINPOINT}/os/${target_dir} + done + ) + fi + + echo "" > /dev/console + echo "Done copying files from USB device" > /dev/console + return 0 +} + +USBMOUNTPOINT=$(mount_usb_key "") +if [[ $? -ne 0 ]]; then + fatal "couldn't mount USB key" +fi + +make_usb_copy_if_possible +exit $? |