diff options
| author | John R. Lenton <chipaca@users.noreply.github.com> | 2019-06-07 12:15:01 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-07 12:15:01 +0100 |
| commit | 9d4e5903d00c24fb7a08aa7c0081e4b88af7fbfe (patch) | |
| tree | 478e680a04c64f8c34760d9a25ff36b7162fc1cf | |
| parent | 605e2e77e1f0299906f5af34dac394a4c2ca1215 (diff) | |
| parent | 4d1911d4ecb40840e39ce655ea6fea8879e6d2c1 (diff) | |
Merge pull request #6961 from chipaca/so-long-install-cohort
overlord/snapstate, & fallout: give Install a *RevisionOptions
| -rw-r--r-- | daemon/api.go | 5 | ||||
| -rw-r--r-- | daemon/api_test.go | 28 | ||||
| -rw-r--r-- | overlord/devicestate/devicestate.go | 2 | ||||
| -rw-r--r-- | overlord/devicestate/devicestate_test.go | 8 | ||||
| -rw-r--r-- | overlord/devicestate/export_test.go | 3 | ||||
| -rw-r--r-- | overlord/hookstate/ctlcmd/services_test.go | 2 | ||||
| -rw-r--r-- | overlord/managers_test.go | 22 | ||||
| -rw-r--r-- | overlord/snapstate/handlers.go | 5 | ||||
| -rw-r--r-- | overlord/snapstate/snapstate.go | 39 | ||||
| -rw-r--r-- | overlord/snapstate/snapstate_test.go | 160 | ||||
| -rw-r--r-- | overlord/snapstate/storehelpers.go | 19 |
11 files changed, 158 insertions, 135 deletions
diff --git a/daemon/api.go b/daemon/api.go index f719577532..16d126343a 100644 --- a/daemon/api.go +++ b/daemon/api.go @@ -784,7 +784,6 @@ type snapInstructionResult struct { var ( snapstateInstall = snapstate.Install snapstateInstallPath = snapstate.InstallPath - snapstateInstallCohort = snapstate.InstallCohort snapstateRefreshCandidates = snapstate.RefreshCandidates snapstateTryPath = snapstate.TryPath snapstateUpdate = snapstate.Update @@ -933,16 +932,14 @@ func snapInstall(inst *snapInstruction, st *state.State) (string, []*state.TaskS return "", nil, err } - var tset *state.TaskSet var ckey string if inst.CohortKey == "" { logger.Noticef("Installing snap %q revision %s", inst.Snaps[0], inst.Revision) - tset, err = snapstateInstall(st, inst.Snaps[0], inst.Channel, inst.Revision, inst.userID, flags) } else { ckey = strutil.ElliptRight(inst.CohortKey, 10) logger.Noticef("Installing snap %q from cohort %q", inst.Snaps[0], ckey) - tset, err = snapstateInstallCohort(st, inst.Snaps[0], inst.Channel, inst.CohortKey, inst.userID, flags) } + tset, err := snapstateInstall(st, inst.Snaps[0], inst.revnoOpts(), inst.userID, flags) if err != nil { return "", nil, err } diff --git a/daemon/api_test.go b/daemon/api_test.go index 1e275d422b..3811cd9bcb 100644 --- a/daemon/api_test.go +++ b/daemon/api_test.go @@ -294,7 +294,6 @@ func (s *apiBaseSuite) SetUpTest(c *check.C) { assertstateRefreshSnapDeclarations = nil snapstateInstall = nil - snapstateInstallCohort = nil snapstateInstallMany = nil snapstateInstallPath = nil snapstateRefreshCandidates = nil @@ -319,7 +318,6 @@ func (s *apiBaseSuite) TearDownTest(c *check.C) { assertstateRefreshSnapDeclarations = assertstate.RefreshSnapDeclarations snapstateInstall = snapstate.Install - snapstateInstallCohort = snapstate.InstallCohort snapstateInstallMany = snapstate.InstallMany snapstateInstallPath = snapstate.InstallPath snapstateRefreshCandidates = snapstate.RefreshCandidates @@ -2656,7 +2654,7 @@ func (s *apiSuite) sideloadCheck(c *check.C, content string, head map[string]str return &snap.Info{SuggestedName: mockedName}, nil } - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { // NOTE: ubuntu-core is not installed in developer mode c.Check(flags, check.Equals, snapstate.Flags{}) installQueue = append(installQueue, name) @@ -3042,7 +3040,7 @@ func (s *apiSuite) TestTrySnap(c *check.C) { return state.NewTaskSet(t), nil } - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { if name != "core" { c.Check(flags, check.DeepEquals, t.flags, check.Commentf(t.desc)) } @@ -3528,10 +3526,10 @@ func (s *apiSuite) testInstall(c *check.C, forcedDevmode bool, flags snapstate.F restore := release.MockForcedDevmode(forcedDevmode) defer restore() - snapstateInstall = func(s *state.State, name, channel string, revno snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledFlags = flags installQueue = append(installQueue, name) - c.Check(revision, check.Equals, revno) + c.Check(revision, check.Equals, opts.Revision) t := s.NewTask("fake-install-snap", "Doing a fake install") return state.NewTaskSet(t), nil @@ -3986,7 +3984,7 @@ func (s *apiSuite) TestRemoveMany(c *check.C) { } func (s *apiSuite) TestInstallFails(c *check.C) { - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { t := s.NewTask("fake-install-snap-error", "Install task") return state.NewTaskSet(t), nil } @@ -4020,7 +4018,7 @@ func (s *apiSuite) TestInstallLeaveOld(c *check.C) { c.Skip("temporarily dropped half-baked support while sorting out flag mess") var calledFlags snapstate.Flags - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledFlags = flags t := s.NewTask("fake-install-snap", "Doing a fake install") @@ -4046,7 +4044,7 @@ func (s *apiSuite) TestInstallLeaveOld(c *check.C) { func (s *apiSuite) TestInstall(c *check.C) { var calledName string - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledName = name t := s.NewTask("fake-install-snap", "Doing a fake install") @@ -4073,9 +4071,9 @@ func (s *apiSuite) TestInstallCohort(c *check.C) { var calledName string var calledCohort string - snapstateInstallCohort = func(s *state.State, name, channel string, cohort string, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledName = name - calledCohort = cohort + calledCohort = opts.CohortKey t := s.NewTask("fake-install-snap", "Doing a fake install") return state.NewTaskSet(t), nil @@ -4101,7 +4099,7 @@ func (s *apiSuite) TestInstallCohort(c *check.C) { func (s *apiSuite) TestInstallDevMode(c *check.C) { var calledFlags snapstate.Flags - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledFlags = flags t := s.NewTask("fake-install-snap", "Doing a fake install") @@ -4128,7 +4126,7 @@ func (s *apiSuite) TestInstallDevMode(c *check.C) { func (s *apiSuite) TestInstallJailMode(c *check.C) { var calledFlags snapstate.Flags - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledFlags = flags t := s.NewTask("fake-install-snap", "Doing a fake install") @@ -4170,7 +4168,7 @@ func (s *apiSuite) TestInstallJailModeDevModeOS(c *check.C) { } func (s *apiSuite) TestInstallEmptyName(c *check.C) { - snapstateInstall = func(_ *state.State, _, _ string, _ snap.Revision, _ int, _ snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(_ *state.State, _ string, _ *snapstate.RevisionOptions, _ int, _ snapstate.Flags) (*state.TaskSet, error) { return nil, errors.New("should not be called") } d := s.daemon(c) @@ -6264,7 +6262,7 @@ func (s *apiSuite) TestAliases(c *check.C) { func (s *apiSuite) TestInstallUnaliased(c *check.C) { var calledFlags snapstate.Flags - snapstateInstall = func(s *state.State, name, channel string, revision snap.Revision, userID int, flags snapstate.Flags) (*state.TaskSet, error) { + snapstateInstall = func(s *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags) (*state.TaskSet, error) { calledFlags = flags t := s.NewTask("fake-install-snap", "Doing a fake install") diff --git a/overlord/devicestate/devicestate.go b/overlord/devicestate/devicestate.go index 8e12101473..a232002cff 100644 --- a/overlord/devicestate/devicestate.go +++ b/overlord/devicestate/devicestate.go @@ -350,7 +350,7 @@ func remodelTasks(st *state.State, current, new *asserts.Model, deviceCtx snapst _, err := snapstate.CurrentInfo(st, snapName) // If the snap is not installed we need to install it now. if _, ok := err.(*snap.NotInstalledError); ok { - ts, err := snapstateInstallWithDeviceContext(st, snapName, "", "", snap.R(0), userID, snapstate.Flags{Required: true}, deviceCtx) + ts, err := snapstateInstallWithDeviceContext(st, snapName, nil, userID, snapstate.Flags{Required: true}, deviceCtx) if err != nil { return nil, err } diff --git a/overlord/devicestate/devicestate_test.go b/overlord/devicestate/devicestate_test.go index 0500978ef2..8276a79fad 100644 --- a/overlord/devicestate/devicestate_test.go +++ b/overlord/devicestate/devicestate_test.go @@ -2512,7 +2512,7 @@ func (s *deviceMgrSuite) TestRemodelTasksSmoke(c *C) { var testDeviceCtx snapstate.DeviceContext - restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { + restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { c.Check(flags.Required, Equals, true) c.Check(deviceCtx, Equals, testDeviceCtx) @@ -2566,7 +2566,7 @@ func (s *deviceMgrSuite) TestRemodelRequiredSnaps(c *C) { s.state.Set("seeded", true) s.state.Set("refresh-privacy-key", "some-privacy-key") - restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { + restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { c.Check(flags.Required, Equals, true) c.Check(deviceCtx, NotNil) @@ -2674,7 +2674,7 @@ func (s *deviceMgrSuite) TestRemodelSwitchKernelTrack(c *C) { s.state.Set("seeded", true) s.state.Set("refresh-privacy-key", "some-privacy-key") - restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { + restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { c.Check(flags.Required, Equals, true) c.Check(deviceCtx, NotNil) c.Check(deviceCtx.ForRemodeling(), Equals, true) @@ -2833,7 +2833,7 @@ func (s *deviceMgrSuite) TestRemodelStoreSwitch(c *C) { var testStore snapstate.StoreService - restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { + restore := devicestate.MockSnapstateInstallWithDeviceContext(func(st *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error) { c.Check(flags.Required, Equals, true) c.Check(deviceCtx, NotNil) c.Check(deviceCtx.ForRemodeling(), Equals, true) diff --git a/overlord/devicestate/export_test.go b/overlord/devicestate/export_test.go index bf90c9ad3a..1cc6d42382 100644 --- a/overlord/devicestate/export_test.go +++ b/overlord/devicestate/export_test.go @@ -27,7 +27,6 @@ import ( "github.com/snapcore/snapd/overlord/snapstate" "github.com/snapcore/snapd/overlord/state" "github.com/snapcore/snapd/overlord/storecontext" - "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/timings" ) @@ -91,7 +90,7 @@ func MockRepeatRequestSerial(label string) (restore func()) { } } -func MockSnapstateInstallWithDeviceContext(f func(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error)) (restore func()) { +func MockSnapstateInstallWithDeviceContext(f func(st *state.State, name string, opts *snapstate.RevisionOptions, userID int, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) (*state.TaskSet, error)) (restore func()) { old := snapstateInstallWithDeviceContext snapstateInstallWithDeviceContext = f return func() { diff --git a/overlord/hookstate/ctlcmd/services_test.go b/overlord/hookstate/ctlcmd/services_test.go index b9fa088926..71763f9d1d 100644 --- a/overlord/hookstate/ctlcmd/services_test.go +++ b/overlord/hookstate/ctlcmd/services_test.go @@ -404,7 +404,7 @@ func (s *servicectlSuite) TestQueuedCommandsSingleLane(c *C) { s.st.Lock() chg := s.st.NewChange("install change", "install change") - ts, err := snapstate.Install(s.st, "one", "", snap.R(1), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.st, "one", &snapstate.RevisionOptions{Revision: snap.R(1)}, 0, snapstate.Flags{}) c.Assert(err, IsNil) c.Assert(ts.Tasks(), HasLen, 13) chg.AddAll(ts) diff --git a/overlord/managers_test.go b/overlord/managers_test.go index ea0dceb114..0aba66fe45 100644 --- a/overlord/managers_test.go +++ b/overlord/managers_test.go @@ -795,7 +795,7 @@ apps: st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -896,7 +896,7 @@ func (s *mgrsSuite) TestHappyRemoteInstallAndUpdateWithEpochBump(c *C) { st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -977,7 +977,7 @@ func (s *mgrsSuite) testHappyRemoteInstallAndUpdateWithMaybeEpochBump(c *C, doBu st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -1407,7 +1407,7 @@ version: @VERSION@ st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -1896,7 +1896,7 @@ apps: st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -1956,7 +1956,7 @@ apps: st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -2062,7 +2062,7 @@ apps: st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{Unaliased: true}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{Unaliased: true}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -2175,7 +2175,7 @@ apps: st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -2189,7 +2189,7 @@ apps: c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("install-snap change failed with: %v", chg.Err())) - ts, err = snapstate.Install(st, "bar", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err = snapstate.Install(st, "bar", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg = st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -2322,7 +2322,7 @@ version: 1.0 st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) @@ -2363,7 +2363,7 @@ version: 1.0 st.Lock() defer st.Unlock() - ts, err := snapstate.Install(st, "foo", "stable", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(st, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) diff --git a/overlord/snapstate/handlers.go b/overlord/snapstate/handlers.go index 38bb11b077..efbad36e58 100644 --- a/overlord/snapstate/handlers.go +++ b/overlord/snapstate/handlers.go @@ -253,7 +253,7 @@ func (m *SnapManager) installOneBaseOrRequired(st *state.State, snapName, channe } // not installed, nor queued for install -> install it - ts, err := Install(st, snapName, channel, snap.R(0), userID, Flags{}) + ts, err := Install(st, snapName, &RevisionOptions{Channel: channel}, userID, Flags{}) // something might have triggered an explicit install while // the state was unlocked -> deal with that here by simply // retrying the operation. @@ -464,7 +464,8 @@ func (m *SnapManager) undoPrepareSnap(t *state.Task, _ *tomb.Tomb) error { func installInfoUnlocked(st *state.State, snapsup *SnapSetup, deviceCtx DeviceContext) (*snap.Info, error) { st.Lock() defer st.Unlock() - return installInfo(st, snapsup.InstanceName(), snapsup.Channel, snapsup.CohortKey, snapsup.Revision(), snapsup.UserID, deviceCtx) + opts := &RevisionOptions{Channel: snapsup.Channel, CohortKey: snapsup.CohortKey, Revision: snapsup.Revision()} + return installInfo(st, snapsup.InstanceName(), opts, snapsup.UserID, deviceCtx) } // autoRefreshRateLimited returns the rate limit of auto-refreshes or 0 if diff --git a/overlord/snapstate/snapstate.go b/overlord/snapstate/snapstate.go index 5ea6f44c80..1cb91b7e7a 100644 --- a/overlord/snapstate/snapstate.go +++ b/overlord/snapstate/snapstate.go @@ -658,22 +658,8 @@ func TryPath(st *state.State, name, path string, flags Flags) (*state.TaskSet, e // Note that the state must be locked by the caller. // // The returned TaskSet will contain a DownloadAndChecksDoneEdge. -func Install(st *state.State, name, channel string, revision snap.Revision, userID int, flags Flags) (*state.TaskSet, error) { - return installGeneric(st, name, channel, "", revision, userID, flags) -} - -// InstallCohort is like Install but instead of a revision, it takes a cohort key. -func InstallCohort(st *state.State, name, channel, cohortKey string, userID int, flags Flags) (*state.TaskSet, error) { - return installGeneric(st, name, channel, cohortKey, snap.Revision{}, userID, flags) -} - -// TODO: refactor things so there's a single Install again that takes a struct, maybe a bit more like doInstall but public-er. -func installGeneric(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags Flags) (*state.TaskSet, error) { - if cohort != "" && !revision.Unset() { - return nil, errors.New("cannot specify revision and cohort") - } - - return InstallWithDeviceContext(st, name, channel, cohort, revision, userID, flags, nil) +func Install(st *state.State, name string, opts *RevisionOptions, userID int, flags Flags) (*state.TaskSet, error) { + return InstallWithDeviceContext(st, name, opts, userID, flags, nil) } // InstallWithDeviceContext returns a set of tasks for installing a snap. @@ -681,9 +667,16 @@ func installGeneric(st *state.State, name, channel, cohort string, revision snap // Note that the state must be locked by the caller. // // The returned TaskSet will contain a DownloadAndChecksDoneEdge. -func InstallWithDeviceContext(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, flags Flags, deviceCtx DeviceContext) (*state.TaskSet, error) { - if channel == "" { - channel = "stable" +func InstallWithDeviceContext(st *state.State, name string, opts *RevisionOptions, userID int, flags Flags, deviceCtx DeviceContext) (*state.TaskSet, error) { + if opts == nil { + opts = &RevisionOptions{} + } + if opts.CohortKey != "" && !opts.Revision.Unset() { + return nil, errors.New("cannot specify revision and cohort") + } + + if opts.Channel == "" { + opts.Channel = "stable" } var snapst SnapState @@ -705,7 +698,7 @@ func InstallWithDeviceContext(st *state.State, name, channel, cohort string, rev return nil, fmt.Errorf("invalid instance name: %v", err) } - info, err := installInfo(st, name, channel, cohort, revision, userID, deviceCtx) + info, err := installInfo(st, name, opts, userID, deviceCtx) if err != nil { return nil, err } @@ -720,7 +713,7 @@ func InstallWithDeviceContext(st *state.State, name, channel, cohort string, rev } snapsup := &SnapSetup{ - Channel: channel, + Channel: opts.Channel, Base: info.Base, Prereq: defaultContentPlugProviders(st, info), UserID: userID, @@ -733,7 +726,7 @@ func InstallWithDeviceContext(st *state.State, name, channel, cohort string, rev auxStoreInfo: auxStoreInfo{ Media: info.Media, }, - CohortKey: cohort, + CohortKey: opts.CohortKey, } return doInstall(st, &snapst, snapsup, 0, "") @@ -2056,7 +2049,7 @@ func TransitionCore(st *state.State, oldName, newName string) ([]*state.TaskSet, } if !newSnapst.IsInstalled() { var userID int - newInfo, err := installInfo(st, newName, oldSnapst.Channel, "", snap.R(0), userID, nil) + newInfo, err := installInfo(st, newName, &RevisionOptions{Channel: oldSnapst.Channel}, userID, nil) if err != nil { return nil, err } diff --git a/overlord/snapstate/snapstate_test.go b/overlord/snapstate/snapstate_test.go index 7071f6996f..c7b9f5849d 100644 --- a/overlord/snapstate/snapstate_test.go +++ b/overlord/snapstate/snapstate_test.go @@ -547,15 +547,17 @@ func (s *snapmgrTestSuite) TestInstallDevModeConfinementFiltering(c *C) { defer s.state.Unlock() // if a snap is devmode, you can't install it without --devmode - _, err := snapstate.Install(s.state, "some-snap", "channel-for-devmode", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-devmode"} + _, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, ErrorMatches, `.* requires devmode or confinement override`) // if a snap is devmode, you *can* install it with --devmode - _, err = snapstate.Install(s.state, "some-snap", "channel-for-devmode", snap.R(0), s.user.ID, snapstate.Flags{DevMode: true}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{DevMode: true}) c.Assert(err, IsNil) // if a snap is *not* devmode, you can still install it with --devmode - _, err = snapstate.Install(s.state, "some-snap", "channel-for-strict", snap.R(0), s.user.ID, snapstate.Flags{DevMode: true}) + opts.Channel = "channel-for-strict" + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{DevMode: true}) c.Assert(err, IsNil) } @@ -582,15 +584,17 @@ func (s *snapmgrTestSuite) TestInstallClassicConfinementFiltering(c *C) { defer s.state.Unlock() // if a snap is classic, you can't install it without --classic - _, err := snapstate.Install(s.state, "some-snap", "channel-for-classic", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-classic"} + _, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, ErrorMatches, `.* requires classic confinement`) // if a snap is classic, you *can* install it with --classic - _, err = snapstate.Install(s.state, "some-snap", "channel-for-classic", snap.R(0), s.user.ID, snapstate.Flags{Classic: true}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{Classic: true}) c.Assert(err, IsNil) // if a snap is *not* classic, but can install it with --classic which gets ignored - _, err = snapstate.Install(s.state, "some-snap", "channel-for-strict", snap.R(0), s.user.ID, snapstate.Flags{Classic: true}) + opts.Channel = "channel-for-strict" + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{Classic: true}) c.Assert(err, IsNil) } @@ -606,7 +610,8 @@ func (s *snapmgrTestSuite) TestInstallFailsWhenClassicSnapsAreNotSupported(c *C) // this needs doing because dirs depends on the release info dirs.SetRootDir(dirs.GlobalRootDir) - _, err := snapstate.Install(s.state, "some-snap", "channel-for-classic", snap.R(0), s.user.ID, snapstate.Flags{Classic: true}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-classic"} + _, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{Classic: true}) c.Assert(err, ErrorMatches, "classic confinement requires snaps under /snap or symlink from /snap to "+dirs.SnapMountDir) } @@ -614,7 +619,8 @@ func (s *snapmgrTestSuite) TestInstallTasks(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, 0, snapstate.Flags{}) c.Assert(err, IsNil) verifyInstallTasks(c, 0, 0, ts, s.state) @@ -625,7 +631,8 @@ func (s *snapmgrTestSuite) TestInstallCohortTasks(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.InstallCohort(s.state, "some-snap", "some-channel", "what", 0, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", CohortKey: "what"} + ts, err := snapstate.Install(s.state, "some-snap", opts, 0, snapstate.Flags{}) c.Assert(err, IsNil) snapsup, err := snapstate.TaskSnapSetup(ts.Tasks()[0]) c.Assert(err, IsNil) @@ -645,7 +652,8 @@ func (s *snapmgrTestSuite) TestInstallWithDeviceContext(c *C) { deviceCtx := &snapstatetest.TrivialDeviceContext{CtxStore: s.fakeStore} - ts, err := snapstate.InstallWithDeviceContext(s.state, "some-snap", "some-channel", "", snap.R(0), 0, snapstate.Flags{}, deviceCtx) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.InstallWithDeviceContext(s.state, "some-snap", opts, 0, snapstate.Flags{}, deviceCtx) c.Assert(err, IsNil) verifyInstallTasks(c, 0, 0, ts, s.state) @@ -1804,7 +1812,7 @@ func (s *snapmgrTestSuite) TestDoInstallWithSlots(c *C) { snapstate.ReplaceStore(s.state, contentStore{fakeStore: s.fakeStore, state: s.state}) - ts, err := snapstate.Install(s.state, "snap-content-slot", "", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "snap-content-slot", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) var snapsup snapstate.SnapSetup @@ -1863,7 +1871,7 @@ func (s *snapmgrTestSuite) TestDoInstallChannelDefault(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) var snapsup snapstate.SnapSetup @@ -1877,7 +1885,8 @@ func (s *snapmgrTestSuite) TestInstallRevision(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "", snap.R(7), 0, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Revision: snap.R(7)} + ts, err := snapstate.Install(s.state, "some-snap", opts, 0, snapstate.Flags{}) c.Assert(err, IsNil) var snapsup snapstate.SnapSetup @@ -1893,7 +1902,7 @@ func (s *snapmgrTestSuite) TestInstallTooEarly(c *C) { s.state.Set("seeded", nil) - _, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{}) c.Assert(err, ErrorMatches, `too early for operation, device not yet seeded or device model not acknowledged`) } @@ -1902,12 +1911,12 @@ func (s *snapmgrTestSuite) TestInstallConflict(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) // need a change to make the tasks visible s.state.NewChange("install", "...").AddAll(ts) - _, err = snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{}) c.Assert(err, ErrorMatches, `snap "some-snap" has "install" change in progress`) } @@ -1928,7 +1937,7 @@ func (s *snapmgrTestSuite) TestInstallAliasConflict(c *C) { SnapType: "app", }) - _, err := snapstate.Install(s.state, "foo", "some-channel", snap.R(0), 0, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "foo", nil, 0, snapstate.Flags{}) c.Assert(err, ErrorMatches, `snap "foo" command namespace conflicts with alias "foo\.bar" for "otherfoosnap" snap`) } @@ -1939,7 +1948,8 @@ func (s *snapmgrTestSuite) TestInstallStrictIgnoresClassic(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "channel-for-strict", snap.R(0), s.user.ID, snapstate.Flags{Classic: true}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-strict"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{Classic: true}) c.Assert(err, IsNil) c.Assert(err, IsNil) @@ -1988,7 +1998,7 @@ func (s *snapmgrTestSuite) TestInstallStateConflict(c *C) { snapstate.ReplaceStore(s.state, sneakyStore{fakeStore: s.fakeStore, state: s.state}) - _, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{}) c.Assert(err, ErrorMatches, `snap "some-snap" has changes in progress`) } @@ -2011,7 +2021,7 @@ func (s *snapmgrTestSuite) TestInstallPathConflict(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "some-snap", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) // need a change to make the tasks visible s.state.NewChange("install", "...").AddAll(ts) @@ -2096,19 +2106,19 @@ func (s *snapmgrTestSuite) TestParallelInstanceInstallNotAllowed(c *C) { tr.Set("core", "experimental.parallel-instances", true) tr.Commit() - _, err := snapstate.Install(s.state, "core_foo", "", snap.R(0), 0, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "core_foo", nil, 0, snapstate.Flags{}) c.Check(err, ErrorMatches, `cannot install snap of type os as "core_foo"`) - _, err = snapstate.Install(s.state, "some-base_foo", "", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-base_foo", nil, 0, snapstate.Flags{}) c.Check(err, ErrorMatches, `cannot install snap of type base as "some-base_foo"`) - _, err = snapstate.Install(s.state, "some-gadget_foo", "", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-gadget_foo", nil, 0, snapstate.Flags{}) c.Check(err, ErrorMatches, `cannot install snap of type gadget as "some-gadget_foo"`) - _, err = snapstate.Install(s.state, "some-kernel_foo", "", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-kernel_foo", nil, 0, snapstate.Flags{}) c.Check(err, ErrorMatches, `cannot install snap of type kernel as "some-kernel_foo"`) - _, err = snapstate.Install(s.state, "some-snapd_foo", "", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snapd_foo", nil, 0, snapstate.Flags{}) c.Check(err, ErrorMatches, `cannot install snap of type snapd as "some-snapd_foo"`) } @@ -2623,7 +2633,8 @@ func (s *snapmgrTestSuite) TestInstallRunThrough(c *C) { c.Check(snapstate.AuxStoreInfoFilename("some-snap-id"), testutil.FileAbsent) chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -2793,7 +2804,8 @@ func (s *snapmgrTestSuite) TestParallelInstanceInstallRunThrough(c *C) { tr.Commit() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap_instance", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap_instance", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -2968,7 +2980,8 @@ func (s *snapmgrTestSuite) TestInstallUndoRunThroughJustOneSnap(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -3116,7 +3129,8 @@ func (s *snapmgrTestSuite) TestInstallWithCohortRunThrough(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.InstallCohort(s.state, "some-snap", "some-channel", "scurries", s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", CohortKey: "scurries"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -3281,7 +3295,8 @@ func (s *snapmgrTestSuite) TestInstallWithRevisionRunThrough(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -3440,7 +3455,8 @@ func (s *snapmgrTestSuite) TestInstallStartOrder(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "services-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "services-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -3470,7 +3486,8 @@ func (s *snapmgrTestSuite) TestInstalling(c *C) { c.Check(snapstate.Installing(s.state), Equals, false) chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(42), 0, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "some-snap", opts, 0, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -9288,7 +9305,8 @@ func (s *snapmgrTestSuite) TestUndoMountSnapFailsInCopyData(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -9485,7 +9503,8 @@ func (s *snapmgrTestSuite) TestAbortCausesNoErrReport(c *C) { defer s.state.Unlock() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) s.fakeBackend.linkSnapWaitCh = make(chan int) @@ -9522,7 +9541,8 @@ func (s *snapmgrTestSuite) TestErrreportDisable(c *C) { defer restore() chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) s.fakeBackend.linkSnapFailTrigger = filepath.Join(dirs.SnapMountDir, "some-snap/11") @@ -12438,13 +12458,14 @@ func (s *snapmgrTestSuite) TestTransitionCoreBlocksOtherChanges(c *C) { chg.SetStatus(state.DoStatus) // other tasks block until the transition is done - _, err := snapstate.Install(s.state, "some-snap", "stable", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "stable"} + _, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{}) c.Check(err, ErrorMatches, "ubuntu-core to core transition in progress, no other changes allowed until this is done") // and when the transition is done, other tasks run chg.SetStatus(state.DoneStatus) - ts, err := snapstate.Install(s.state, "some-snap", "stable", snap.R(0), s.user.ID, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Check(err, IsNil) c.Check(ts, NotNil) } @@ -12760,7 +12781,8 @@ func (s *snapmgrTestSuite) TestInstallWithoutCoreRunThrough1(c *C) { snapstate.Set(s.state, "core", nil) chg := s.state.NewChange("install", "install a snap on a system without core") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -12981,12 +13003,14 @@ func (s *snapmgrTestSuite) TestInstallWithoutCoreTwoSnapsRunThrough(c *C) { snapstate.Set(s.state, "core", nil) chg1 := s.state.NewChange("install", "install snap 1") - ts1, err := snapstate.Install(s.state, "snap1", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts1, err := snapstate.Install(s.state, "snap1", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg1.AddAll(ts1) chg2 := s.state.NewChange("install", "install snap 2") - ts2, err := snapstate.Install(s.state, "snap2", "some-other-channel", snap.R(21), s.user.ID, snapstate.Flags{}) + opts = &snapstate.RevisionOptions{Channel: "some-other-channel", Revision: snap.R(21)} + ts2, err := snapstate.Install(s.state, "snap2", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg2.AddAll(ts2) @@ -13042,7 +13066,8 @@ func (s *snapmgrTestSuite) TestInstallWithoutCoreTwoSnapsWithFailureRunThrough(c // chg1 has an error chg1 := s.state.NewChange("install", "install snap 1") - ts1, err := snapstate.Install(s.state, "snap1", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts1, err := snapstate.Install(s.state, "snap1", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg1.AddAll(ts1) @@ -13054,7 +13079,8 @@ func (s *snapmgrTestSuite) TestInstallWithoutCoreTwoSnapsWithFailureRunThrough(c // chg2 is good chg2 := s.state.NewChange("install", "install snap 2") - ts2, err := snapstate.Install(s.state, "snap2", "some-other-channel", snap.R(21), s.user.ID, snapstate.Flags{}) + opts = &snapstate.RevisionOptions{Channel: "some-other-channel", Revision: snap.R(21)} + ts2, err := snapstate.Install(s.state, "snap2", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg2.AddAll(ts2) @@ -13162,7 +13188,8 @@ func (s *snapmgrTestSuite) TestInstallWithoutCoreConflictingInstall(c *C) { // now install a snap that will pull in core chg := s.state.NewChange("install", "install a snap on a system without core") - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -13334,7 +13361,8 @@ func (s *snapmgrTestSuite) TestInstallDefaultProviderRunThrough(c *C) { ifacerepo.Replace(s.state, repo) chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "snap-content-plug", "stable", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "stable", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "snap-content-plug", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -13497,7 +13525,8 @@ func (s *snapmgrTestSuite) TestInstallDefaultProviderCircular(c *C) { ifacerepo.Replace(s.state, repo) chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "snap-content-circular1", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "snap-content-circular1", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -13530,7 +13559,8 @@ func (s *snapmgrTestSuite) TestInstallDefaultProviderCompat(c *C) { ifacerepo.Replace(s.state, repo) chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "snap-content-plug-compat", "some-channel", snap.R(42), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel", Revision: snap.R(42)} + ts, err := snapstate.Install(s.state, "snap-content-plug-compat", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -13612,7 +13642,8 @@ func (s *snapmgrTestSuite) TestSnapManagerRefreshSchedule(c *C) { func (s *snapmgrTestSuite) TestSideInfoPaid(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "channel-for-paid", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-paid"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg := s.state.NewChange("install", "install paid snap") @@ -13634,7 +13665,8 @@ func (s *snapmgrTestSuite) TestSideInfoPaid(c *C) { func (s *snapmgrTestSuite) TestSideInfoPrivate(c *C) { s.state.Lock() defer s.state.Unlock() - ts, err := snapstate.Install(s.state, "some-snap", "channel-for-private", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-private"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg := s.state.NewChange("install", "install private snap") @@ -13747,35 +13779,36 @@ func (s *snapmgrTestSuite) TestInstallLayoutsChecksFeatureFlag(c *C) { defer s.state.Unlock() // Layouts are now enabled by default. - _, err := snapstate.Install(s.state, "some-snap", "channel-for-layout", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "channel-for-layout"} + _, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) // Layouts can be explicitly disabled. tr := config.NewTransaction(s.state) tr.Set("core", "experimental.layouts", false) tr.Commit() - _, err = snapstate.Install(s.state, "some-snap", "channel-for-layout", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, ErrorMatches, "experimental feature disabled - test it by setting 'experimental.layouts' to true") // Layouts can be explicitly enabled. tr = config.NewTransaction(s.state) tr.Set("core", "experimental.layouts", true) tr.Commit() - _, err = snapstate.Install(s.state, "some-snap", "channel-for-layout", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) // The default empty value now means "enabled". tr = config.NewTransaction(s.state) tr.Set("core", "experimental.layouts", "") tr.Commit() - _, err = snapstate.Install(s.state, "some-snap", "channel-for-layout", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) // Layouts are enabled when the controlling flag is reset to nil. tr = config.NewTransaction(s.state) tr.Set("core", "experimental.layouts", nil) tr.Commit() - _, err = snapstate.Install(s.state, "some-snap", "channel-for-layout", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) } @@ -14044,12 +14077,13 @@ func (s *snapmgrTestSuite) TestNoConfigureForBasesTask(c *C) { defer s.state.Unlock() // normal snaps get a configure task - ts, err := snapstate.Install(s.state, "some-snap", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + opts := &snapstate.RevisionOptions{Channel: "some-channel"} + ts, err := snapstate.Install(s.state, "some-snap", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) c.Check(hasConfigureTask(ts), Equals, true) // but bases do not for install - ts, err = snapstate.Install(s.state, "some-base", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + ts, err = snapstate.Install(s.state, "some-base", opts, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) c.Check(hasConfigureTask(ts), Equals, false) @@ -14074,7 +14108,7 @@ func (s *snapmgrTestSuite) TestNoSnapdSnapOnSystemsWithoutBaseOnUbuntuCore(c *C) defer s.state.Unlock() // but snapd do not for install - _, err := snapstate.Install(s.state, "snapd", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "snapd", nil, s.user.ID, snapstate.Flags{}) c.Assert(err, ErrorMatches, "cannot install snapd snap on a model without a base snap yet") } @@ -14086,7 +14120,7 @@ func (s *snapmgrTestSuite) TestNoSnapdSnapOnSystemsWithoutBaseButOption(c *C) { tr.Set("core", "experimental.snapd-snap", true) tr.Commit() - _, err := snapstate.Install(s.state, "snapd", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "snapd", nil, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) } @@ -14099,7 +14133,7 @@ func (s *snapmgrTestSuite) TestNoConfigureForSnapdSnap(c *C) { defer r() // but snapd do not for install - ts, err := snapstate.Install(s.state, "snapd", "some-channel", snap.R(0), s.user.ID, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "snapd", nil, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) c.Check(hasConfigureTask(ts), Equals, false) @@ -14240,13 +14274,13 @@ func (s *snapmgrTestSuite) TestRequestSalt(c *C) { // clear request-salt to have it generated s.state.Set("refresh-privacy-key", nil) - _, err := snapstate.Install(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{}) c.Assert(err, ErrorMatches, "internal error: request salt is unset") s.state.Set("refresh-privacy-key", "privacy-key") chg := s.state.NewChange("install", "install a snap") - ts, err := snapstate.Install(s.state, "some-snap", "", snap.R(0), s.user.ID, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "some-snap", nil, s.user.ID, snapstate.Flags{}) c.Assert(err, IsNil) chg.AddAll(ts) @@ -14401,10 +14435,10 @@ func (s *snapmgrTestSuite) TestInstallValidatesInstanceNames(c *C) { s.state.Lock() defer s.state.Unlock() - _, err := snapstate.Install(s.state, "foo--invalid", "", snap.R(0), 0, snapstate.Flags{}) + _, err := snapstate.Install(s.state, "foo--invalid", nil, 0, snapstate.Flags{}) c.Assert(err, ErrorMatches, `invalid instance name: invalid snap name: "foo--invalid"`) - _, err = snapstate.Install(s.state, "foo_123_456", "", snap.R(0), 0, snapstate.Flags{}) + _, err = snapstate.Install(s.state, "foo_123_456", nil, 0, snapstate.Flags{}) c.Assert(err, ErrorMatches, `invalid instance name: invalid instance key: "123_456"`) _, _, err = snapstate.InstallMany(s.state, []string{"foo--invalid"}, 0) @@ -14430,7 +14464,7 @@ func (s *snapmgrTestSuite) TestGadgetUpdateTaskAddedOnInstall(c *C) { defer s.state.Unlock() // task added on install - ts, err := snapstate.Install(s.state, "brand-gadget", "", snap.R(0), 0, snapstate.Flags{}) + ts, err := snapstate.Install(s.state, "brand-gadget", nil, 0, snapstate.Flags{}) c.Assert(err, IsNil) c.Assert(s.state.TaskCount(), Equals, len(ts.Tasks())) diff --git a/overlord/snapstate/storehelpers.go b/overlord/snapstate/storehelpers.go index 03f98e9ca3..0859a388ce 100644 --- a/overlord/snapstate/storehelpers.go +++ b/overlord/snapstate/storehelpers.go @@ -82,7 +82,7 @@ func refreshOptions(st *state.State, origOpts *store.RefreshOptions) (*store.Ref return &opts, nil } -func installInfo(st *state.State, name, channel, cohort string, revision snap.Revision, userID int, deviceCtx DeviceContext) (*snap.Info, error) { +func installInfo(st *state.State, name string, revOpts *RevisionOptions, userID int, deviceCtx DeviceContext) (*snap.Info, error) { // TODO: support ignore-validation? curSnaps, err := currentSnaps(st) @@ -95,11 +95,6 @@ func installInfo(st *state.State, name, channel, cohort string, revision snap.Re return nil, err } - // cannot specify both with the API - if !revision.Unset() { - channel = "" - } - opts, err := refreshOptions(st, nil) if err != nil { return nil, err @@ -108,11 +103,17 @@ func installInfo(st *state.State, name, channel, cohort string, revision snap.Re action := &store.SnapAction{ Action: "install", InstanceName: name, + } + + // cannot specify both with the API + if revOpts.Revision.Unset() { // the desired channel - Channel: channel, + action.Channel = revOpts.Channel + // the desired cohort key + action.CohortKey = revOpts.CohortKey + } else { // the desired revision - Revision: revision, - CohortKey: cohort, + action.Revision = revOpts.Revision } theStore := Store(st, deviceCtx) |
