summaryrefslogtreecommitdiff
diff options
authorJohn R. Lenton <chipaca@users.noreply.github.com>2019-06-07 12:15:01 +0100
committerGitHub <noreply@github.com>2019-06-07 12:15:01 +0100
commit9d4e5903d00c24fb7a08aa7c0081e4b88af7fbfe (patch)
tree478e680a04c64f8c34760d9a25ff36b7162fc1cf
parent605e2e77e1f0299906f5af34dac394a4c2ca1215 (diff)
parent4d1911d4ecb40840e39ce655ea6fea8879e6d2c1 (diff)
Merge pull request #6961 from chipaca/so-long-install-cohort
overlord/snapstate, & fallout: give Install a *RevisionOptions
-rw-r--r--daemon/api.go5
-rw-r--r--daemon/api_test.go28
-rw-r--r--overlord/devicestate/devicestate.go2
-rw-r--r--overlord/devicestate/devicestate_test.go8
-rw-r--r--overlord/devicestate/export_test.go3
-rw-r--r--overlord/hookstate/ctlcmd/services_test.go2
-rw-r--r--overlord/managers_test.go22
-rw-r--r--overlord/snapstate/handlers.go5
-rw-r--r--overlord/snapstate/snapstate.go39
-rw-r--r--overlord/snapstate/snapstate_test.go160
-rw-r--r--overlord/snapstate/storehelpers.go19
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)