func (bs *bootedSuite) TestUpdateBootRevisionsKernelSimple(c *C) { st := bs.state st.Lock() defer st.Unlock() bs.makeInstalledKernelOS(c, st) bs.bootloader.BootVars["snap_kernel"] = "canonical-pc-linux_1.snap" err := snapstate.UpdateBootRevisions(st) c.Assert(err, IsNil) st.Unlock() bs.settle() st.Lock() c.Assert(st.Changes(), HasLen, 1) chg := st.Changes()[0] c.Assert(chg.Err(), IsNil) c.Assert(chg.Kind(), Equals, "update-revisions") c.Assert(chg.IsReady(), Equals, true) // canonical-pc-linux "current" got reverted but core did not var snapst snapstate.SnapState err = snapstate.Get(st, "canonical-pc-linux", &snapst) c.Assert(err, IsNil) c.Assert(snapst.Current, Equals, snap.R(1)) c.Assert(snapst.Active, Equals, true) err = snapstate.Get(st, "core", &snapst) c.Assert(err, IsNil) c.Assert(snapst.Current, Equals, snap.R(2)) c.Assert(snapst.Active, Equals, true) }
func (s *patch2Suite) TestPatch2(c *C) { restorer := patch.MockLevel(2) defer restorer() r, err := os.Open(dirs.SnapStateFile) c.Assert(err, IsNil) defer r.Close() st, err := state.ReadState(nil, r) c.Assert(err, IsNil) // go from patch level 1 -> 2 err = patch.Apply(st) c.Assert(err, IsNil) st.Lock() defer st.Unlock() // our mocks are correct c.Assert(st.Changes(), HasLen, 2) c.Assert(st.Tasks(), HasLen, 2) var snapsup snapstate.SnapSetup // transition of: // - SnapSetup.{Name,Revision} -> SnapSetup.SideInfo.{RealName,Revision} t := st.Task("1") err = t.Get("snap-setup", &snapsup) c.Assert(err, IsNil) c.Assert(snapsup.SideInfo, DeepEquals, &snap.SideInfo{ RealName: "foo", Revision: snap.R("x3"), }) // transition of: // - SnapState.Sequence is backfilled with "RealName" (if missing) var snapst snapstate.SnapState err = snapstate.Get(st, "foo", &snapst) c.Assert(err, IsNil) c.Check(snapst.Sequence[0].RealName, Equals, "foo") c.Check(snapst.Sequence[1].RealName, Equals, "foo") // transition of: // - Candidate for "bar" -> tasks SnapSetup.SideInfo t = st.Task("2") err = t.Get("snap-setup", &snapsup) c.Assert(err, IsNil) c.Assert(snapsup.SideInfo, DeepEquals, &snap.SideInfo{ RealName: "bar", Revision: snap.R("x1"), }) // FIXME: bar is now empty and should no longer be there? err = snapstate.Get(st, "bar", &snapst) c.Assert(err, IsNil) }
func (s *linkSnapSuite) TestDoLinkSnapSuccess(c *C) { s.state.Lock() t := s.state.NewTask("link-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ RealName: "foo", Revision: snap.R(33), }, Channel: "beta", }) s.state.NewChange("dummy", "...").AddTask(t) s.state.Unlock() s.snapmgr.Ensure() s.snapmgr.Wait() s.state.Lock() defer s.state.Unlock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, IsNil) typ, err := snapst.Type() c.Check(err, IsNil) c.Check(typ, Equals, snap.TypeApp) c.Check(snapst.Active, Equals, true) c.Check(snapst.Sequence, HasLen, 1) c.Check(snapst.Current, Equals, snap.R(33)) c.Check(snapst.Channel, Equals, "beta") c.Check(t.Status(), Equals, state.DoneStatus) c.Check(s.stateBackend.restartRequested, Equals, false) }
func (m *InterfaceManager) undoSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapName := ss.Name() // Get the name from SnapSetup and use it to find the current SideInfo // about the snap, if there is one. var snapst snapstate.SnapState err = snapstate.Get(st, snapName, &snapst) if err != nil && err != state.ErrNoState { return err } sideInfo := snapst.CurrentSideInfo() if sideInfo == nil { // The snap was not installed before so undo should remove security profiles. return m.removeProfilesForSnap(task, tomb, snapName) } else { // The snap was installed before so undo should setup the old security profiles. snapInfo, err := snap.ReadInfo(snapName, sideInfo) if err != nil { return err } return m.setupProfilesForSnap(task, tomb, snapInfo, snapst.DevMode) } }
func (s *linkSnapSuite) TestDoUndoLinkSnap(c *C) { s.state.Lock() defer s.state.Unlock() si := &snap.SideInfo{ RealName: "foo", Revision: snap.R(33), } t := s.state.NewTask("link-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: si, Channel: "beta", }) chg := s.state.NewChange("dummy", "...") chg.AddTask(t) terr := s.state.NewTask("error-trigger", "provoking total undo") terr.WaitFor(t) chg.AddTask(terr) s.state.Unlock() for i := 0; i < 3; i++ { s.snapmgr.Ensure() s.snapmgr.Wait() } s.state.Lock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, Equals, state.ErrNoState) c.Check(t.Status(), Equals, state.UndoneStatus) }
func (m *InterfaceManager) setupAffectedSnaps(task *state.Task, affectingSnap string, affectedSnaps []string) error { st := task.State() // Setup security of the affected snaps. for _, affectedSnapName := range affectedSnaps { // the snap that triggered the change needs to be skipped if affectedSnapName == affectingSnap { continue } var snapst snapstate.SnapState if err := snapstate.Get(st, affectedSnapName, &snapst); err != nil { return err } affectedSnapInfo, err := snapst.CurrentInfo() if err != nil { return err } snap.AddImplicitSlots(affectedSnapInfo) opts := confinementOptions(snapst.Flags) if err := setupSnapSecurity(task, affectedSnapInfo, opts, m.repo); err != nil { return err } } return nil }
func (m *InterfaceManager) doDisconnect(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() plugRef, slotRef, err := getPlugAndSlotRefs(task) if err != nil { return err } conns, err := getConns(st) if err != nil { return err } var affectedConns []interfaces.ConnRef if plugRef.Snap != "" && plugRef.Name != "" && slotRef.Snap != "" && slotRef.Name != "" { if err := m.repo.Disconnect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name); err != nil { return err } affectedConns = []interfaces.ConnRef{{plugRef, slotRef}} } else if plugRef.Name != "" && slotRef.Snap == "" && slotRef.Name == "" { // NOTE: plugRef.Snap can be either empty or not, Connected handles both affectedConns, err = m.repo.Connected(plugRef.Snap, plugRef.Name) if err != nil { return err } m.repo.DisconnectAll(affectedConns) } else if plugRef.Snap == "" && plugRef.Name == "" && slotRef.Name != "" { // Symmetrically, slotRef.Snap can be either empty or not affectedConns, err = m.repo.Connected(slotRef.Snap, slotRef.Name) if err != nil { return err } m.repo.DisconnectAll(affectedConns) } else { return fmt.Errorf("internal error, unhandled disconnect case plug: %q, slot: %q", plugRef, slotRef) } affectedSnaps := snapNamesFromConns(affectedConns) for _, snapName := range affectedSnaps { var snapst snapstate.SnapState if err := snapstate.Get(st, snapName, &snapst); err != nil { return err } snapInfo, err := snapst.CurrentInfo() if err != nil { return err } opts := confinementOptions(snapst.Flags) if err := setupSnapSecurity(task, snapInfo, opts, m.repo); err != nil { return &state.Retry{} } } for _, conn := range affectedConns { delete(conns, conn.ID()) } setConns(st, conns) return nil }
func (s *discardSnapSuite) TestDoDiscardSnapToEmpty(c *C) { s.state.Lock() snapstate.Set(s.state, "foo", &snapstate.SnapState{ Sequence: []*snap.SideInfo{ {RealName: "foo", Revision: snap.R(3)}, }, Current: snap.R(3), SnapType: "app", }) t := s.state.NewTask("discard-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ RealName: "foo", Revision: snap.R(33), }, }) s.state.NewChange("dummy", "...").AddTask(t) s.state.Unlock() s.snapmgr.Ensure() s.snapmgr.Wait() s.state.Lock() defer s.state.Unlock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, Equals, state.ErrNoState) }
func (ms *mgrsSuite) installLocalTestSnap(c *C, snapYamlContent string) *snap.Info { st := ms.o.State() snapPath := makeTestSnap(c, snapYamlContent) snapf, err := snap.Open(snapPath) c.Assert(err, IsNil) info, err := snap.ReadInfoFromSnapFile(snapf, nil) c.Assert(err, IsNil) // store current state snapName := info.Name() var snapst snapstate.SnapState snapstate.Get(st, snapName, &snapst) ts, err := snapstate.InstallPath(st, &snap.SideInfo{RealName: snapName}, snapPath, "", snapstate.Flags{DevMode: true}) c.Assert(err, IsNil) chg := st.NewChange("install-snap", "...") chg.AddAll(ts) st.Unlock() err = ms.o.Settle() st.Lock() c.Assert(err, IsNil) c.Assert(chg.Err(), IsNil) c.Assert(chg.Status(), Equals, state.DoneStatus, Commentf("install-snap change failed with: %v", chg.Err())) return info }
func (m *InterfaceManager) doConnect(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() plugRef, slotRef, err := getPlugAndSlotRefs(task) if err != nil { return err } conns, err := getConns(st) if err != nil { return err } err = m.repo.Connect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name) if err != nil { return err } plug := m.repo.Plug(plugRef.Snap, plugRef.Name) var plugSnapst snapstate.SnapState if err := snapstate.Get(st, plugRef.Snap, &plugSnapst); err != nil { return err } slot := m.repo.Slot(slotRef.Snap, slotRef.Name) var slotSnapst snapstate.SnapState if err := snapstate.Get(st, slotRef.Snap, &slotSnapst); err != nil { return err } if err := setupSnapSecurity(task, plug.Snap, plugSnapst.DevModeAllowed(), m.repo); err != nil { return err } if err := setupSnapSecurity(task, slot.Snap, slotSnapst.DevModeAllowed(), m.repo); err != nil { return err } conns[connID(plugRef, slotRef)] = connState{Interface: plug.Interface} setConns(st, conns) return nil }
func (bs *bootedSuite) TestUpdateRevisionsKernelSimple(c *C) { st := bs.overlord.State() bs.makeInstalledKernelOS(c, st) bs.bootloader.BootVars["snap_kernel"] = "canonical-pc-linux_1.snap" err := boot.UpdateRevisions(bs.overlord) c.Assert(err, IsNil) st.Lock() defer st.Unlock() // canonical-pc-linux "current" got reverted but ubuntu-core did not var snapst snapstate.SnapState err = snapstate.Get(st, "canonical-pc-linux", &snapst) c.Assert(err, IsNil) c.Assert(snapst.Current, Equals, snap.R(1)) c.Assert(snapst.Active, Equals, true) err = snapstate.Get(st, "ubuntu-core", &snapst) c.Assert(err, IsNil) c.Assert(snapst.Current, Equals, snap.R(2)) c.Assert(snapst.Active, Equals, true) }
func (s *interfaceManagerSuite) mockUpdatedSnap(c *C, yamlText string, revision int) *snap.Info { sideInfo := &snap.SideInfo{Revision: snap.R(revision)} snapInfo := snaptest.MockSnap(c, yamlText, "", sideInfo) sideInfo.RealName = snapInfo.Name() s.state.Lock() defer s.state.Unlock() // Put the new revision (stored in SideInfo) into the state var snapst snapstate.SnapState err := snapstate.Get(s.state, snapInfo.Name(), &snapst) c.Assert(err, IsNil) snapst.Sequence = append(snapst.Sequence, sideInfo) snapstate.Set(s.state, snapInfo.Name(), &snapst) return snapInfo }
func (s *patch1Suite) TestPatch1(c *C) { restore := patch.MockReadInfo(s.readInfo) defer restore() r, err := os.Open(dirs.SnapStateFile) c.Assert(err, IsNil) defer r.Close() st, err := state.ReadState(nil, r) c.Assert(err, IsNil) // go from patch-level 0 to patch-level 1 restorer := patch.MockLevel(1) defer restorer() err = patch.Apply(st) c.Assert(err, IsNil) st.Lock() defer st.Unlock() expected := []struct { name string typ snap.Type cur snap.Revision }{ {"foo", snap.TypeApp, snap.R(22)}, {"core", snap.TypeOS, snap.R(111)}, {"borken", snap.TypeApp, snap.R(-2)}, {"wip", "", snap.R(0)}, } for _, exp := range expected { var snapst snapstate.SnapState err := snapstate.Get(st, exp.name, &snapst) c.Assert(err, IsNil) c.Check(snap.Type(snapst.SnapType), Equals, exp.typ) c.Check(snapst.Current, Equals, exp.cur) } // ensure we only moved forward to patch-level 1 var patchLevel int err = st.Get("patch-level", &patchLevel) c.Assert(err, IsNil) c.Assert(patchLevel, Equals, 1) }
func hookSetup(task *state.Task) (*HookSetup, *snapstate.SnapState, error) { var hooksup HookSetup err := task.Get("hook-setup", &hooksup) if err != nil { return nil, nil, fmt.Errorf("cannot extract hook setup from task: %s", err) } var snapst snapstate.SnapState err = snapstate.Get(task.State(), hooksup.Snap, &snapst) if err == state.ErrNoState { return nil, nil, fmt.Errorf("cannot find %q snap", hooksup.Snap) } if err != nil { return nil, nil, fmt.Errorf("cannot handle %q snap: %v", hooksup.Snap, err) } return &hooksup, &snapst, nil }
func (s *linkSnapSuite) TestDoLinkSnapTryToCleanupOnError(c *C) { s.state.Lock() defer s.state.Unlock() si := &snap.SideInfo{ RealName: "foo", Revision: snap.R(35), } t := s.state.NewTask("link-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: si, Channel: "beta", }) s.fakeBackend.linkSnapFailTrigger = "/snap/foo/35" s.state.NewChange("dummy", "...").AddTask(t) s.state.Unlock() s.snapmgr.Ensure() s.snapmgr.Wait() s.state.Lock() // state as expected var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, Equals, state.ErrNoState) // tried to cleanup c.Check(s.fakeBackend.ops, DeepEquals, fakeOps{ { op: "candidate", sinfo: *si, }, { op: "link-snap.failed", name: "/snap/foo/35", }, { op: "unlink-snap", name: "/snap/foo/35", }, }) }
func (s *linkSnapSuite) TestDoUndoLinkSnapSequenceHadCandidate(c *C) { s.state.Lock() defer s.state.Unlock() si1 := &snap.SideInfo{ RealName: "foo", Revision: snap.R(1), } si2 := &snap.SideInfo{ RealName: "foo", Revision: snap.R(2), } snapstate.Set(s.state, "foo", &snapstate.SnapState{ Sequence: []*snap.SideInfo{si1, si2}, Current: si2.Revision, }) t := s.state.NewTask("link-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: si1, Channel: "beta", }) chg := s.state.NewChange("dummy", "...") chg.AddTask(t) terr := s.state.NewTask("error-trigger", "provoking total undo") terr.WaitFor(t) chg.AddTask(terr) s.state.Unlock() for i := 0; i < 3; i++ { s.snapmgr.Ensure() s.snapmgr.Wait() } s.state.Lock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, IsNil) c.Check(snapst.Active, Equals, false) c.Check(snapst.Sequence, HasLen, 2) c.Check(snapst.Current, Equals, snap.R(2)) c.Check(t.Status(), Equals, state.UndoneStatus) }
// localSnapInfo returns the information about the current snap for the given name plus the SnapState with the active flag and other snap revisions. func localSnapInfo(st *state.State, name string) (*snap.Info, *snapstate.SnapState, error) { st.Lock() defer st.Unlock() var snapst snapstate.SnapState err := snapstate.Get(st, name, &snapst) if err != nil && err != state.ErrNoState { return nil, nil, fmt.Errorf("cannot consult state: %v", err) } info, err := snapst.CurrentInfo() if err == snapstate.ErrNoCurrent { return nil, nil, errNoSnap } if err != nil { return nil, nil, fmt.Errorf("cannot read snap details: %v", err) } return info, &snapst, nil }
func (m *InterfaceManager) doDiscardConns(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() snapSetup, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapName := snapSetup.Name() var snapState snapstate.SnapState err = snapstate.Get(st, snapName, &snapState) if err != nil && err != state.ErrNoState { return err } if err == nil && len(snapState.Sequence) != 0 { return fmt.Errorf("cannot discard connections for snap %q while it is present", snapName) } conns, err := getConns(st) if err != nil { return err } removed := make(map[string]connState) for id := range conns { plugRef, slotRef, err := parseConnID(id) if err != nil { return err } if plugRef.Snap == snapName || slotRef.Snap == snapName { removed[id] = conns[id] delete(conns, id) } } task.Set("removed", removed) setConns(st, conns) return nil }
func (s *downloadSnapSuite) TestDoUndoDownloadSnap(c *C) { s.state.Lock() si := &snap.SideInfo{ RealName: "foo", Revision: snap.R(33), } t := s.state.NewTask("download-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: si, DownloadInfo: &snap.DownloadInfo{ DownloadURL: "http://something.com/snap", }, }) chg := s.state.NewChange("dummy", "...") chg.AddTask(t) terr := s.state.NewTask("error-trigger", "provoking total undo") terr.WaitFor(t) chg.AddTask(terr) s.state.Unlock() for i := 0; i < 3; i++ { s.snapmgr.Ensure() s.snapmgr.Wait() } s.state.Lock() defer s.state.Unlock() // task was undone c.Check(t.Status(), Equals, state.UndoneStatus) // and nothing is in the state for "foo" var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, Equals, state.ErrNoState) }
func (s *discardSnapSuite) TestDoDiscardSnapNoErrorsForActive(c *C) { s.state.Lock() snapstate.Set(s.state, "foo", &snapstate.SnapState{ Sequence: []*snap.SideInfo{ {RealName: "foo", Revision: snap.R(3)}, {RealName: "foo", Revision: snap.R(33)}, }, Current: snap.R(33), Active: true, SnapType: "app", }) t := s.state.NewTask("discard-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ RealName: "foo", Revision: snap.R(3), }, }) chg := s.state.NewChange("dummy", "...") chg.AddTask(t) s.state.Unlock() s.snapmgr.Ensure() s.snapmgr.Wait() s.state.Lock() defer s.state.Unlock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "foo", &snapst) c.Assert(err, IsNil) c.Assert(chg.Err(), IsNil) c.Check(snapst.Sequence, HasLen, 1) c.Check(snapst.Current, Equals, snap.R(33)) c.Check(t.Status(), Equals, state.DoneStatus) }
func (s *linkSnapSuite) TestDoLinkSnapSuccessCoreRestarts(c *C) { restore := release.MockOnClassic(true) defer restore() s.state.Lock() si := &snap.SideInfo{ RealName: "core", Revision: snap.R(33), } t := s.state.NewTask("link-snap", "test") t.Set("snap-setup", &snapstate.SnapSetup{ SideInfo: si, }) s.state.NewChange("dummy", "...").AddTask(t) s.state.Unlock() s.snapmgr.Ensure() s.snapmgr.Wait() s.state.Lock() defer s.state.Unlock() var snapst snapstate.SnapState err := snapstate.Get(s.state, "core", &snapst) c.Assert(err, IsNil) typ, err := snapst.Type() c.Check(err, IsNil) c.Check(typ, Equals, snap.TypeOS) c.Check(t.Status(), Equals, state.DoneStatus) c.Check(s.stateBackend.restartRequested, Equals, true) c.Check(t.Log(), HasLen, 1) c.Check(t.Log()[0], Matches, `.*INFO Requested daemon restart\.`) }
func (m *InterfaceManager) doConnect(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() plugRef, slotRef, err := getPlugAndSlotRefs(task) if err != nil { return err } conns, err := getConns(st) if err != nil { return err } connRef, err := m.repo.ResolveConnect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name) if err != nil { return err } plug := m.repo.Plug(connRef.PlugRef.Snap, connRef.PlugRef.Name) if plug == nil { return fmt.Errorf("snap %q has no %q plug", connRef.PlugRef.Snap, connRef.PlugRef.Name) } var plugDecl *asserts.SnapDeclaration if plug.Snap.SnapID != "" { var err error plugDecl, err = assertstate.SnapDeclaration(st, plug.Snap.SnapID) if err != nil { return fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap.Name(), err) } } slot := m.repo.Slot(connRef.SlotRef.Snap, connRef.SlotRef.Name) if slot == nil { return fmt.Errorf("snap %q has no %q slot", connRef.SlotRef.Snap, connRef.SlotRef.Name) } var slotDecl *asserts.SnapDeclaration if slot.Snap.SnapID != "" { var err error slotDecl, err = assertstate.SnapDeclaration(st, slot.Snap.SnapID) if err != nil { return fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap.Name(), err) } } baseDecl, err := assertstate.BaseDeclaration(st) if err != nil { return fmt.Errorf("internal error: cannot find base declaration: %v", err) } // check the connection against the declarations' rules ic := policy.ConnectCandidate{ Plug: plug.PlugInfo, PlugSnapDeclaration: plugDecl, Slot: slot.SlotInfo, SlotSnapDeclaration: slotDecl, BaseDeclaration: baseDecl, } // if either of plug or slot snaps don't have a declaration it // means they were installed with "dangerous", so the security // check should be skipped at this point. if plugDecl != nil && slotDecl != nil { err = ic.Check() if err != nil { return err } } err = m.repo.Connect(connRef) if err != nil { return err } var plugSnapst snapstate.SnapState if err := snapstate.Get(st, connRef.PlugRef.Snap, &plugSnapst); err != nil { return err } var slotSnapst snapstate.SnapState if err := snapstate.Get(st, connRef.SlotRef.Snap, &slotSnapst); err != nil { return err } slotOpts := confinementOptions(slotSnapst.Flags) if err := setupSnapSecurity(task, slot.Snap, slotOpts, m.repo); err != nil { return err } plugOpts := confinementOptions(plugSnapst.Flags) if err := setupSnapSecurity(task, plug.Snap, plugOpts, m.repo); err != nil { return err } conns[connRef.ID()] = connState{Interface: plug.Interface} setConns(st, conns) return nil }
func (s *FirstBootTestSuite) TestPopulateFromSeedHappy(c *C) { // put a firstboot snap into the SnapBlobDir snapYaml := `name: foo version: 1.0` mockSnapFile := snaptest.MakeTestSnapWithFiles(c, snapYaml, nil) targetSnapFile := filepath.Join(dirs.SnapSeedDir, "snaps", filepath.Base(mockSnapFile)) err := os.Rename(mockSnapFile, targetSnapFile) c.Assert(err, IsNil) // put a firstboot local snap into the SnapBlobDir snapYaml = `name: local version: 1.0` mockSnapFile = snaptest.MakeTestSnapWithFiles(c, snapYaml, nil) targetSnapFile2 := filepath.Join(dirs.SnapSeedDir, "snaps", filepath.Base(mockSnapFile)) err = os.Rename(mockSnapFile, targetSnapFile2) c.Assert(err, IsNil) devAcct := assertstest.NewAccount(s.storeSigning, "developer", map[string]interface{}{ "account-id": "developerid", }, "") devAcctFn := filepath.Join(dirs.SnapSeedDir, "assertions", "developer.account") err = ioutil.WriteFile(devAcctFn, asserts.Encode(devAcct), 0644) c.Assert(err, IsNil) snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{ "series": "16", "snap-id": "snapidsnapid", "publisher-id": "developerid", "snap-name": "foo", "timestamp": time.Now().UTC().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) declFn := filepath.Join(dirs.SnapSeedDir, "assertions", "foo.snap-declaration") err = ioutil.WriteFile(declFn, asserts.Encode(snapDecl), 0644) c.Assert(err, IsNil) sha3_384, size, err := asserts.SnapFileSHA3_384(targetSnapFile) c.Assert(err, IsNil) snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{ "snap-sha3-384": sha3_384, "snap-size": fmt.Sprintf("%d", size), "snap-id": "snapidsnapid", "developer-id": "developerid", "snap-revision": "128", "timestamp": time.Now().UTC().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) revFn := filepath.Join(dirs.SnapSeedDir, "assertions", "foo.snap-revision") err = ioutil.WriteFile(revFn, asserts.Encode(snapRev), 0644) c.Assert(err, IsNil) // add a model assertion and its chain assertsChain := s.makeModelAssertionChain(c) for i, as := range assertsChain { fn := filepath.Join(dirs.SnapSeedDir, "assertions", strconv.Itoa(i)) err := ioutil.WriteFile(fn, asserts.Encode(as), 0644) c.Assert(err, IsNil) } // create a seed.yaml content := []byte(fmt.Sprintf(` snaps: - name: foo file: %s devmode: true - name: local unasserted: true file: %s `, filepath.Base(targetSnapFile), filepath.Base(targetSnapFile2))) err = ioutil.WriteFile(filepath.Join(dirs.SnapSeedDir, "seed.yaml"), content, 0644) c.Assert(err, IsNil) // run the firstboot stuff st := s.overlord.State() st.Lock() defer st.Unlock() tsAll, err := devicestate.PopulateStateFromSeedImpl(st) c.Assert(err, IsNil) // the last task of the last taskset must be mark-seeded markSeededTask := tsAll[len(tsAll)-1].Tasks()[0] c.Check(markSeededTask.Kind(), Equals, "mark-seeded") // and the markSeededTask must wait for the other tasks prevTasks := tsAll[len(tsAll)-2].Tasks() otherTask := prevTasks[len(prevTasks)-1] c.Check(markSeededTask.WaitTasks(), testutil.Contains, otherTask) // now run the change and check the result chg := st.NewChange("run-it", "run the populate from seed changes") for _, ts := range tsAll { chg.AddAll(ts) } c.Assert(st.Changes(), HasLen, 1) st.Unlock() s.overlord.Settle() st.Lock() c.Assert(chg.Err(), IsNil) // and check the snap got correctly installed c.Check(osutil.FileExists(filepath.Join(dirs.SnapMountDir, "foo", "128", "meta", "snap.yaml")), Equals, true) c.Check(osutil.FileExists(filepath.Join(dirs.SnapMountDir, "local", "x1", "meta", "snap.yaml")), Equals, true) // verify r, err := os.Open(dirs.SnapStateFile) c.Assert(err, IsNil) state, err := state.ReadState(nil, r) c.Assert(err, IsNil) state.Lock() defer state.Unlock() // check foo info, err := snapstate.CurrentInfo(state, "foo") c.Assert(err, IsNil) c.Assert(info.SnapID, Equals, "snapidsnapid") c.Assert(info.Revision, Equals, snap.R(128)) c.Assert(info.DeveloperID, Equals, "developerid") var snapst snapstate.SnapState err = snapstate.Get(state, "foo", &snapst) c.Assert(err, IsNil) c.Assert(snapst.DevMode, Equals, true) // check local info, err = snapstate.CurrentInfo(state, "local") c.Assert(err, IsNil) c.Assert(info.SnapID, Equals, "") c.Assert(info.Revision, Equals, snap.R("x1")) c.Assert(info.DeveloperID, Equals, "") // and ensure state is now considered seeded var seeded bool err = state.Get("seeded", &seeded) c.Assert(err, IsNil) c.Check(seeded, Equals, true) }
func (m *InterfaceManager) doConnect(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() plugRef, slotRef, err := getPlugAndSlotRefs(task) if err != nil { return err } conns, err := getConns(st) if err != nil { return err } connRef, err := m.repo.ResolveConnect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name) if err != nil { return err } plug := m.repo.Plug(connRef.PlugRef.Snap, connRef.PlugRef.Name) if plug == nil { return fmt.Errorf("snap %q has no %q plug", connRef.PlugRef.Snap, connRef.PlugRef.Name) } var plugDecl *asserts.SnapDeclaration if plug.Snap.SnapID != "" { var err error plugDecl, err = assertstate.SnapDeclaration(st, plug.Snap.SnapID) if err != nil { return fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap.Name(), err) } } slot := m.repo.Slot(connRef.SlotRef.Snap, connRef.SlotRef.Name) if slot == nil { return fmt.Errorf("snap %q has no %q slot", connRef.SlotRef.Snap, connRef.SlotRef.Name) } var slotDecl *asserts.SnapDeclaration if slot.Snap.SnapID != "" { var err error slotDecl, err = assertstate.SnapDeclaration(st, slot.Snap.SnapID) if err != nil { return fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap.Name(), err) } } baseDecl, err := assertstate.BaseDeclaration(st) if err != nil { return fmt.Errorf("internal error: cannot find base declaration: %v", err) } // check the connection against the declarations' rules ic := policy.ConnectCandidate{ Plug: plug.PlugInfo, PlugSnapDeclaration: plugDecl, Slot: slot.SlotInfo, SlotSnapDeclaration: slotDecl, BaseDeclaration: baseDecl, } err = ic.Check() if err != nil { return err } err = m.repo.Connect(connRef) if err != nil { return err } var plugSnapst snapstate.SnapState if err := snapstate.Get(st, connRef.PlugRef.Snap, &plugSnapst); err != nil { return err } var slotSnapst snapstate.SnapState if err := snapstate.Get(st, connRef.SlotRef.Snap, &slotSnapst); err != nil { return err } if err := setupSnapSecurity(task, slot.Snap, slotSnapst.DevModeAllowed(), m.repo); err != nil { return err } if err := setupSnapSecurity(task, plug.Snap, plugSnapst.DevModeAllowed(), m.repo); err != nil { return err } conns[connRef.ID()] = connState{Interface: plug.Interface} setConns(st, conns) return nil }
func (s *FirstBootTestSuite) TestPopulateFromSeedHappy(c *C) { // put a firstboot snap into the SnapBlobDir snapYaml := `name: foo version: 1.0` mockSnapFile := snaptest.MakeTestSnapWithFiles(c, snapYaml, nil) targetSnapFile := filepath.Join(dirs.SnapSeedDir, "snaps", filepath.Base(mockSnapFile)) err := os.Rename(mockSnapFile, targetSnapFile) c.Assert(err, IsNil) // put a firstboot local snap into the SnapBlobDir snapYaml = `name: local version: 1.0` mockSnapFile = snaptest.MakeTestSnapWithFiles(c, snapYaml, nil) targetSnapFile2 := filepath.Join(dirs.SnapSeedDir, "snaps", filepath.Base(mockSnapFile)) err = os.Rename(mockSnapFile, targetSnapFile2) c.Assert(err, IsNil) devAcct := assertstest.NewAccount(s.storeSigning, "developer", map[string]interface{}{ "account-id": "developerid", }, "") devAcctFn := filepath.Join(dirs.SnapSeedDir, "assertions", "developer.account") err = ioutil.WriteFile(devAcctFn, asserts.Encode(devAcct), 0644) c.Assert(err, IsNil) snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{ "series": "16", "snap-id": "snapidsnapid", "publisher-id": "developerid", "snap-name": "foo", "timestamp": time.Now().UTC().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) declFn := filepath.Join(dirs.SnapSeedDir, "assertions", "foo.snap-declaration") err = ioutil.WriteFile(declFn, asserts.Encode(snapDecl), 0644) c.Assert(err, IsNil) sha3_384, size, err := asserts.SnapFileSHA3_384(targetSnapFile) c.Assert(err, IsNil) snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, map[string]interface{}{ "snap-sha3-384": sha3_384, "snap-size": fmt.Sprintf("%d", size), "snap-id": "snapidsnapid", "developer-id": "developerid", "snap-revision": "128", "timestamp": time.Now().UTC().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) revFn := filepath.Join(dirs.SnapSeedDir, "assertions", "foo.snap-revision") err = ioutil.WriteFile(revFn, asserts.Encode(snapRev), 0644) c.Assert(err, IsNil) // add a model assertion and its chain assertsChain := s.makeModelAssertionChain(c) for i, as := range assertsChain { fn := filepath.Join(dirs.SnapSeedDir, "assertions", strconv.Itoa(i)) err := ioutil.WriteFile(fn, asserts.Encode(as), 0644) c.Assert(err, IsNil) } // create a seed.yaml content := []byte(fmt.Sprintf(` snaps: - name: foo file: %s devmode: true - name: local unasserted: true file: %s `, filepath.Base(targetSnapFile), filepath.Base(targetSnapFile2))) err = ioutil.WriteFile(filepath.Join(dirs.SnapSeedDir, "seed.yaml"), content, 0644) c.Assert(err, IsNil) // run the firstboot stuff err = boot.PopulateStateFromSeed() c.Assert(err, IsNil) // and check the snap got correctly installed c.Check(osutil.FileExists(filepath.Join(dirs.SnapMountDir, "foo", "128", "meta", "snap.yaml")), Equals, true) c.Check(osutil.FileExists(filepath.Join(dirs.SnapMountDir, "local", "x1", "meta", "snap.yaml")), Equals, true) // verify r, err := os.Open(dirs.SnapStateFile) c.Assert(err, IsNil) state, err := state.ReadState(nil, r) c.Assert(err, IsNil) state.Lock() defer state.Unlock() // check foo info, err := snapstate.CurrentInfo(state, "foo") c.Assert(err, IsNil) c.Assert(info.SnapID, Equals, "snapidsnapid") c.Assert(info.Revision, Equals, snap.R(128)) c.Assert(info.DeveloperID, Equals, "developerid") var snapst snapstate.SnapState err = snapstate.Get(state, "foo", &snapst) c.Assert(err, IsNil) c.Assert(snapst.DevMode(), Equals, true) // check local info, err = snapstate.CurrentInfo(state, "local") c.Assert(err, IsNil) c.Assert(info.SnapID, Equals, "") c.Assert(info.Revision, Equals, snap.R("x1")) c.Assert(info.DeveloperID, Equals, "") }