func (s *patch4Suite) TestPatch4OnRefreshes(c *C) { restorer := patch.MockLevel(4) 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) func() { st.Lock() defer st.Unlock() task := st.Task("16") c.Assert(task, NotNil) // simulate that the task was running (but the change // is not fully done yet) task.SetStatus(state.DoneStatus) ss, err := snapstate.TaskSnapSetup(task) c.Assert(err, IsNil) c.Check(ss.Flags.Revert(), Equals, false) var had bool var idx int c.Check(task.Get("had-candidate", &had), IsNil) c.Check(had, Equals, false) c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) c.Check(len(task.Change().Tasks()), Equals, 7) }() // go from patch level 3 -> 4 err = patch.Apply(st) c.Assert(err, IsNil) st.Lock() defer st.Unlock() task := st.Task("16") c.Assert(task, NotNil) ss, err := snapstate.TaskSnapSetup(task) c.Assert(err, IsNil) c.Check(ss.Flags.Revert(), Equals, false) var had bool var idx int c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) c.Check(task.Get("old-candidate-index", &idx), IsNil) c.Check(idx, Equals, 1) // we added cleanup c.Check(len(task.Change().Tasks()), Equals, 7+1) }
func (s *patch4Suite) TestPatch4OnRevertsNoCandidateYet(c *C) { restorer := patch.MockLevel(4) 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) func() { st.Lock() defer st.Unlock() task := st.Task("4") c.Assert(task, NotNil) // its ready to run but has not run yet task.Clear("had-candidate") task.SetStatus(state.DoStatus) ss, err := snapstate.TaskSnapSetup(task) c.Assert(err, IsNil) c.Check(ss.Flags.Revert(), Equals, false) var had bool var idx int c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) c.Check(task.Get("old-candidate-index", &idx), Equals, state.ErrNoState) c.Check(len(task.Change().Tasks()), Equals, 4) }() // go from patch level 3 -> 4 err = patch.Apply(st) c.Assert(err, IsNil) st.Lock() defer st.Unlock() task := st.Task("4") c.Assert(task, NotNil) ss, err := snapstate.TaskSnapSetup(task) c.Assert(err, IsNil) c.Check(ss.Flags.Revert(), Equals, true) var had bool var idx int c.Check(task.Get("had-candidate", &had), Equals, state.ErrNoState) c.Check(task.Get("old-candidate-index", &idx), IsNil) c.Check(idx, Equals, 1) c.Check(len(task.Change().Tasks()), Equals, 4) }
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) doSetupProfiles(task *state.Task, _ *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(ss.Name(), ss.SideInfo) if err != nil { return err } snap.AddImplicitSlots(snapInfo) snapName := snapInfo.Name() // The snap may have been updated so perform the following operation to // ensure that we are always working on the correct state: // // - disconnect all connections to/from the given snap // - remembering the snaps that were affected by this operation // - remove the (old) snap from the interfaces repository // - add the (new) snap to the interfaces repository // - restore connections based on what is kept in the state // - if a connection cannot be restored then remove it from the state // - setup the security of all the affected snaps affectedSnaps, err := m.repo.DisconnectSnap(snapName) if err != nil { return err } // XXX: what about snap renames? We should remove the old name (or switch // to IDs in the interfaces repository) if err := m.repo.RemoveSnap(snapName); err != nil { return err } if err := m.repo.AddSnap(snapInfo); err != nil { if _, ok := err.(*interfaces.BadInterfacesError); ok { logger.Noticef("%s", err) } else { return err } } if err := m.reloadConnections(snapName); err != nil { return err } // FIXME: here we should not reconnect auto-connect plug/slot // pairs that were explicitly disconnected by the user if err := m.autoConnect(task, snapName, nil); err != nil { return err } if err := setupSnapSecurity(task, snapInfo, ss.DevModeAllowed(), m.repo); err != nil { return err } return m.setupAffectedSnaps(task, snapName, affectedSnaps) }
func (m *InterfaceManager) doRemoveProfiles(task *state.Task, tomb *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() // Get SnapSetup for this snap. This is gives us the name of the snap. snapSetup, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapName := snapSetup.Name() return m.removeProfilesForSnap(task, tomb, snapName) }
func (m *InterfaceManager) doSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(ss.Name(), ss.SideInfo) if err != nil { return err } return m.setupProfilesForSnap(task, tomb, snapInfo, ss.DevModeAllowed()) }
func (m *InterfaceManager) doSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. snapsup, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(snapsup.Name(), snapsup.SideInfo) if err != nil { return err } opts := confinementOptions(snapsup.Flags) return m.setupProfilesForSnap(task, tomb, snapInfo, opts) }
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 }
// doValidateSnap fetches the relevant assertions for the snap being installed and cross checks them with the snap. func doValidateSnap(t *state.Task, _ *tomb.Tomb) error { t.State().Lock() defer t.State().Unlock() ss, err := snapstate.TaskSnapSetup(t) if err != nil { return nil } sha3_384, snapSize, err := asserts.SnapFileSHA3_384(ss.SnapPath) if err != nil { return err } err = doFetch(t.State(), ss.UserID, func(f asserts.Fetcher) error { return snapasserts.FetchSnapAssertions(f, sha3_384) }) if notFound, ok := err.(*store.AssertionNotFoundError); ok { if notFound.Ref.Type == asserts.SnapRevisionType { return fmt.Errorf("cannot verify snap %q, no matching signatures found", ss.Name()) } else { return fmt.Errorf("cannot find supported signatures to verify snap %q and its hash (%v)", ss.Name(), notFound) } } if err != nil { return err } db := DB(t.State()) err = snapasserts.CrossCheck(ss.Name(), sha3_384, snapSize, ss.SideInfo, db) if err != nil { // TODO: trigger a global sanity check // that will generate the changes to deal with this // for things like snap-decl revocation and renames? return err } // TODO: set DeveloperID from assertions return nil }
func (m *InterfaceManager) doRemoveProfiles(task *state.Task, _ *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() // Get SnapSetup for this snap. This is gives us the name of the snap. snapSetup, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapName := snapSetup.Name() // Disconnect the snap entirely. // This is required to remove the snap from the interface repository. // The returned list of affected snaps will need to have its security setup // to reflect the change. affectedSnaps, err := m.repo.DisconnectSnap(snapName) if err != nil { return err } if err := m.setupAffectedSnaps(task, snapName, affectedSnaps); err != nil { return err } // Remove the snap from the interface repository. // This discards all the plugs and slots belonging to that snap. if err := m.repo.RemoveSnap(snapName); err != nil { return err } // Remove security artefacts of the snap. if err := removeSnapSecurity(task, snapName); err != nil { // TODO: how long to wait? return &state.Retry{} } return nil }