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 mapLocal(localSnap *snap.Info, snapst *snapstate.SnapState) map[string]interface{} { status := "installed" if snapst.Active && localSnap.Revision == snapst.Current { status = "active" } apps := make([]appJSON, 0, len(localSnap.Apps)) for _, app := range localSnap.Apps { apps = append(apps, appJSON{ Name: app.Name, }) } return map[string]interface{}{ "description": localSnap.Description(), "developer": localSnap.Developer, "icon": snapIcon(localSnap), "id": localSnap.SnapID, "install-date": snapDate(localSnap), "installed-size": localSnap.Size, "name": localSnap.Name(), "revision": localSnap.Revision, "status": status, "summary": localSnap.Summary(), "type": string(localSnap.Type), "version": localSnap.Version, "channel": localSnap.Channel, "confinement": localSnap.Confinement, "devmode": snapst.DevMode(), "trymode": snapst.TryMode(), "private": localSnap.Private, "apps": apps, "broken": localSnap.Broken, } }
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 (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 *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 }
// 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 (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 } 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 (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, "") }