PSARC/2011/212 Zones Support for Automated Install
authorSusan Kamm-Worrell <Susan.Kamm-Worrell@Sun.COM>
Wed, 01 Jun 2011 22:33:36 -0700
changeset 2391 e326a9d20501
parent 2390 49043c6c5187
child 2392 80961b842cc8
PSARC/2011/212 Zones Support for Automated Install 18013 Update pkgcreatezone to call the Automated Installer 18145 pkgcreatezone should not copy the lib/svc/seed/nonglobal.db with the integration of EMI
src/brand/attach
src/brand/clone
src/brand/common.ksh
src/brand/image_install
src/brand/p2v
src/brand/pkgcreatezone
--- a/src/brand/attach	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/attach	Wed Jun 01 22:33:36 2011 -0700
@@ -31,7 +31,7 @@
 
 m_attach_log=$(gettext "Log File: %s")
 m_zfs=$(gettext "A ZFS file system was created for the zone.")
-m_usage=$(gettext  "attach [-a archive] [-d dataset] [-r zfs-recv] [-v] [-u]\n\tThe -a archive option specifies a tar file or cpio archive.\n\tThe -d dataset option specifies an existing dataset.\n\tThe -r zfs-recv option receives the output of a 'zfs send' command\n\tof an existing zone root dataset.\n\tThe -u option indicates that the software should be updated to match\n\tthe current host.\n\tThe -v option enables verbose output.")
+m_usage=$(gettext  "attach [-a archive] [-d dataset] [-n] [-r zfs-recv] [-u] [-v] [-c profile | dir]\n\tThe -a archive option specifies a tar file or cpio archive.\n\tThe -d dataset option specifies an existing dataset.\n\tThe -r zfs-recv option receives the output of a 'zfs send' command\n\tof an existing zone root dataset.\n\tThe -u option indicates that the software should be updated to match\n\tthe current host.\n\tThe -v option enables verbose output.\n\tThe -c option gives a profile or a directory of profiles to be applied to the system after attach.")
 m_attach_root=$(gettext "               Attach Path: %s")
 m_attach_ds=$(gettext   "        Attach ZFS Dataset: %s")
 m_gzinc=$(gettext       "       Global zone version: %s")
@@ -153,6 +153,7 @@
 noexecute=0
 
 unset inst_type
+unset sc_config
 
 # Get publisher information for global zone.  These structures are used
 # to store information about the global zone publishers and
@@ -163,7 +164,7 @@
 #
 verbose=""
 # Other brand attach options are invalid for this brand.
-while getopts "a:d:n:r:uv" opt; do
+while getopts "a:c:d:n:r:uv" opt; do
 	case $opt in
 		a)
 			if [[ -n "$inst_type" ]]; then
@@ -172,6 +173,7 @@
 		 	inst_type="archive"
 			install_media="$OPTARG"
 			;;
+		c)	sc_config="$OPTARG" ;;
 		d)
 			if [[ -n "$inst_type" ]]; then
 				fatal "$incompat_options" "$m_usage"
@@ -312,6 +314,8 @@
 LC_ALL=C $PKG install $verbose pkg:///package/pkg/zones-proxy || \
     pkg_err_check "$f_sysrepo"
 
+[[ -n $sc_config ]] && reconfigure_zone $sc_config
+
 log "\n$m_sync_done"
 log "$m_complete"
 
--- a/src/brand/clone	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/clone	Wed Jun 01 22:33:36 2011 -0700
@@ -24,7 +24,7 @@
 
 . /usr/lib/brand/ipkg/common.ksh
 
-m_usage=$(gettext "clone {sourcezone}")
+m_usage=$(gettext "clone {sourcezone} [-c profile | dir]\n\tThe -c option gives a profile or a directory of profiles to be applied to the system after clone.")
 f_nosource=$(gettext "Error: unable to determine source zone dataset.")
 
 # Clean up on failure
@@ -39,8 +39,9 @@
 }
 
 # Source and destination zones
+unset sc_config
 typeset src dst	
-# Other brand clone options are invalid for this brand.
+# Brand clone options are handled below
 while getopts "R:z:" opt; do
 	case $opt in
 		R)	opt_R="$OPTARG" ;;
@@ -50,12 +51,22 @@
 done
 shift $((OPTIND-1))
 
-if (($# != 1)); then
-	fail_usage "";
+if (($# < 1)); then
+	fail_usage ""
 fi
 
 init_zone dst "$opt_z" "$opt_R"
 init_zone src "$1"
+shift
+
+let OPTIND=1
+# Other brand clone options are invalid for this brand.
+while getopts "c:" opt; do
+	case $opt in
+		c)	sc_config="$OPTARG" ;;
+		*)	fail_usage "";;
+	esac
+done
 
 get_current_gzbe
 get_active_be src || fatal "$e_no_active_be"
@@ -74,11 +85,11 @@
 trap trap_exit EXIT
 
 #
-# Completion of unconfigure_zone will leave the zone root mounted for
+# Completion of reconfigure_zone will leave the zone root mounted for
 # ipkg brand zones.  The root won't be mounted for labeled brand zones.
 #
 is_brand_labeled
-(( $? == 0 )) && unconfigure_zone
+(( $? == 0 )) && reconfigure_zone $sc_config
 
 trap - EXIT
 exit $ZONE_SUBPROC_OK
--- a/src/brand/common.ksh	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/common.ksh	Wed Jun 01 22:33:36 2011 -0700
@@ -63,8 +63,8 @@
 
 m_brnd_usage=$(gettext "brand-specific usage: ")
 
-v_unconfig=$(gettext "Performing zone sys-unconfig")
-e_unconfig=$(gettext "sys-unconfig failed")
+v_reconfig=$(gettext "Performing zone system configuration")
+e_reconfig=$(gettext "System configuration failed")
 v_mounting=$(gettext "Mounting the zone")
 e_badmount=$(gettext "Zone mount failed")
 v_unmount=$(gettext "Unmounting zone")
@@ -237,10 +237,11 @@
 }
 
 #
-# Run sys-unconfig on the zone.
+# Run system configuration inside a zone.
 #
-unconfigure_zone() {
-	vlog "$v_unconfig"
+reconfigure_zone() {
+	typeset sc_config=$1
+	vlog "$v_reconfig"
 
 	vlog "$v_mounting"
 	ZONE_IS_MOUNTED=1
@@ -250,17 +251,32 @@
 	SC_ONLINE=$(svcprop -p restarter/state \
 	    svc:/milestone/unconfig:default 2> /dev/null)
 	if (( $? == 0 )) && [[ $SC_ONLINE == "online" ]]; then
-		zlogin -S $ZONENAME "export _UNCONFIG_ALT_ROOT=/a; \
-		    /usr/sbin/sysconfig unconfigure -g system; \
-		    export _UNCONFIG_ALT_ROOT= ;" \
-		    </dev/null >/dev/null 2>&1
+		if [[ -n $sc_config ]]; then
+			safe_copy $sc_config \
+			    $ZONEPATH/lu/system/volatile/$sc_config
+			zlogin -S $ZONENAME "export _UNCONFIG_ALT_ROOT=/a; \
+			    /usr/sbin/sysconfig configure -g system \
+			    -c /system/volatile/$sc_config;
+			    export _UNCONFIG_ALT_ROOT= ;" \
+			    </dev/null >/dev/null 2>&1
+		else
+			zlogin -S $ZONENAME "export _UNCONFIG_ALT_ROOT=/a; \
+			    /usr/sbin/sysconfig unconfigure -g system; \
+			    export _UNCONFIG_ALT_ROOT= ;" \
+			    </dev/null >/dev/null 2>&1
+		fi
+		ret=$?
 	else
 		zlogin -S $ZONENAME /usr/sbin/sys-unconfig -R /a \
 		    </dev/null >/dev/null 2>&1
+		ret=$?
+		if [[ -n $sc_config ]]; then
+			safe_copy $sc_config $ZONEPATH/lu/a/etc/sysidcfg
+		fi
 	fi
 
-	if (( $? != 0 )); then
-		error "$e_unconfig"
+	if (( $ret != 0 )); then
+		error "$e_reconfig"
 		failed=1
 	fi
 
--- a/src/brand/image_install	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/image_install	Wed Jun 01 22:33:36 2011 -0700
@@ -37,8 +37,9 @@
 
 # Allows developer to override some things like PATH and PYTHONPATH
 . /usr/lib/brand/ipkg/developerenv.ksh
+m_usage=$(gettext "\n        install {-a archive|-d path} {-p|-u} [-s|-v] \
+	[-c profile | dir]")
 
-m_usage=$(gettext "\n        install {-a archive|-d path} {-p|-u} [-s|-v]")
 install_log=$(gettext   "    Log File: %s")
 
 p2ving=$(gettext        "Postprocessing: This may take a while...")
@@ -109,6 +110,7 @@
 unset msg
 unset silent_mode
 unset verbose_mode
+unset OPT_C
 
 #
 # It is worth noting here that we require the end user to pick one of
@@ -120,7 +122,7 @@
 unset unconfig_zone
 unset preserve_zone
 
-while getopts "a:d:psuv" opt
+while getopts "a:c:d:psuv" opt
 do
 	case "$opt" in
 		a)
@@ -130,6 +132,7 @@
 		 	inst_type="archive"
 			install_media="$OPTARG"
 			;;
+		c)	OPT_C="-c $OPTARG";;
 		d)
 			if [[ -n "$inst_type" ]]; then
 				fatal "$both_kinds" "zoneadm install"
@@ -194,9 +197,9 @@
 # to find the log file and then reopen the log (O_APPEND) when p2v is done.
 #
 log "$p2ving"
-vlog "running: p2v $verbose_mode $unconfig_zone $ZONENAME $ZONEPATH"
+vlog "running: p2v $verbose_mode $unconfig_zone $ZONENAME $ZONEPATH $OPT_C"
 /usr/lib/brand/ipkg/p2v -l "$LOGFILE" $verbose_mode $unconfig_zone $ZONENAME \
-    $ZONEPATH
+    $ZONEPATH $OPT_C
 p2v_result=$?
 exec 2>>$LOGFILE
 
--- a/src/brand/p2v	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/p2v	Wed Jun 01 22:33:36 2011 -0700
@@ -341,9 +341,11 @@
 OPT_U=
 OPT_V=
 OPT_L=
-while getopts "b:uvl:" opt
+sc_config=
+while getopts "b:c:uvl:" opt
 do
 	case "$opt" in
+		c)	sc_config="$OPTARG";;
 		u)	OPT_U="-u";;
 		v)	OPT_V="-v";;
 		l)	LOGFILE="$OPTARG"; OPT_L="-l \"$OPTARG\"";;
@@ -502,7 +504,7 @@
 zoneadm -z $ZONENAME mark incomplete || fatal "$e_badupdate"
 log "$v_updatedone"
 
-[[ -n $OPT_U ]] && unconfigure_zone
+[[ -n $OPT_U ]] && reconfigure_zone $sc_config
 
 (( $brand_labeled == 1 )) && mount_active_be zone
 
--- a/src/brand/pkgcreatezone	Thu Jun 02 12:13:18 2011 +1200
+++ b/src/brand/pkgcreatezone	Wed Jun 01 22:33:36 2011 -0700
@@ -24,35 +24,24 @@
 # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 
-#
-# Resetting GZ_IMAGE to something besides slash allows for simplified
-# debugging of various global zone image configurations-- simply make
-# an image somewhere with the appropriate interesting parameters.
-#
-GZ_IMAGE=${GZ_IMAGE:-/}
-PKG_IMAGE=$GZ_IMAGE
-export PKG_IMAGE
-
 . /usr/lib/brand/ipkg/common.ksh
 
 # Allows developers to override some things like PATH and PYTHONPATH
 . /usr/lib/brand/ipkg/developerenv.ksh
 
 f_a_obs=$(gettext "-a publisher=uri option is obsolete.")
-f_pkg5_missing=$(gettext "pkg(5) does not seem to be present on this system.\n")
-f_img=$(gettext "failed to create image\n")
-f_imglink=$(gettext "failed to link image to global zone\n")
-f_pkg=$(gettext "failed to install package\n")
 f_interrupted=$(gettext "Installation cancelled due to interrupt.\n")
-f_bad_publisher=$(gettext "Syntax error in publisher information.")
+f_mktemp=$(gettext "Unable to make temporary filename.")
+f_aimanifest_load=$(gettext "Unable to aimanifest load.")
+f_aimanifest_add=$(gettext "Unable to aimanifest add.")
+f_autoinstall=$(gettext "auto-install failed.")
 
 m_image=$(gettext       "       Image: Preparing at %s.")
-m_core=$(gettext	"  Installing: Packages (output follows)\n")
-m_smf=$(gettext		" Postinstall: Copying SMF seed repository ...")
+m_link=$(gettext		" Postinstall: Making symlinks ...")
 m_more_brokenness=$(gettext " Postinstall: Applying workarounds.")
 m_mannote=$(gettext     "        Note: Man pages can be obtained by installing pkg:/system/manual")
 
-m_usage=$(gettext "\n        install [-h]\n        install\n                [-e extrapkg [...]]\n        install {-a archive|-d path} {-p|-u} [-s|-v]")
+m_usage=$(gettext "\n        install [-h]\n        install [-m manifest] [-c profile | dir]\n        install {-a archive|-d path} {-p|-u} [-s|-v] [-c profile | dir]")
 
 m_done=$(gettext      " done.")
 
@@ -64,7 +53,8 @@
 EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE
 trap trap_cleanup INT
 
-extra_packages=""
+manifest=""
+profile_dir=""
 ZONENAME=""
 ZONEPATH=""
 
@@ -76,11 +66,13 @@
 
 unset install_archive
 unset source_dir
-unset msg
 unset silent_mode
 unset verbose_mode
+unset sc_config
+unset OPT_C
+unset temp_manifest
 
-while getopts "a:d:e:hpR:suvz:" opt; do
+while getopts "a:c:d:hm:pR:suvz:" opt; do
 	case $opt in
 		a)	# We're expecting a path to an archive
 			if [[ ! -f $OPTARG ]]; then
@@ -91,9 +83,11 @@
 				fi
 			fi
 			install_archive="-a $OPTARG";;
+		c)	sc_config="$OPTARG"
+			OPT_C="-c $OPTARG" ;;
 		d)	source_dir="-d $OPTARG";;
-		e)	extra_packages="$extra_packages $OPTARG" ;;
 		h)	fail_usage "";;
+		m)	manifest="$OPTARG" ;;
 		p)	preserve_zone="-p";;
 		R)	ZONEPATH="$OPTARG" ;;
 		s)	silent_mode=1;;
@@ -128,10 +122,10 @@
 [[ -n $unconfig_zone && -n $preserve_zone ]] && \
     fail_usage "$f_incompat_options" "-u" "-p"
 
-# IPS options aren't allowed when installing from a system image.
+# AI zone manifest option isn`t allowed when installing from a system image.
 if [[ -n "$install_archive" || -n "$source_dir" ]]; then
-	[[ -n "$extra_packages" ]] && \
-	    fail_usage "$f_incompat_options" "-a|-d" "-e"
+	[[ -n "$manifest" ]] && fail_usage \
+	    "$f_incompat_options" "-a|-d" "-m"
 fi
 
 # p2v options aren't allowed when installing from a repo.
@@ -150,19 +144,15 @@
 entire_fmri=$(get_entire_incorp)
 
 #
-# Before installing the zone, set up ZFS dataset hierarchy for the zone root
-# dataset.
-#
-create_active_ds zone || fail_fatal "$f_no_ds"
-mount_active_be -c zone || fail_fatal "$f_no_ds"
-
-#
 # If we're installing from an image, branch off to that installer.
+# Set up ZFS dataset hierarchy for the zone root dataset.
 #
 if [[ -n $install_archive || -n $source_dir ]]; then
+	create_active_ds zone || fail_fatal "$f_no_ds"
+	mount_active_be -c zone || fail_fatal "$f_no_ds"
 	/usr/lib/brand/ipkg/image_install $ZONENAME $ZONEPATH \
 	    $install_archive $source_dir $verbose_mode $silent_mode \
-	    $unconfig_zone $preserve_zone
+	    $unconfig_zone $preserve_zone $OPT_C
 	ii_result=$?
 
 	if (( $ii_result != 0 )); then
@@ -178,100 +168,104 @@
 	exit $ZONE_SUBPROC_NOTCOMPLETE
 fi
 
-#
-# The image is created.
-#
-LC_ALL=C $PKG image-create --zone --full \
-    --set-property use-system-repo=true \
-    $ZONEROOT || fail_incomplete "$f_img"
-
-# Link this image to the parent image.
-printf "$m_image_link\n" $GZ_IMAGE
-LC_ALL=C $PKG attach-linked -q -f --no-refresh --no-index --linked-md-only \
-    -c zone:$ZONENAME $ZONEROOT || fail_incomplete "$f_imglink"
-
-# Change the value of PKG_IMAGE so that future PKG operation will work
-# on the newly created zone rather than the global zone
-PKG_IMAGE="$ZONEROOT"
-export PKG_IMAGE
-
-if [[ -f /var/pkg/pkg5.image && -d /var/pkg/publisher ]]; then
-	# respect PKG_CACHEROOT if the caller has it set.
-	[ -z "$PKG_CACHEROOT" ] && PKG_CACHEROOT=/var/pkg/publisher
-	export PKG_CACHEROOT
-	printf "$m_cache\n" $PKG_CACHEROOT
-fi
-
-printf "$m_core\n"
-pkglist=""
-
-#
-# 'entire' is essentially optional-- if you don't have it in your global
-# zone, you are probably an OS developer, and therefore you probably don't
-# want it in your non-global zone.  We follow the preference we find in
-# the global zone.
-if [[ -n $entire_fmri ]]; then
-	pkglist="$pkglist pkg:///entire"
+# Use default AI zone manifest if none is given
+if [[ ! -n $manifest ]]; then
+	manifest=/usr/share/auto_install/manifest/zone_default.xml
 fi
 
 #
-# If this is a labeled brand, install the trusted desktop package.
-# Otherwise, install the small server package
+# Add packages to AI zone manifest for TX zones if appropriate.
+# Add entire package if installed in GZ
+# The environment variable AIM_MANIFEST contains the file where all the
+# aimanifest changes will be made.  The load operation loads that manifest
+# into the working file.  The add operation adds the entries to the
+# working file.
 #
-if (( $brand_labeled == 1 )); then
-    pkglist="$pkglist pkg:///group/feature/trusted-desktop"
-else
-    pkglist="$pkglist pkg:///group/system/solaris-small-server"
+if (( $brand_labeled == 1 )) || [[ -n $entire_fmri ]]; then
+	temp_manifest=`mktemp -t manifest.xml.XXXXXX`
+	if [[ -z $temp_manifest ]]; then
+		print "$f_mktemp"
+		exit $ZONE_SUBPROC_NOTCOMPLETE
+	fi
+	export AIM_MANIFEST=$temp_manifest
+	aimanifest load $manifest
+	if [[ $? -ne 0 ]]; then
+		print "$f_aimanifest_load"
+		exit $ZONE_SUBPROC_NOTCOMPLETE
+	fi
+	if (( $brand_labeled == 1 )); then
+		aimanifest add \
+		    /auto_install/ai_instance/software/software_data[@action="install"]/name \
+		    pkg:/group/feature/trusted-desktop
+		if [[ $? -ne 0 ]]; then
+			print "$f_aimanifest_add"
+			exit $ZONE_SUBPROC_NOTCOMPLETE
+		fi
+	fi
+	if [[ -n $entire_fmri ]]; then
+		aimanifest add \
+		    /auto_install/ai_instance/software/software_data[@action="install"]/name \
+		    pkg:///entire
+		if [[ $? -ne 0 ]]; then
+			print "$f_aimanifest_add"
+			exit $ZONE_SUBPROC_NOTCOMPLETE
+		fi
+	fi
+	manifest=$temp_manifest
 fi
 
 #
-# Add in any extra packages requested by the user.
+# Before installing the zone, set up ZFS dataset for the zone root dataset,
+# but don't create rpool/ROOT or rpool/export hierarchies since installer
+# will create them.
 #
-pkglist="$pkglist $extra_packages"
+create_active_ds -r zone || fail_fatal "$f_no_ds"
 
 #
-# Do the install; we just refreshed after image-create, so skip that.  We
-# also skip indexing here, as that is also what the LiveCD does.
+# If unconfig service is online, then call auto-install with the default
+# profile or with the caller supplied profile.
+# If unconfig service is offline or doesn't exist, then don't pass
+# any profile to auto-install since this will cause SCI tool to start in
+# zone on boot.  Previous sysconfig method handled below after install.
 #
-LC_ALL=C $PKG install --accept --no-index --no-refresh $pkglist || \
-    pkg_err_check "$f_pkg"
+SC_ONLINE=$(svcprop -p restarter/state \
+    svc:/milestone/unconfig:default 2> /dev/null)
+if (( $? == 0 )) && [[ $SC_ONLINE == "online" ]]; then
+	if [[ -n $sc_config ]]; then
+		/usr/bin/auto-install -Z ${zone.rpool_ds} -m $manifest $OPT_C
+	else
+		/usr/bin/auto-install -Z ${zone.rpool_ds} -m $manifest \
+		    -c /usr/share/auto_install/sc_profiles/enable_sci.xml
+	fi
+else
+	/usr/bin/auto-install -Z ${zone.rpool_ds} -m $manifest
+fi
+if [[ $? -ne 0 ]]; then
+	fail_fatal "$f_autoinstall"
+fi
+
+if [[ -n $temp_manifest ]]; then
+	rm $temp_manifest
+fi
 
 printf "\n$m_mannote\n"
 
-printf "$m_smf"
-PROFILEDIR=etc/svc/profile
-ln -s ns_files.xml $ZONEROOT/$PROFILEDIR/name_service.xml
-ln -s generic_limited_net.xml $ZONEROOT/$PROFILEDIR/generic.xml
-ln -s inetd_generic.xml $ZONEROOT/$PROFILEDIR/inetd_services.xml
-ln -s platform_none.xml $ZONEROOT/$PROFILEDIR/platform.xml
-
-# This was formerly done in i.manifest
-repfile=$ZONEROOT/etc/svc/repository.db
-cp $ZONEROOT/lib/svc/seed/nonglobal.db $repfile
-chmod 0600 $repfile
-chown root:sys $repfile
-
 printf "$m_done\n"
 
 #
-# If unconfig service exists and is online then copy in enable_sci.xml
-# sysconfig file to trigger config cycle on boot of zone.
+# If unconfig service is offline or doesn't exist, then use
+# previous sysconfig method since that is still being used by the
+# zone.  Copy sysidcfg file if given, but only copy if it isn't the 
+# new SC file enable_sci.xml.  The enable_sci.xml file causes
+# sysid to generate warnings in a zone.
 #
-SC_ONLINE=$(svcprop -p restarter/state \
-    svc:/milestone/unconfig:default 2> /dev/null)
-if (( $? == 0 )) && [[ $SC_ONLINE == "online" ]]; then
-	cp /usr/share/auto_install/sc_profiles/enable_sci.xml \
-	    $ZONEROOT/etc/svc/profile/site
-else
-	#
-	# Make sure sysidtools run; we manually poke in the SSH action
-	# so that we get an SSH key.  Yes, this is seriously borken.
-	# See http://defect.opensolaris.org/bz/show_bug.cgi?id=741
-	#
-	printf "$m_more_brokenness\n"
-	/usr/sbin/sysidconfig -b $ZONEROOT -a /lib/svc/method/sshd
-
+mount_active_be -c zone || fail_fatal "$f_no_ds"
+if [[ $SC_ONLINE != "online" ]]; then
 	touch $ZONEROOT/etc/.UNCONFIGURED
+	if [[ -n $sc_config ]] && [[ $sc_config != \
+	    "/usr/share/auto_install/sc_profiles/enable_sci.xml" ]]; then
+		cp $sc_config $ZONEROOT/etc/sysidcfg
+	fi
 fi
 
 #