diff --git a/features/features.go b/features/features.go index 40fd709b474..e2b37f91782 100644 --- a/features/features.go +++ b/features/features.go @@ -40,8 +40,6 @@ const ( ParallelInstances // Hotplug controls availability of dynamically creating slots based on system hardware. Hotplug - // SnapdSnap controls possibility of installing the snapd snap. - SnapdSnap // PerUserMountNamespace controls the persistence of per-user mount namespaces. PerUserMountNamespace // RefreshAppAwareness controls refresh being aware of running applications. @@ -101,7 +99,6 @@ var featureNames = map[SnapdFeature]string{ Layouts: "layouts", ParallelInstances: "parallel-instances", Hotplug: "hotplug", - SnapdSnap: "snapd-snap", PerUserMountNamespace: "per-user-mount-namespace", RefreshAppAwareness: "refresh-app-awareness", diff --git a/features/features_test.go b/features/features_test.go index 2db23e772bf..48783a25ab6 100644 --- a/features/features_test.go +++ b/features/features_test.go @@ -48,7 +48,6 @@ func (*featureSuite) TestName(c *C) { check(features.Layouts, "layouts") check(features.ParallelInstances, "parallel-instances") check(features.Hotplug, "hotplug") - check(features.SnapdSnap, "snapd-snap") check(features.PerUserMountNamespace, "per-user-mount-namespace") check(features.RefreshAppAwareness, "refresh-app-awareness") check(features.ClassicPreservesXdgRuntimeDir, "classic-preserves-xdg-runtime-dir") @@ -88,8 +87,6 @@ func (*featureSuite) TestIsExported(c *C) { check(features.Layouts, false) check(features.Hotplug, false) - check(features.SnapdSnap, false) - check(features.ParallelInstances, true) check(features.PerUserMountNamespace, true) check(features.RefreshAppAwareness, true) @@ -216,7 +213,6 @@ func (*featureSuite) TestIsEnabledWhenUnset(c *C) { check(features.Layouts, true) check(features.ParallelInstances, false) check(features.Hotplug, false) - check(features.SnapdSnap, false) check(features.PerUserMountNamespace, false) check(features.RefreshAppAwareness, true) check(features.ClassicPreservesXdgRuntimeDir, true) diff --git a/overlord/snapstate/snapmgr.go b/overlord/snapstate/snapmgr.go index 7b5719f3e6d..879de24cb4c 100644 --- a/overlord/snapstate/snapmgr.go +++ b/overlord/snapstate/snapmgr.go @@ -20,7 +20,6 @@ package snapstate import ( - "context" "errors" "fmt" "io" @@ -1169,112 +1168,6 @@ func changeInFlight(st *state.State) bool { return false } -// ensureSnapdSnapTransition will migrate systems to use the "snapd" snap -func (m *SnapManager) ensureSnapdSnapTransition() error { - m.state.Lock() - defer m.state.Unlock() - - // we only auto-transition people on classic systems, for core we - // will need to do a proper re-model - if !release.OnClassic { - return nil - } - - // Wait for the system to be seeded before transtioning - var seeded bool - err := m.state.Get("seeded", &seeded) - if err != nil { - if !errors.Is(err, state.ErrNoState) { - // already seeded or other error - return err - } - return nil - } - if !seeded { - return nil - } - - // check if snapd snap is installed - var snapst SnapState - err = Get(m.state, "snapd", &snapst) - if err != nil && !errors.Is(err, state.ErrNoState) { - return err - } - // nothing to do - if snapst.IsInstalled() { - return nil - } - - // check if the user opts into the snapd snap - optedIntoSnapdTransition, err := optedIntoSnapdSnap(m.state) - if err != nil { - return err - } - // nothing to do: the user does not want the snapd snap yet - if !optedIntoSnapdTransition { - return nil - } - - // ensure we only transition systems that have snaps already - installedSnaps, err := NumSnaps(m.state) - if err != nil { - return err - } - // no installed snaps (yet): do nothing (fresh classic install) - if installedSnaps == 0 { - return nil - } - - // get current core snap and use same channel/user for the snapd snap - err = Get(m.state, "core", &snapst) - // Note that state.ErrNoState should never happen in practice. However - // if it *does* happen we still want to fix those systems by installing - // the snapd snap. - if err != nil && !errors.Is(err, state.ErrNoState) { - return err - } - coreChannel := snapst.TrackingChannel - // snapd/core are never blocked on auth so we don't need to copy - // the userID from the snapst here - userID := 0 - - if changeInFlight(m.state) { - // check that there is no change in flight already, this is a - // precaution to ensure the snapd transition is safe - return nil - } - - // ensure we limit the retries in case something goes wrong - var lastSnapdTransitionAttempt time.Time - err = m.state.Get("snapd-transition-last-retry-time", &lastSnapdTransitionAttempt) - if err != nil && !errors.Is(err, state.ErrNoState) { - return err - } - now := time.Now() - if !lastSnapdTransitionAttempt.IsZero() && lastSnapdTransitionAttempt.Add(snapdTransitionDelayWithRandomness).After(now) { - return nil - } - m.state.Set("snapd-transition-last-retry-time", now) - - var retryCount int - err = m.state.Get("snapd-transition-retry", &retryCount) - if err != nil && !errors.Is(err, state.ErrNoState) { - return err - } - m.state.Set("snapd-transition-retry", retryCount+1) - - ts, err := Install(context.Background(), m.state, "snapd", &RevisionOptions{Channel: coreChannel}, userID, Flags{}) - if err != nil { - return err - } - - msg := i18n.G("Transition to the snapd snap") - chg := m.state.NewChange("transition-to-snapd-snap", msg) - chg.AddAll(ts) - - return nil -} - // ensureUbuntuCoreTransition will migrate systems that use "ubuntu-core" // to the new "core" snap func (m *SnapManager) ensureUbuntuCoreTransition() error { @@ -1593,7 +1486,6 @@ func (m *SnapManager) Ensure() error { m.ensureAliasesV2(), m.ensureForceDevmodeDropsDevmodeFromState(), m.ensureUbuntuCoreTransition(), - m.ensureSnapdSnapTransition(), // we should check for full regular refreshes before // considering issuing a hint only refresh request m.autoRefresh.Ensure(), diff --git a/overlord/snapstate/snapstate.go b/overlord/snapstate/snapstate.go index 04f576cd8c0..d657b82d972 100644 --- a/overlord/snapstate/snapstate.go +++ b/overlord/snapstate/snapstate.go @@ -194,15 +194,6 @@ func isParallelInstallable(snapsup *SnapSetup) error { return fmt.Errorf("cannot install snap of type %v as %q", snapsup.Type, snapsup.InstanceName()) } -func optedIntoSnapdSnap(st *state.State) (bool, error) { - tr := config.NewTransaction(st) - experimentalAllowSnapd, err := features.Flag(tr, features.SnapdSnap) - if err != nil && !config.IsNoOption(err) { - return false, err - } - return experimentalAllowSnapd, nil -} - // refreshRetain returns refresh.retain value if set, or the default value (different for core and classic). // It deals with potentially wrong type due to lax validation. func refreshRetain(st *state.State) int { diff --git a/overlord/snapstate/snapstate_test.go b/overlord/snapstate/snapstate_test.go index d87958728a8..e25103cf085 100644 --- a/overlord/snapstate/snapstate_test.go +++ b/overlord/snapstate/snapstate_test.go @@ -5916,46 +5916,6 @@ func (s *snapmgrTestSuite) TestTransitionCoreBlocksOtherChanges(c *C) { c.Check(ts, NotNil) } -func (s *snapmgrTestSuite) TestTransitionSnapdSnapDoesNotRunWithoutSnaps(c *C) { - s.state.Lock() - defer s.state.Unlock() - - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - // no snaps installed on this system (e.g. fresh classic) - snapstate.Set(s.state, "core", nil) - - s.settle(c) - - c.Check(s.state.Changes(), HasLen, 0) -} - -func (s *snapmgrTestSuite) TestTransitionSnapdSnapDoesRunWithAnySnap(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - // some snap installed on this system but no core - snapstate.Set(s.state, "core", nil) - snapstate.Set(s.state, "foo", &snapstate.SnapState{ - Active: true, - Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{{RealName: "foo", SnapID: "foo-id", Revision: snap.R(1), Channel: "beta"}}), - Current: snap.R(1), - }) - - s.settle(c) - - c.Check(s.state.Changes(), HasLen, 1) -} - func (s *snapmgrTestSuite) TestTransitionSnapdSnapDoesNotRunWhenNotEnabled(c *C) { s.state.Lock() defer s.state.Unlock() @@ -5972,108 +5932,6 @@ func (s *snapmgrTestSuite) TestTransitionSnapdSnapDoesNotRunWhenNotEnabled(c *C) c.Check(s.state.Changes(), HasLen, 0) } -func (s *snapmgrTestSuite) TestTransitionSnapdSnapStartsAutomaticallyWhenEnabled(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - snapstate.Set(s.state, "core", &snapstate.SnapState{ - Active: true, - Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{{RealName: "core", SnapID: "core-snap-id", Revision: snap.R(1), Channel: "beta"}}), - Current: snap.R(1), - SnapType: "os", - }) - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - s.settle(c) - - c.Assert(s.state.Changes(), HasLen, 1) - chg := s.state.Changes()[0] - c.Check(chg.Kind(), Equals, "transition-to-snapd-snap") - c.Assert(chg.Err(), IsNil) - c.Assert(chg.IsReady(), Equals, true) - - // snapd snap is installed from the default channel - var snapst snapstate.SnapState - snapstate.Get(s.state, "snapd", &snapst) - c.Assert(snapst.TrackingChannel, Equals, "latest/stable") -} - -func (s *snapmgrTestSuite) TestTransitionSnapdSnapWithCoreRunthrough(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - // setup a classic model so the device context says we are on classic - defer snapstatetest.MockDeviceModel(ClassicModel())() - - snapstate.Set(s.state, "core", &snapstate.SnapState{ - Active: true, - Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{{RealName: "core", SnapID: "core-snap-id", Revision: snap.R(1), Channel: "edge"}}), - Current: snap.R(1), - SnapType: "os", - // TrackingChannel - TrackingChannel: "latest/beta", - }) - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - s.settle(c) - - c.Assert(s.state.Changes(), HasLen, 1) - chg := s.state.Changes()[0] - c.Assert(chg.Kind(), Equals, "transition-to-snapd-snap") - c.Assert(chg.Err(), IsNil) - c.Assert(chg.IsReady(), Equals, true) - c.Check(s.fakeStore.downloads, HasLen, 1) - ts := state.NewTaskSet(chg.Tasks()...) - // task set was reconstituted from change tasks, so edges information is - // lost - verifyInstallTasks(c, snap.TypeSnapd, noConfigure|noLastBeforeModificationsEdge, 0, ts) - - // ensure preferences from the core snap got transferred over - var snapst snapstate.SnapState - snapstate.Get(s.state, "snapd", &snapst) - c.Assert(snapst.TrackingChannel, Equals, "latest/beta") -} - -func (s *snapmgrTestSuite) TestTransitionSnapdSnapTimeLimitWorks(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - // tried 3h ago, no retry - s.state.Set("snapd-transition-last-retry-time", time.Now().Add(-3*time.Hour)) - - s.settle(c) - - c.Check(s.state.Changes(), HasLen, 0) - - // tried 7h ago, retry - s.state.Set("snapd-transition-last-retry-time", time.Now().Add(-7*time.Hour)) - - s.settle(c) - - c.Check(s.state.Changes(), HasLen, 1) - - var t time.Time - s.state.Get("snapd-transition-last-retry-time", &t) - c.Assert(time.Since(t) < 2*time.Minute, Equals, true) -} - type unhappyStore struct { *fakeStore } @@ -6086,46 +5944,6 @@ func (s unhappyStore) SnapAction(ctx context.Context, currentSnaps []*store.Curr return nil, nil, fmt.Errorf("a grumpy store") } -func (s *snapmgrTestSuite) TestTransitionSnapdSnapError(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - snapstate.ReplaceStore(s.state, unhappyStore{fakeStore: s.fakeStore}) - - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - s.state.Unlock() - - err := s.o.Settle(5 * time.Second) - c.Assert(err, ErrorMatches, `state ensure errors: \[a grumpy store\]`) - - s.state.Lock() - c.Check(s.state.Changes(), HasLen, 0) - - // all the attempts were recorded - var t time.Time - s.state.Get("snapd-transition-last-retry-time", &t) - c.Assert(time.Since(t) < 2*time.Minute, Equals, true) - - var cnt int - s.state.Get("snapd-transition-retry", &cnt) - c.Assert(cnt, Equals, 1) - - // the transition is not tried again (because of retry time) - s.state.Unlock() - err = s.o.Settle(5 * time.Second) - c.Assert(err, IsNil) - s.state.Lock() - - s.state.Get("snapd-transition-retry", &cnt) - c.Assert(cnt, Equals, 1) -} - func (s *snapmgrTestSuite) TestTransitionSnapdSnapBlocksOtherChanges(c *C) { s.state.Lock() defer s.state.Unlock() @@ -6868,40 +6686,6 @@ func (s *snapmgrTestSuite) TestSnapdSnapOnCoreWithoutBase(c *C) { c.Assert(err, IsNil) } -func (s *snapmgrTestSuite) TestSnapdSnapOnSystemsWithoutBaseOnUbuntuCore(c *C) { - s.state.Lock() - defer s.state.Unlock() - r := release.MockOnClassic(false) - defer r() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - // it is not possible to opt-into the snapd snap on core yet - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - // it is now possible to install snapd snap on a system with core, experimental option has no effect - _, err := snapstate.Install(context.Background(), s.state, "snapd", nil, s.user.ID, snapstate.Flags{}) - c.Assert(err, IsNil) -} - -func (s *snapmgrTestSuite) TestNoSnapdSnapOnSystemsWithoutBaseButOption(c *C) { - s.state.Lock() - defer s.state.Unlock() - - // remove snapd snap added for snapmgrBaseTest - snapstate.Set(s.state, "snapd", nil) - - tr := config.NewTransaction(s.state) - tr.Set("core", "experimental.snapd-snap", true) - tr.Commit() - - _, err := snapstate.Install(context.Background(), s.state, "snapd", nil, s.user.ID, snapstate.Flags{}) - c.Assert(err, IsNil) -} - func (s *snapmgrTestSuite) TestNoConfigureForSnapdSnap(c *C) { s.state.Lock() defer s.state.Unlock() diff --git a/tests/main/snapd-reexec-snapd-snap/task.yaml b/tests/main/snapd-reexec-snapd-snap/task.yaml deleted file mode 100644 index 2319b51c185..00000000000 --- a/tests/main/snapd-reexec-snapd-snap/task.yaml +++ /dev/null @@ -1,63 +0,0 @@ -summary: Test that snapd reexecs itself into the snapd snap - -details: | - This test ensures that snap cli reexecs itself into the snapd snap under the - right conditions (when SNAP_REEXEC is set and when experimental.snapd-snap=true) - - We also check that the snapd snap is automatically installed when the - experimental.snapd-snap feature is enabled. - -# Disable for Fedora, openSUSE and Arch as re-exec is not support there yet -systems: [-ubuntu-core-*, -fedora-*, -opensuse-*, -arch-*, -amazon-*, -centos-*] - -restore: | - umount /snap/snapd/current/usr/lib/snapd/info || true - -debug: | - echo 'experimental "snapd-snap" feature is enabled:' - snap get core experimental.snapd-snap || true - - echo "snap changes" - snap changes || true - - echo "list of installed snaps" - snap list || true - -execute: | - if [ "${SNAP_REEXEC:-}" = "0" ]; then - echo "skipping test when SNAP_REEXEC is disabled" - exit 0 - fi - - # remove all snaps to remove snapd - snap remove core - snap remove snapd - - # TODO the 'old' snapd keeps running, this should be fixed in snapd snap - systemctl restart snapd - - # TODO the test should install the snapd snap we built - snap install --dangerous "$TESTSTMP"/core_snap/core_*.snap - - echo "Enable installing the snapd snap, this happens automatically" - snap set core experimental.snapd-snap=true - echo "Ensure transition" - snap debug ensure-state-soon - # give the state time to create the change and then start watching it - retry -n 30 snap watch --last=transition-to-snapd-snap - snap list snapd - - # installing the snapd snap should result in a daemon restart so that - # the snapd from the snap can be used. It won't be used in this test - # because the version of the snapd from the store is lower than the - # version of the installed snapd. - "$TESTSTOOLS"/journal-state match-log "Requested daemon restart." - - # We need to pretend the version of snapd in the snapd snap is the same - # as the installed one so that it re-execs. We use a higher version in - # the local snap and "tweak" the core snap to get re-exec but this will - # only work with core re-exec not snapd-reexec. - mount -o bind /usr/lib/snapd/info /snap/snapd/current/usr/lib/snapd/info - - echo "Ensure we re-exec by default" - /usr/bin/env SNAPD_DEBUG=1 snap list 2>&1 | MATCH 'DEBUG: restarting into "/snap/snapd/current/usr/bin/snap"' diff --git a/tests/main/snapd-snap-transition-experimental-flag/task.yaml b/tests/main/snapd-snap-transition-experimental-flag/task.yaml deleted file mode 100644 index dc2153fdee2..00000000000 --- a/tests/main/snapd-snap-transition-experimental-flag/task.yaml +++ /dev/null @@ -1,32 +0,0 @@ -summary: Ensure snapd-snap experimental flag based transition to snapd snap works. - -details: | - Ensure that we can transition classic systems from core snap - to snapd snap using the snapd-snap experimental flag. - -# Exclude Ubuntu Core systems - require proper remodeling -systems: [-ubuntu-core-*] - -prepare: | - # remove all snaps to remove snapd - snap remove core - # this is only possible when snapd is the only installed snap - snap remove snapd - # at this point we expect to be running from the distro package - systemctl restart snapd.service - - # transition from core snap to snapd snap - snap install --dangerous "$TESTSTMP"/core_snap/core_*.snap -execute: | - echo "Enable the snapd snap experimental feature" - snap set core experimental.snapd-snap=true - - for _ in $(seq 30); do - snap debug ensure-state-soon - if snap list snapd; then - break - fi - sleep 6 - done - snap list snapd - snap changes | MATCH "Transition to the snapd snap" diff --git a/tests/main/snapd-without-core/task.yaml b/tests/main/snapd-without-core/task.yaml deleted file mode 100644 index b680e260c98..00000000000 --- a/tests/main/snapd-without-core/task.yaml +++ /dev/null @@ -1,49 +0,0 @@ -summary: Ensure the snapd works without core on classic systems - -details: | - Check that snapd can be installed without the core snap on classic - systems and that commands can re-exec into snapd. - -# Run only on ubuntu classic because this re-execs. We have a -# separate test for UC18 already and on UC16 we always have a core -# snap so we don't need to test there. -systems: [ubuntu-1*-64, ubuntu-2*-64] - -environment: - # uploading large snap triggers OOM - SNAPD_NO_MEMORY_LIMIT: 1 - -restore: | - rm -f /tmp/snapd_*.snap - -execute: | - if [ "${SNAP_REEXEC:-}" = "0" ]; then - echo "skipping test when SNAP_REEXEC is disabled" - exit 0 - fi - - echo "Create modified snapd snap" - #shellcheck source=tests/lib/prepare.sh - . "$TESTSLIB"/prepare.sh - build_snapd_snap /tmp - - echo "Ensure core is gone so that we can have snapd" - #shellcheck source=tests/lib/pkgdb.sh - . "$TESTSLIB"/pkgdb.sh - distro_purge_package snapd - distro_install_build_snapd - - echo "Install the snapd snap" - snap set core experimental.snapd-snap=true - snap install --dangerous /tmp/snapd_*.snap - echo "Ensure we restarted into the snapd snap" - "$TESTSTOOLS"/journal-state match-log 'restarting into "/snap/snapd/' - - echo "Now install a core18 based snap and ensure it works" - snap install test-snapd-sh-core18 - test-snapd-sh-core18.sh -c 'echo hello' | MATCH hello - echo "No core was installed" - snap list | not grep ^"core " - - echo "Ensure we re-exec to the snapd snap" - SNAPD_DEBUG=1 test-snapd-sh-core18.sh -c 'true' 2>&1 | MATCH 'restarting into "/snap/snapd/current'