#1204 zoneadm cannot create clone of zone from snapshot (IPS) oi_151a oi_151a_prestable9
authorJon Tibble <meths@btinternet.com>
Thu, 21 Nov 2013 11:47:19 +0000
branchoi_151a
changeset 2591 98ff1ea26243
parent 2590 1b157a5cc2c4
child 2592 7b887790aee8
#1204 zoneadm cannot create clone of zone from snapshot (IPS)
src/brand/clone
--- a/src/brand/clone	Fri Jul 19 16:18:09 2013 +0100
+++ b/src/brand/clone	Thu Nov 21 11:47:19 2013 +0000
@@ -23,11 +23,14 @@
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright (C) 2013 by Jim Klimov - implemented the previously absent
+#    cloning of zones from specified snapshot, and avoidance of sys-unconfig
 
 . /usr/lib/brand/ipkg/common.ksh
 
 m_usage=$(gettext "clone {sourcezone}")
 f_nosource=$(gettext "Error: unable to determine source zone dataset.")
+f_badsource=$(gettext "Error: specified snapshot is invalid for this source zone.")
 
 # Clean up on failure
 trap_exit()
@@ -45,9 +48,29 @@
 ROOT="rpool/ROOT"
 
 # Other brand clone options are invalid for this brand.
-while getopts "R:z:" opt; do
+while getopts "R:s:Xz:" opt; do
 	case $opt in
 		R)	ZONEPATH="$OPTARG" ;;
+		s)	case "$OPTARG" in
+			*@*) # Full snapshot name was provided, or just "@snap"
+			     # Split this into dataset name (even if empty) and
+			     # snapshot name (also may be empty)
+				SNAPNAME="`echo "$OPTARG" | sed 's/^[^@]*@//'`"
+				REQUESTED_DS="`echo "$OPTARG" | sed 's/\([^@]*\)@.*$/\1/'`"
+				;;
+			*/*) # Only dataset name was passed, so we will make a
+			     # snapshot there automatically and clone off it
+				SNAPNAME=""
+				REQUESTED_DS="$OPTARG"
+				;;
+			*)   # Only snapshot name was passed, so we will clone
+			     # the source zone's active ZBE and this snapshot
+				SNAPNAME="$OPTARG"
+				REQUESTED_DS=""
+				;;
+			esac
+			;;
+		X)	NO_SYSUNCONFIG=yes ;;
 		z)	ZONENAME="$OPTARG" ;;
 		*)	fail_usage "";;
 	esac
@@ -57,18 +80,37 @@
 if [ $# -ne 1 ]; then
 	fail_usage "";
 fi
+sourcezone="$1"
 
-sourcezone=$1
+get_current_gzbe
+
+if [ -z "$REQUESTED_DS" ]; then
+	# Find the active source zone dataset to clone.
+	sourcezonepath=`/usr/sbin/zoneadm -z $sourcezone list -p | awk -F: '{print $4}'`
+	if [ -z "$sourcezonepath" ]; then
+		fail_fatal "$f_nosource"
+	fi
 
-# Find the active source zone dataset to clone.
-sourcezonepath=`/usr/sbin/zoneadm -z $sourcezone list -p | awk -F: '{print $4}'`
-if [ -z "$sourcezonepath" ]; then
-	fail_fatal "$f_nosource"
+	get_zonepath_ds $sourcezonepath
+	get_active_ds $CURRENT_GZBE $ZONEPATH_DS
+else
+	# Sanity-check the provided dataset (should exist and be an IPS ZBE)
+	REQUESTED_DS="`echo "$REQUESTED_DS" | egrep '^.*/'"$sourcezone"'/ROOT/[^/]+$'`"
+	if [ $? != 0 -o x"$REQUESTED_DS" = x ]; then
+		fail_fatal "$f_badsource"
+	fi
+	zfs list -H -o \
+		org.opensolaris.libbe:parentbe,org.opensolaris.libbe:active \
+		"$REQUESTED_DS" > /dev/null || \
+			fail_fatal "$f_badsource"
+	ACTIVE_DS="$REQUESTED_DS"
 fi
 
-get_current_gzbe
-get_zonepath_ds $sourcezonepath
-get_active_ds $CURRENT_GZBE $ZONEPATH_DS
+# Another sanity-check: requested snapshot exists for default or requested ZBE
+if [ x"$SNAPNAME" != x ]; then
+	zfs list -H "$ACTIVE_DS@$SNAPNAME" > /dev/null || \
+		fail_fatal "$f_badsource"
+fi
 
 #
 # Now set up the zone's datasets
@@ -95,20 +137,25 @@
 
 /usr/sbin/zfs create -o mountpoint=legacy -o zoned=on $zpds/$zpname/ROOT
 
-# make snapshot
-SNAPNAME=${ZONENAME}_snap
-SNAPNUM=0
-while [ $SNAPNUM -lt 100 ]; do
-	/usr/sbin/zfs snapshot $ACTIVE_DS@$SNAPNAME
-        if [ $? = 0 ]; then
-                break
+if [ x"$SNAPNAME" = x ]; then
+	# make snapshot
+	SNAPNAME=${ZONENAME}_snap
+	SNAPNUM=0
+	while [ $SNAPNUM -lt 100 ]; do
+		/usr/sbin/zfs snapshot $ACTIVE_DS@$SNAPNAME
+		if [ $? = 0 ]; then
+    			break
+		fi
+		SNAPNUM=`expr $SNAPNUM + 1`
+		SNAPNAME="${ZONENAME}_snap$SNAPNUM"
+	done
+
+	# NOTE: This artificially limits us to 100 clones of a "golden" zone
+	# into a same-named (test?) zone, unless clones are based on some
+	# same snapshot via command-line
+	if [ $SNAPNUM -ge 100 ]; then
+		fail_fatal "$f_zfs_create"
 	fi
-	SNAPNUM=`expr $SNAPNUM + 1`
-	SNAPNAME="${ZONENAME}_snap$SNAPNUM"
-done
-
-if [ $SNAPNUM -ge 100 ]; then
-	fail_fatal "$f_zfs_create"
 fi
 
 # do clone
@@ -149,7 +196,13 @@
 # ipkg brand zones.  The root won't be mounted for labeled brand zones.
 #
 is_brand_labeled
-(( $? == 0 )) && unconfigure_zone
+(( $? == 0 )) && if [ x"$NO_SYSUNCONFIG" = xyes ]; then
+	vlog "$v_mounting"
+	ZONE_IS_MOUNTED=1
+	zoneadm -z $ZONENAME mount -f || fatal "$e_badmount"
+else
+	unconfigure_zone
+fi
 
 trap - EXIT
 exit $ZONE_SUBPROC_OK