From 4d79b097d7f704a2780dce9455ebb9998a19ec4e Mon Sep 17 00:00:00 2001 From: ernestl Date: Tue, 9 Jul 2024 17:57:48 +0200 Subject: [PATCH] overlord, overlord/snapstate: install snapd on classic systems when missing --- overlord/managers_test.go | 27 +++- overlord/snapstate/aliasesv2_test.go | 1 + overlord/snapstate/autorefresh_gating_test.go | 16 +++ overlord/snapstate/backend_test.go | 2 +- overlord/snapstate/handlers.go | 31 ++++- overlord/snapstate/handlers_prereq_test.go | 126 +++++++++++++----- overlord/snapstate/snapstate_install_test.go | 12 ++ overlord/snapstate/snapstate_test.go | 46 ++++++- 8 files changed, 217 insertions(+), 44 deletions(-) diff --git a/overlord/managers_test.go b/overlord/managers_test.go index f96578b38c90..6edfa5ff1995 100644 --- a/overlord/managers_test.go +++ b/overlord/managers_test.go @@ -465,6 +465,19 @@ func (s *baseMgrsSuite) SetUpTest(c *C) { }, }) + // add snapd itself + snapstate.Set(st, "snapd", &snapstate.SnapState{ + Active: true, + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", SnapID: fakeSnapID("snapd"), Revision: snap.R(1)}, + }), + Current: snap.R(1), + SnapType: "snapd", + Flags: snapstate.Flags{ + Required: true, + }, + }) + // commonly used core and snapd revisions in tests defaultInfoFile := ` VERSION=2.54.3+git1.g479e745-dirty @@ -575,6 +588,13 @@ func (s *mgrsSuiteCore) SetUpTest(c *C) { // it panicking. restore := release.MockOnClassic(false) s.baseMgrsSuite.SetUpTest(c) + + // remove snapd snap added for baseMgrsSuite + st := s.o.State() + st.Lock() + snapstate.Set(st, "snapd", nil) + st.Unlock() + s.AddCleanup(restore) } @@ -712,9 +732,11 @@ hooks: // nothing in snaps all, err := snapstate.All(st) c.Assert(err, IsNil) - c.Check(all, HasLen, 1) + c.Check(all, HasLen, 2) _, ok := all["core"] c.Check(ok, Equals, true) + _, ok = all["snapd"] + c.Check(ok, Equals, true) // nothing in config var config map[string]*json.RawMessage @@ -6061,6 +6083,9 @@ func (s *kernelSuite) SetUpTest(c *C) { st.Lock() defer st.Unlock() + // remove snapd snap added for baseMgrsSuite + snapstate.Set(st, "snapd", nil) + // create/set custom model assertion model := s.brands.Model("can0nical", "my-model", modelDefaults) devicestatetest.SetDevice(st, &auth.DeviceState{ diff --git a/overlord/snapstate/aliasesv2_test.go b/overlord/snapstate/aliasesv2_test.go index c62ab3a9a440..6a81dcea859f 100644 --- a/overlord/snapstate/aliasesv2_test.go +++ b/overlord/snapstate/aliasesv2_test.go @@ -248,6 +248,7 @@ func (s *snapmgrTestSuite) TestAutoAliasesDeltaAll(c *C) { c.Check(seen, DeepEquals, map[string]bool{ "core": true, + "snapd": true, "alias-snap": true, "other-snap": true, "alias-snap-apps-go-away": true, diff --git a/overlord/snapstate/autorefresh_gating_test.go b/overlord/snapstate/autorefresh_gating_test.go index 1828c1ae72f3..2dfaaaa287ad 100644 --- a/overlord/snapstate/autorefresh_gating_test.go +++ b/overlord/snapstate/autorefresh_gating_test.go @@ -1960,6 +1960,14 @@ func (s *snapmgrTestSuite) testAutoRefreshPhase2(c *C, beforePhase1 func(), gate st.Lock() defer st.Unlock() + // prevent automatic installation of snapd + /*snapstate.Set(s.state, "snapd", &snapstate.SnapState{ + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", Revision: snap.R(1)}, + }), + Current: snap.R(1), + })*/ + // enable gate-auto-refresh-hook feature tr := config.NewTransaction(s.state) tr.Set("core", "experimental.gate-auto-refresh-hook", true) @@ -2255,6 +2263,14 @@ func (s *snapmgrTestSuite) testAutoRefreshPhase2DiskSpaceCheck(c *C, fail bool) st.Lock() defer st.Unlock() + // prevent automatic installation of snapd + /*snapstate.Set(s.state, "snapd", &snapstate.SnapState{ + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", Revision: snap.R(1)}, + }), + Current: snap.R(1), + })*/ + restore := snapstate.MockOsutilCheckFreeSpace(func(path string, sz uint64) error { c.Check(sz, Equals, snapstate.SafetyMarginDiskSpace(123)) if fail { diff --git a/overlord/snapstate/backend_test.go b/overlord/snapstate/backend_test.go index e8e5fc3836aa..8edbe4c3ff1f 100644 --- a/overlord/snapstate/backend_test.go +++ b/overlord/snapstate/backend_test.go @@ -261,7 +261,7 @@ func (f *fakeStore) snap(spec snapSpec) (*snap.Info, error) { switch spec.Name { case "core", "core16", "ubuntu-core", "some-core": typ = snap.TypeOS - case "some-base", "other-base", "some-other-base", "yet-another-base", "core18", "core22": + case "some-base", "other-base", "some-other-base", "yet-another-base", "core18", "core20", "core22", "core24", "bare": typ = snap.TypeBase case "some-kernel": typ = snap.TypeKernel diff --git a/overlord/snapstate/handlers.go b/overlord/snapstate/handlers.go index 276640e65821..c91419502c52 100644 --- a/overlord/snapstate/handlers.go +++ b/overlord/snapstate/handlers.go @@ -383,11 +383,19 @@ func (m *SnapManager) installOneBaseOrRequired(t *state.Task, snapName string, c // retrying the operation. var conflErr *ChangeConflictError if errors.As(err, &conflErr) { + // TODO: Fix unit test to enable this + // if we are not seeded it is too early to do installs + /*if conflErr.ChangeKind == "seed" { + t.Logf("cannot install %q before seeding: %s", snapName, conflErr) + return nil, nil + }*/ + // conflicted with an install in the same change, just skip if conflErr.ChangeID == t.Change().ID() { return nil, nil } + // TODO: Track retries and warn/terminate on threshold return nil, &state.Retry{After: prerequisitesRetryTimeout} } return ts, err @@ -561,18 +569,27 @@ func (m *SnapManager) installPrereqs(t *state.Task, base string, prereq map[stri } } - // on systems without core or snapd need to install snapd to - // make interfaces work - LP: 1819318 + // On systems without core or snapd need to install snapd to make + // interfaces work - LP: 1819318. Ubuntu Core systems must always + // have either core or snapd. On classic systems, to ensure + // consistent behaviour with all bases, we always install snapd. var tsSnapd *state.TaskSet snapdSnapInstalled, err := isInstalled(st, "snapd") if err != nil { return err } - coreSnapInstalled, err := isInstalled(st, "core") - if err != nil { - return err - } - if base != "core" && !snapdSnapInstalled && !coreSnapInstalled { + + // Required for unit test TestPreseedOnClassicHappy which runs + // as classic system that is not yet seeded. Attempting snapd + // installation in non seeded system result in conflict error + // without change ID (even though it is for the same change) + // forever retries due to InstallWithDeviceContext conflict + // error handling of installOneBaseOrRequired. Alternatively + // we can skip install on seed conflict error. + deviceCtx, err := DevicePastSeeding(st, nil) + seeded := err == nil && deviceCtx != nil + + if release.OnClassic && seeded && !snapdSnapInstalled { timings.Run(tm, "install-prereq", "install snapd", func(timings.Measurer) { noTypeBaseCheck := false tsSnapd, err = m.installOneBaseOrRequired(t, "snapd", nil, noTypeBaseCheck, defaultSnapdSnapsChannel(), onInFlightErr, userID, Flags{ diff --git a/overlord/snapstate/handlers_prereq_test.go b/overlord/snapstate/handlers_prereq_test.go index a6e52e1e9514..bb70b6500cf3 100644 --- a/overlord/snapstate/handlers_prereq_test.go +++ b/overlord/snapstate/handlers_prereq_test.go @@ -91,13 +91,45 @@ func (s *prereqSuite) SetUpTest(c *C) { func (s *prereqSuite) TestDoPrereqNothingToDo(c *C) { s.state.Lock() - si1 := &snap.SideInfo{ - RealName: "core", - Revision: snap.R(1), - } + // install snapd so that prerequisites handler won't try to install it + snapstate.Set(s.state, "snapd", &snapstate.SnapState{ + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", Revision: snap.R(1)}, + }), + Current: snap.R(1), + }) + + t := s.state.NewTask("prerequisites", "test") + t.Set("snap-setup", &snapstate.SnapSetup{ + SideInfo: &snap.SideInfo{ + RealName: "foo", + Revision: snap.R(33), + }, + Base: "none", + }) + s.state.NewChange("sample", "...").AddTask(t) + s.state.Unlock() + + s.se.Ensure() + s.se.Wait() + + s.state.Lock() + defer s.state.Unlock() + c.Assert(s.fakeBackend.ops, HasLen, 0) + c.Check(t.Status(), Equals, state.DoneStatus) +} + +func (s *prereqSuite) TestDoPrereqNothingToDoOnCore(c *C) { + restore := release.MockOnClassic(false) + defer restore() + + s.state.Lock() + snapstate.Set(s.state, "core", &snapstate.SnapState{ - Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{si1}), - Current: si1.Revision, + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "core", Revision: snap.R(1)}, + }), + Current: snap.R(1), }) t := s.state.NewTask("prerequisites", "test") @@ -106,6 +138,7 @@ func (s *prereqSuite) TestDoPrereqNothingToDo(c *C) { RealName: "foo", Revision: snap.R(33), }, + Base: "core", }) s.state.NewChange("sample", "...").AddTask(t) s.state.Unlock() @@ -302,11 +335,23 @@ func (s *prereqSuite) TestDoPrereqTalksToStoreAndQueues(c *C) { }, revno: snap.R(11), }, + { + op: "storesvc-snap-action", + }, + { + op: "storesvc-snap-action:action", + action: store.SnapAction{ + Action: "install", + InstanceName: "snapd", + Channel: "stable", + }, + revno: snap.R(11), + }, }) c.Check(t.Status(), Equals, state.DoneStatus) // check that the do-prereq task added all needed prereqs - expectedLinkedSnaps := []string{"prereq1", "prereq2", "some-base"} + expectedLinkedSnaps := []string{"prereq1", "prereq2", "some-base", "snapd"} linkedSnaps := make([]string, 0, len(expectedLinkedSnaps)) for _, t := range chg.Tasks() { if t.Kind() == "link-snap" { @@ -363,6 +408,14 @@ func (s *prereqSuite) TestDoPrereqRetryWhenBaseInFlight(c *C) { }, }) + // install snapd so that prerequisites handler won't try to install it + snapstate.Set(s.state, "snapd", &snapstate.SnapState{ + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", Revision: snap.R(1)}, + }), + Current: snap.R(1), + }) + // pretend foo gets installed and needs core (which is in progress) prereqTask = s.state.NewTask("prerequisites", "foo") prereqTask.Set("snap-setup", &snapstate.SnapSetup{ @@ -480,10 +533,11 @@ func (s *prereqSuite) TestDoPrereqChannelEnvvars(c *C) { defer os.Unsetenv("SNAPD_PREREQS_CHANNEL") s.state.Lock() - snapstate.Set(s.state, "core", &snapstate.SnapState{ + // install snapd so that prerequisites handler won't try to install it + snapstate.Set(s.state, "snapd", &snapstate.SnapState{ Active: true, Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ - {RealName: "core", Revision: snap.R(1)}, + {RealName: "snapd", Revision: snap.R(1)}, }), Current: snap.R(1), SnapType: "os", @@ -602,7 +656,10 @@ func (s *prereqSuite) TestDoPrereqNothingToDoForSnapdSnap(c *C) { s.state.Unlock() } -func (s *prereqSuite) TestDoPrereqCore16wCoreNothingToDo(c *C) { +func (s *prereqSuite) TestDoPrereqCore16WithCoreNothingToDoOnCore(c *C) { + restore := release.MockOnClassic(false) + defer restore() + s.state.Lock() si1 := &snap.SideInfo{ @@ -634,12 +691,8 @@ func (s *prereqSuite) TestDoPrereqCore16wCoreNothingToDo(c *C) { c.Check(t.Status(), Equals, state.DoneStatus) } -func (s *prereqSuite) testDoPrereqNoCorePullsInSnaps(c *C, base string) { - restore := release.MockOnClassic(true) - defer restore() - +func (s *prereqSuite) testDoPrereqBasePullsInSnapd(c *C, base string) { s.state.Lock() - t := s.state.NewTask("prerequisites", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ @@ -687,16 +740,36 @@ func (s *prereqSuite) testDoPrereqNoCorePullsInSnaps(c *C, base string) { c.Check(t.Status(), Equals, state.DoneStatus) } -func (s *prereqSuite) TestDoPrereqCore16noCore(c *C) { - s.testDoPrereqNoCorePullsInSnaps(c, "core16") +func (s *prereqSuite) TestDoPrereqCorePullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core") +} + +func (s *prereqSuite) TestDoPrereqCore16PullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core16") +} + +func (s *prereqSuite) TestDoPrereqCore18PullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core18") +} + +func (s *prereqSuite) TestDoPrereqCore20PullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core20") +} + +func (s *prereqSuite) TestDoPrereqCore22PullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core22") } -func (s *prereqSuite) TestDoPrereqCore18NoCorePullsInSnapd(c *C) { - s.testDoPrereqNoCorePullsInSnaps(c, "core18") +func (s *prereqSuite) TestDoPrereqCore24PullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "core24") } -func (s *prereqSuite) TestDoPrereqOtherBaseNoCorePullsInSnapd(c *C) { - s.testDoPrereqNoCorePullsInSnaps(c, "some-base") +func (s *prereqSuite) TestDoPrereqBarePullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "bare") +} + +func (s *prereqSuite) TestDoPrereqOtherBasePullsInSnapd(c *C) { + s.testDoPrereqBasePullsInSnapd(c, "other-base") } func (s *prereqSuite) TestDoPrereqBaseIsNotBase(c *C) { @@ -914,17 +987,6 @@ func (s *prereqSuite) TestDoPrereqSkipDuringRemodel(c *C) { // ChangeConflictError, which is then ignored, making this test invalid snapstate.ReplaceStore(s.state, storetest.Store{}) - // install snapd so that prerequisites handler won't try to install it - snapstate.Set(s.state, "snapd", &snapstate.SnapState{ - Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ - { - RealName: "snapd", - Revision: snap.R(1), - }, - }), - Current: snap.R(1), - }) - prereqTask := s.state.NewTask("prerequisites", "test") prereqTask.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ diff --git a/overlord/snapstate/snapstate_install_test.go b/overlord/snapstate/snapstate_install_test.go index 1598a2f963b6..aa4ec0eb9ace 100644 --- a/overlord/snapstate/snapstate_install_test.go +++ b/overlord/snapstate/snapstate_install_test.go @@ -364,6 +364,9 @@ func (s *snapmgrTestSuite) TestInstallSnapdSnapTypeOnClassic(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())() @@ -385,6 +388,9 @@ func (s *snapmgrTestSuite) TestInstallSnapdSnapTypeOnCore(c *C) { s.state.Lock() defer s.state.Unlock() + // remove snapd snap added for snapmgrBaseTest + snapstate.Set(s.state, "snapd", nil) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} ts, err := snapstate.Install(context.Background(), s.state, "snapd", opts, 0, snapstate.Flags{}) c.Assert(err, IsNil) @@ -508,6 +514,9 @@ func (s *snapmgrTestSuite) TestInstallWithDeviceContextNoRemodelConflict(c *C) { s.state.Lock() defer s.state.Unlock() + // remove snapd snap added for snapmgrBaseTest + snapstate.Set(s.state, "snapd", nil) + // unset the global store, it will need to come via the device context snapstate.ReplaceStore(s.state, nil) @@ -904,6 +913,9 @@ func (s *snapmgrTestSuite) TestInstallSnapdConflict(c *C) { s.state.Lock() defer s.state.Unlock() + // remove snapd snap added for snapmgrBaseTest + snapstate.Set(s.state, "snapd", nil) + tugc := s.state.NewTask("update-gadget-cmdline", "update gadget cmdline") chg := s.state.NewChange("optional-kernel-cmdline", "optional kernel cmdline") chg.AddTask(tugc) diff --git a/overlord/snapstate/snapstate_test.go b/overlord/snapstate/snapstate_test.go index c77067775737..e9220b3ae8a5 100644 --- a/overlord/snapstate/snapstate_test.go +++ b/overlord/snapstate/snapstate_test.go @@ -307,6 +307,14 @@ func (s *snapmgrBaseTest) SetUpTest(c *C) { Current: snap.R(1), SnapType: "os", }) + snapstate.Set(s.state, "snapd", &snapstate.SnapState{ + Active: true, + Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ + {RealName: "snapd", Revision: snap.R(1)}, + }), + Current: snap.R(1), + SnapType: "snapd", + }) // commonly used revisions in tests defaultInfoFile := ` @@ -5915,6 +5923,9 @@ 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() @@ -5952,6 +5963,9 @@ func (s *snapmgrTestSuite) TestTransitionSnapdSnapStartsAutomaticallyWhenEnabled 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"}}), @@ -5964,13 +5978,13 @@ func (s *snapmgrTestSuite) TestTransitionSnapdSnapStartsAutomaticallyWhenEnabled s.settle(c) - c.Check(s.state.Changes(), HasLen, 1) + 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 instaleld from the default channel + // 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") @@ -5980,6 +5994,9 @@ 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())() @@ -6018,6 +6035,9 @@ 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() @@ -6057,6 +6077,9 @@ 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) @@ -6227,6 +6250,7 @@ func (s *snapmgrTestSuite) TestEnsureAliasesV2(c *C) { } snapstate.Set(s.state, "core", nil) + snapstate.Set(s.state, "snapd", nil) snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ {RealName: "alias-snap", Revision: snap.R(11)}, @@ -6295,6 +6319,7 @@ func (s *snapmgrTestSuite) TestEnsureAliasesV2SnapDisabled(c *C) { } snapstate.Set(s.state, "core", nil) + snapstate.Set(s.state, "snapd", nil) snapstate.Set(s.state, "alias-snap", &snapstate.SnapState{ Sequence: snapstatetest.NewSequenceFromSnapSideInfos([]*snap.SideInfo{ {RealName: "alias-snap", Revision: snap.R(11)}, @@ -6822,6 +6847,9 @@ func (s *snapmgrTestSuite) TestSnapdSnapOnCoreWithoutBase(c *C) { r := release.MockOnClassic(false) defer r() + // remove snapd snap added for snapmgrBaseTest + snapstate.Set(s.state, "snapd", nil) + // it is now possible to install snapd snap on a system with core _, err := snapstate.Install(context.Background(), s.state, "snapd", &snapstate.RevisionOptions{Channel: "some-channel"}, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) @@ -6833,6 +6861,9 @@ func (s *snapmgrTestSuite) TestSnapdSnapOnSystemsWithoutBaseOnUbuntuCore(c *C) { 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) @@ -6847,6 +6878,9 @@ 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() @@ -6859,6 +6893,9 @@ func (s *snapmgrTestSuite) TestNoConfigureForSnapdSnap(c *C) { s.state.Lock() defer s.state.Unlock() + // remove snapd snap added for snapmgrBaseTest + snapstate.Set(s.state, "snapd", nil) + // snapd cannot be installed unless the model uses a base snap r := snapstatetest.MockDeviceModel(ModelWithBase("core18")) defer r() @@ -7772,8 +7809,10 @@ func (s *snapmgrTestSuite) TestInstallModeDisableFreshInstallEnabledByHook(c *C) var snapst snapstate.SnapState st.Lock() err := snapstate.Get(st, "services-snap", &snapst) + // Use Check here, Assert causes deadlock + c.Check(err, IsNil) st.Unlock() - c.Assert(err, IsNil) + snapst.ServicesEnabledByHooks = []string{"svcInstallModeDisable"} st.Lock() snapstate.Set(st, "services-snap", &snapst) @@ -8802,6 +8841,7 @@ func (s *snapmgrTestSuite) TestResolveValidationSetsEnforcementError(c *C) { c.Check(pinned, DeepEquals, pinnedSeqs) c.Check(snaps, testutil.DeepUnsortedMatches, []*snapasserts.InstalledSnap{ {SnapRef: naming.NewSnapRef("core", ""), Revision: snap.R(1)}, + {SnapRef: naming.NewSnapRef("snapd", ""), Revision: snap.R(1)}, {SnapRef: naming.NewSnapRef("some-other-snap", "some-other-snap-id"), Revision: snap.R(2)}, {SnapRef: naming.NewSnapRef("some-snap", "some-snap-id"), Revision: snap.R(1)}}) c.Check(snapsToIgnore, HasLen, 0)