diff --git a/debian/changelog b/debian/changelog index a1e982bc..9f4eef35 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +livecd-rootfs (2.408.59) xenial; urgency=medium + + * Backport snap preseed base support (LP: #1874834) + + -- Robert C Jennings Fri, 24 Apr 2020 10:54:54 -0500 + livecd-rootfs (2.408.58) xenial; urgency=medium * Use a snap cohort key for consistent parallel builds (LP: #1866159) diff --git a/live-build/functions b/live-build/functions index fff3d679..9d6b0467 100644 --- a/live-build/functions +++ b/live-build/functions @@ -349,6 +349,47 @@ release_ver() { distro-info --series="$LB_DISTRIBUTION" -r | awk '{ print $1 }' } +_snap_post_process() { + # Look for the 'core' snap. If it is not present, assume that the image + # contains only snaps with bases >= core18. In that case snapd is + # preseeded. However, when 'core' is being installed and snapd has not + # been installed by a call to 'snap_preseed' (see below) then it is + # removed again. + local CHROOT_ROOT=$1 + local SNAP_NAME=$2 + + local seed_dir="$CHROOT_ROOT/var/lib/snapd/seed" + local snaps_dir="$seed_dir/snaps" + local seed_yaml="$seed_dir/seed.yaml" + local assertions_dir="$seed_dir/assertions" + local snapd_install_stamp="$seed_dir/.snapd-explicit-install-stamp" + + case $SNAP_NAME in + core[0-9]*) + # If the 'core' snap is not present, assume we are coreXX-only and + # install the snapd snap. + if [ ! -f ${snaps_dir}/core_[0-9]*.snap ]; then + _snap_preseed $CHROOT_ROOT snapd stable + fi + ;; + core) + # If the snapd snap has been seeded, but not marked as explicitly + # installed (see snap_preseed below), then remove it. + if [ -f ${snaps_dir}/snapd_[0-9]*.snap ] && \ + [ ! -f "$snapd_install_stamp" ] + then + # Remove snap, assertions and entry in seed.yaml + rm -f ${snaps_dir}/snapd_[0-9]*.snap + rm -f ${assertions_dir}/snapd_[0-9]*.assert + sed -i -e'N;/name: snapd/,+2d' $seed_yaml + fi + ;; + *) + # ignore + ;; + esac +} + _snap_preseed() { # Download the snap/assertion and add to the preseed local CHROOT_ROOT=$1 @@ -363,12 +404,18 @@ _snap_preseed() { # Download the snap & assertion local snap_download_failed=0 - chroot $CHROOT_ROOT sh -c " + + # Preseed a snap only once + if [ -f ${snaps_dir}/${SNAP_NAME}_[0-9]*.snap ]; then + return + fi + + sh -c " set -x; - cd /var/lib/snapd/seed; + cd \"$CHROOT_ROOT/var/lib/snapd/seed\"; SNAPPY_STORE_NO_CDN=1 snap download \ --cohort="${COHORT_KEY:-}" \ - --channel=$CHANNEL \"$SNAP_NAME\"" || snap_download_failed=1 + --channel=\"$CHANNEL\" \"$SNAP_NAME\"" || snap_download_failed=1 if [ $snap_download_failed = 1 ] ; then echo "If the channel ($CHANNEL) includes '*/ubuntu-##.##' track per " echo "Ubuntu policy (ex. stable/ubuntu-18.04) the publisher will need " @@ -381,6 +428,35 @@ _snap_preseed() { mv -v $seed_dir/*.assert $assertions_dir mv -v $seed_dir/*.snap $snaps_dir + # Pre-seed snap's base + case $SNAP_NAME in + snapd) + # snapd is self-contained, ignore base + ;; + core|core[0-9][0-9]) + # core and core## are self-contained, ignore base + ;; + *) + # Determine which core snap is needed + local snap_info + + # snap info doesn't have --channel, so must run agains the downloaded snap + snap_info=$(snap info --verbose ${snaps_dir}/${SNAP_NAME}_[0-9]*.snap) + + if [ $? -ne 0 ]; then + echo "Failed to retrieve base of $SNAP_NAME!" + exit 1 + fi + + local core_snap=$(echo "$snap_info" | grep '^base:' | awk '{print $2}') + + # If snap info does not list a base use 'core' + core_snap=${core_snap:-core} + + _snap_preseed $CHROOT_ROOT $core_snap stable + ;; + esac + # Add the snap to the seed.yaml ! [ -e $seed_yaml ] && echo "snaps:" > $seed_yaml cat <> $seed_yaml @@ -393,6 +469,8 @@ EOF echo -n " file: " >> $seed_yaml (cd $snaps_dir; ls -1 ${SNAP_NAME}_*.snap) >> $seed_yaml + + _snap_post_process $CHROOT_ROOT $SNAP_NAME } snap_prepare_assertions() { @@ -444,25 +522,43 @@ snap_prepare() { # used for the image's model assertion local CUSTOM_BRAND_MODEL=${2:-generic:generic-classic} - local seed_dir="$CHROOT_ROOT/var/lib/snapd/seed" - local snaps_dir="$seed_dir/snaps" - snap_prepare_assertions "$CHROOT_ROOT" "$CUSTOM_BRAND_MODEL" - - # Download the core snap - if ! [ -f $snaps_dir/core_[0-9]*.snap ] ; then - _snap_preseed $CHROOT_ROOT core stable - fi } snap_preseed() { # Preseed a snap in the image local CHROOT_ROOT=$1 local SNAP=$2 + local SNAP_NAME=${SNAP%/*} # Per Ubuntu policy, all seeded snaps (with the exception of the core # snap) must pull from stable/ubuntu-$(release_ver) as their channel. local CHANNEL=${3:-"stable/ubuntu-$(release_ver)"} snap_prepare $CHROOT_ROOT _snap_preseed $CHROOT_ROOT $SNAP $CHANNEL + + # Mark this image as having snapd installed explicitly. + case $SNAP_NAME in + snapd) + touch "$CHROOT_ROOT/var/lib/snapd/seed/.snapd-explicit-install-stamp" + ;; + esac + + # Do basic validation of generated snapd seed.yaml, doing it here + # means we catch all the places(tm) that snaps are added but the + # downside is that each time a snap is added the seed must be valid, + # i.e. snaps with bases need to add bases first etc + # + # Skip validation by setting SNAP_NO_VALIDATE_SEED=1. + if [ -z "${SNAP_NO_VALIDATE_SEED:-}" ]; then + snap_validate_seed "${CHROOT_ROOT}" + fi +} + +snap_validate_seed() { + local CHROOT_ROOT=$1 + + if [ -e "${CHROOT_ROOT}/var/lib/snapd/seed/seed.yaml" ]; then + snap debug validate-seed "${CHROOT_ROOT}/var/lib/snapd/seed/seed.yaml" + fi }