summaryrefslogtreecommitdiff
diff options
-rw-r--r--overlord/managers_test.go275
-rw-r--r--overlord/snapstate/snapstate.go11
2 files changed, 266 insertions, 20 deletions
diff --git a/overlord/managers_test.go b/overlord/managers_test.go
index 2f2eae9686..2ceadf6a36 100644
--- a/overlord/managers_test.go
+++ b/overlord/managers_test.go
@@ -441,6 +441,48 @@ func (s *baseMgrsSuite) SetUpTest(c *C) {
s.logbuf = logbuf
}
+func (s *baseMgrsSuite) makeSerialAssertionInState(c *C, st *state.State, brandID, model, serialN string) *asserts.Serial {
+ encDevKey, err := asserts.EncodePublicKey(deviceKey.PublicKey())
+ c.Assert(err, IsNil)
+ serial, err := s.brands.Signing(brandID).Sign(asserts.SerialType, map[string]interface{}{
+ "brand-id": brandID,
+ "model": model,
+ "serial": serialN,
+ "device-key": string(encDevKey),
+ "device-key-sha3-384": deviceKey.PublicKey().ID(),
+ "timestamp": time.Now().Format(time.RFC3339),
+ }, nil, "")
+ c.Assert(err, IsNil)
+ err = assertstate.Add(st, serial)
+ c.Assert(err, IsNil)
+ return serial.(*asserts.Serial)
+}
+
+// XXX: We have some very similar code in hookstate/ctlcmd/is_connected_test.go
+// should this be moved to overlord/snapstate/snapstatetest as a common
+// helper
+func (ms *baseMgrsSuite) mockInstalledSnapWithFiles(c *C, snapYaml string, files [][]string) *snap.Info {
+ return ms.mockInstalledSnapWithRevAndFiles(c, snapYaml, snap.R(1), files)
+}
+
+func (ms *baseMgrsSuite) mockInstalledSnapWithRevAndFiles(c *C, snapYaml string, rev snap.Revision, files [][]string) *snap.Info {
+ st := ms.o.State()
+
+ info := snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(1)}, files)
+ si := &snap.SideInfo{
+ RealName: info.SnapName(),
+ SnapID: fakeSnapID(info.SnapName()),
+ Revision: info.Revision,
+ }
+ snapstate.Set(st, info.InstanceName(), &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{si},
+ Current: info.Revision,
+ SnapType: string(info.Type()),
+ })
+ return info
+}
+
type mgrsSuite struct {
baseMgrsSuite
}
@@ -4756,6 +4798,219 @@ version: 20.04`
})
}
+func (ms *mgrsSuite) TestRefreshSimpleSameRev(c *C) {
+ // the "some-snap" in rev1
+ snapYaml := "name: some-snap\nversion: 1.0"
+ revStr := "1"
+ // is available in the store
+ snapPath, _ := ms.makeStoreTestSnap(c, snapYaml, revStr)
+ ms.serveSnap(snapPath, revStr)
+
+ mockServer := ms.mockStore(c)
+ ms.AddCleanup(mockServer.Close)
+
+ st := ms.o.State()
+ st.Lock()
+ defer st.Unlock()
+
+ // and some-snap:rev1 is also installed
+ info := ms.mockInstalledSnapWithRevAndFiles(c, snapYaml, snap.R(revStr), nil)
+
+ // now refresh from rev1 to rev1
+ revOpts := &snapstate.RevisionOptions{Revision: snap.R(revStr)}
+ ts, err := snapstate.Update(st, "some-snap", revOpts, 0, snapstate.Flags{})
+ c.Assert(err, IsNil)
+
+ chg := st.NewChange("refresh", "...")
+ chg.AddAll(ts)
+
+ st.Unlock()
+ err = ms.o.Settle(settleTimeout)
+ st.Lock()
+ c.Assert(err, IsNil)
+ c.Check(chg.Err(), IsNil)
+ c.Check(chg.Status(), Equals, state.DoneStatus)
+
+ // the snap file is in the right place
+ c.Check(info.MountFile(), testutil.FilePresent)
+
+ // rev1 is installed
+ var snapst snapstate.SnapState
+ snapstate.Get(st, "some-snap", &snapst)
+ info, err = snapst.CurrentInfo()
+ c.Assert(err, IsNil)
+ c.Assert(info.Revision, Equals, snap.R(1))
+}
+
+func (ms *mgrsSuite) TestRefreshSimplePrevRev(c *C) {
+ // the "some-snap" in rev1
+ snapYaml := "name: some-snap\nversion: 1.0"
+ revStr := "1"
+ // is available in the store
+ snapPath, _ := ms.makeStoreTestSnap(c, snapYaml, revStr)
+ ms.serveSnap(snapPath, revStr)
+
+ mockServer := ms.mockStore(c)
+ ms.AddCleanup(mockServer.Close)
+
+ st := ms.o.State()
+ st.Lock()
+ defer st.Unlock()
+
+ // and some-snap at both rev1, rev2 are installed
+ info := snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(1)}, nil)
+ snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(2)}, nil)
+ si1 := &snap.SideInfo{
+ RealName: info.SnapName(),
+ SnapID: fakeSnapID(info.SnapName()),
+ Revision: snap.R(1),
+ }
+ si2 := &snap.SideInfo{
+ RealName: info.SnapName(),
+ SnapID: fakeSnapID(info.SnapName()),
+ Revision: snap.R(2),
+ }
+ snapstate.Set(st, info.InstanceName(), &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{si1, si2},
+ Current: snap.R(2),
+ SnapType: string(info.Type()),
+ })
+
+ // now refresh from rev2 to the local rev1
+ revOpts := &snapstate.RevisionOptions{Revision: snap.R(revStr)}
+ ts, err := snapstate.Update(st, "some-snap", revOpts, 0, snapstate.Flags{})
+ c.Assert(err, IsNil)
+
+ chg := st.NewChange("refresh", "...")
+ chg.AddAll(ts)
+
+ st.Unlock()
+ err = ms.o.Settle(settleTimeout)
+ st.Lock()
+ c.Assert(err, IsNil)
+ c.Check(chg.Err(), IsNil)
+ c.Check(chg.Status(), Equals, state.DoneStatus)
+
+ // the snap file is in the right place
+ c.Check(info.MountFile(), testutil.FilePresent)
+
+ var snapst snapstate.SnapState
+ snapstate.Get(st, "some-snap", &snapst)
+ info, err = snapst.CurrentInfo()
+ c.Assert(err, IsNil)
+ c.Assert(info.Revision, Equals, snap.R(1))
+}
+
+func (ms *mgrsSuite) TestRefreshSimpleSameRevFromLocalFile(c *C) {
+ // the "some-snap" in rev1
+ snapYaml := "name: some-snap\nversion: 1.0"
+ revStr := "1"
+
+ // pretend we got a temp snap file from e.g. the snapd daemon
+ tmpSnapFile := makeTestSnap(c, snapYaml)
+
+ st := ms.o.State()
+ st.Lock()
+ defer st.Unlock()
+
+ // and some-snap:rev1 is also installed
+ info := ms.mockInstalledSnapWithRevAndFiles(c, snapYaml, snap.R(revStr), nil)
+
+ // now refresh from rev1 to rev1
+ flags := snapstate.Flags{RemoveSnapPath: true}
+ ts, _, err := snapstate.InstallPath(st, &snap.SideInfo{RealName: "some-snap", Revision: snap.R(revStr)}, tmpSnapFile, "", "", flags)
+ c.Assert(err, IsNil)
+
+ chg := st.NewChange("refresh", "...")
+ chg.AddAll(ts)
+
+ st.Unlock()
+ err = ms.o.Settle(settleTimeout)
+ st.Lock()
+ c.Assert(err, IsNil)
+ c.Check(chg.Err(), IsNil)
+ c.Check(chg.Status(), Equals, state.DoneStatus)
+
+ // the temp file got cleaned up
+ snapsup, err := snapstate.TaskSnapSetup(chg.Tasks()[0])
+ c.Assert(err, IsNil)
+ c.Check(snapsup.Flags.RemoveSnapPath, Equals, true)
+ c.Check(snapsup.SnapPath, testutil.FileAbsent)
+
+ // the snap file is in the right place
+ c.Check(info.MountFile(), testutil.FilePresent)
+
+ var snapst snapstate.SnapState
+ snapstate.Get(st, "some-snap", &snapst)
+ info, err = snapst.CurrentInfo()
+ c.Assert(err, IsNil)
+ c.Assert(info.Revision, Equals, snap.R(1))
+}
+
+func (ms *mgrsSuite) TestRefreshSimpleRevertToLocalFromLocalFile(c *C) {
+ // the "some-snap" in rev1
+ snapYaml := "name: some-snap\nversion: 1.0"
+ revStr := "1"
+
+ // pretend we got a temp snap file from e.g. the snapd daemon
+ tmpSnapFile := makeTestSnap(c, snapYaml)
+
+ st := ms.o.State()
+ st.Lock()
+ defer st.Unlock()
+
+ // and some-snap at both rev1, rev2 are installed
+ info := snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(1)}, nil)
+ snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(2)}, nil)
+ si1 := &snap.SideInfo{
+ RealName: info.SnapName(),
+ SnapID: fakeSnapID(info.SnapName()),
+ Revision: snap.R(1),
+ }
+ si2 := &snap.SideInfo{
+ RealName: info.SnapName(),
+ SnapID: fakeSnapID(info.SnapName()),
+ Revision: snap.R(2),
+ }
+ snapstate.Set(st, info.InstanceName(), &snapstate.SnapState{
+ Active: true,
+ Sequence: []*snap.SideInfo{si1, si2},
+ Current: snap.R(2),
+ SnapType: string(info.Type()),
+ })
+
+ // now refresh from rev2 to rev1
+ flags := snapstate.Flags{RemoveSnapPath: true}
+ ts, _, err := snapstate.InstallPath(st, &snap.SideInfo{RealName: "some-snap", Revision: snap.R(revStr)}, tmpSnapFile, "", "", flags)
+ c.Assert(err, IsNil)
+
+ chg := st.NewChange("refresh", "...")
+ chg.AddAll(ts)
+
+ st.Unlock()
+ err = ms.o.Settle(settleTimeout)
+ st.Lock()
+ c.Assert(err, IsNil)
+ c.Check(chg.Err(), IsNil)
+ c.Check(chg.Status(), Equals, state.DoneStatus)
+
+ // the temp file got cleaned up
+ snapsup, err := snapstate.TaskSnapSetup(chg.Tasks()[0])
+ c.Assert(err, IsNil)
+ c.Check(snapsup.Flags.RemoveSnapPath, Equals, true)
+ c.Check(snapsup.SnapPath, testutil.FileAbsent)
+
+ // the snap file is in the right place
+ c.Check(info.MountFile(), testutil.FilePresent)
+
+ var snapst snapstate.SnapState
+ snapstate.Get(st, "some-snap", &snapst)
+ info, err = snapst.CurrentInfo()
+ c.Assert(err, IsNil)
+ c.Assert(info.Revision, Equals, snap.R(1))
+}
+
type kernelSuite struct {
baseMgrsSuite
@@ -7215,26 +7470,6 @@ func tsWithoutReRefresh(c *C, ts *state.TaskSet) *state.TaskSet {
return ts
}
-// XXX: We have some very similar code in hookstate/ctlcmd/is_connected_test.go
-// should this be moved to overlord/snapstate/snapstatetest as a common
-// helper
-func (ms *gadgetUpdatesSuite) mockInstalledSnapWithFiles(c *C, snapYaml string, files [][]string) {
- st := ms.o.State()
-
- info := snaptest.MockSnapWithFiles(c, snapYaml, &snap.SideInfo{Revision: snap.R(1)}, files)
- si := &snap.SideInfo{
- RealName: info.SnapName(),
- SnapID: fakeSnapID(info.SnapName()),
- Revision: info.Revision,
- }
- snapstate.Set(st, info.InstanceName(), &snapstate.SnapState{
- Active: true,
- Sequence: []*snap.SideInfo{si},
- Current: info.Revision,
- SnapType: string(info.Type()),
- })
-}
-
// mockSnapUpgradeWithFiles will put a "rev 2" of the given snapYaml/files
// into the mock snapstore
func (ms *gadgetUpdatesSuite) mockSnapUpgradeWithFiles(c *C, snapYaml string, files [][]string) {
diff --git a/overlord/snapstate/snapstate.go b/overlord/snapstate/snapstate.go
index 98e00a2478..677f73a138 100644
--- a/overlord/snapstate/snapstate.go
+++ b/overlord/snapstate/snapstate.go
@@ -312,6 +312,17 @@ func doInstall(st *state.State, snapst *SnapState, snapsup *SnapSetup, flags int
mount := st.NewTask("mount-snap", fmt.Sprintf(i18n.G("Mount snap %q%s"), snapsup.InstanceName(), revisionStr))
addTask(mount)
prev = mount
+ } else {
+ if snapsup.Flags.RemoveSnapPath {
+ // If the revision is local, we will not need the
+ // temporary snap. This can happen when
+ // e.g. side-loading a local revision again. The
+ // SnapPath is only needed in the "mount-snap" handler
+ // and that is skipped for local revisions.
+ if err := os.Remove(snapsup.SnapPath); err != nil {
+ return nil, err
+ }
+ }
}
// run refresh hooks when updating existing snap, otherwise run install hook further down.