func (cs *taskSuite) TestNewTaskSet(c *C) { ts0 := state.NewTaskSet() c.Check(ts0.Tasks(), HasLen, 0) st := state.New(nil) st.Lock() t1 := st.NewTask("download", "1...") t2 := st.NewTask("install", "2...") ts2 := state.NewTaskSet(t1, t2) st.Unlock() c.Assert(ts2.Tasks(), DeepEquals, []*state.Task{t1, t2}) }
// Enable sets a snap to the active state func Enable(s *state.State, name string) (*state.TaskSet, error) { var snapst SnapState err := Get(s, name, &snapst) if err == state.ErrNoState { return nil, fmt.Errorf("cannot find snap %q", name) } if err != nil { return nil, err } if snapst.Active { return nil, fmt.Errorf("snap %q already enabled", name) } if err := checkChangeConflict(s, name, nil); err != nil { return nil, err } ss := &SnapSetup{ SideInfo: snapst.CurrentSideInfo(), } prepareSnap := s.NewTask("prepare-snap", fmt.Sprintf(i18n.G("Prepare snap %q (%s)"), ss.Name(), snapst.Current)) prepareSnap.Set("snap-setup", &ss) linkSnap := s.NewTask("link-snap", fmt.Sprintf(i18n.G("Make snap %q (%s) available to the system"), ss.Name(), snapst.Current)) linkSnap.Set("snap-setup", &ss) linkSnap.WaitFor(prepareSnap) startSnapServices := s.NewTask("start-snap-services", fmt.Sprintf(i18n.G("Start snap %q (%s) services"), ss.Name(), snapst.Current)) startSnapServices.Set("snap-setup", &ss) startSnapServices.WaitFor(linkSnap) return state.NewTaskSet(prepareSnap, linkSnap, startSnapServices), nil }
func setSnapConf(c *Command, r *http.Request, user *auth.UserState) Response { vars := muxVars(r) snapName := vars["name"] var patchValues map[string]interface{} decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&patchValues); err != nil { return BadRequest("cannot decode request body into patch values: %v", err) } // TODO: Add patch values to configmanager s := c.d.overlord.State() s.Lock() defer s.Unlock() hookTaskSummary := fmt.Sprintf(i18n.G("Run apply-config hook for %s"), snapName) task := hookstate.HookTask(s, hookTaskSummary, snapName, snap.Revision{}, "apply-config") taskset := state.NewTaskSet(task) change := s.NewChange("configure-snap", fmt.Sprintf("Setting config for %s", snapName)) change.AddAll(taskset) s.EnsureBefore(0) return AsyncResponse(nil, &Meta{Change: change.ID()}) }
// Alias enables the provided aliases for the snap with the given name. func Alias(st *state.State, snapName string, aliases []string) (*state.TaskSet, error) { var snapst SnapState err := Get(st, snapName, &snapst) if err == state.ErrNoState { return nil, fmt.Errorf("cannot find snap %q", snapName) } if err != nil { return nil, err } if !snapst.Active { return nil, fmt.Errorf("enabling aliases for disabled snap %q not supported", snapName) } if err := checkChangeConflict(st, snapName, nil); err != nil { return nil, err } snapsup := &SnapSetup{ SideInfo: &snap.SideInfo{RealName: snapName}, } alias := st.NewTask("alias", fmt.Sprintf(i18n.G("Enable aliases for snap %q"), snapsup.Name())) alias.Set("snap-setup", &snapsup) toEnable := map[string]string{} for _, alias := range aliases { toEnable[alias] = "enabled" } alias.Set("aliases", toEnable) return state.NewTaskSet(alias), nil }
// ResetAliases resets the provided aliases for the snap with the given name to their default state, enabled for auto-aliases, disabled otherwise. func ResetAliases(st *state.State, snapName string, aliases []string) (*state.TaskSet, error) { var snapst SnapState err := Get(st, snapName, &snapst) if err == state.ErrNoState { return nil, fmt.Errorf("cannot find snap %q", snapName) } if err != nil { return nil, err } if !snapst.Active { // TODO: we might want to support this return nil, fmt.Errorf("resetting aliases to their default state for disabled snap %q not supported", snapName) } if err := checkChangeConflict(st, snapName, nil); err != nil { return nil, err } snapsup := &SnapSetup{ SideInfo: &snap.SideInfo{RealName: snapName}, } alias := st.NewTask("alias", fmt.Sprintf(i18n.G("Reset aliases for snap %q"), snapsup.Name())) alias.Set("snap-setup", &snapsup) toReset := map[string]string{} for _, alias := range aliases { toReset[alias] = "auto" } alias.Set("aliases", toReset) return state.NewTaskSet(alias), nil }
// Disable sets a snap to the inactive state func Disable(s *state.State, name string) (*state.TaskSet, error) { var snapst SnapState err := Get(s, name, &snapst) if err == state.ErrNoState { return nil, fmt.Errorf("cannot find snap %q", name) } if err != nil { return nil, err } if !snapst.Active { return nil, fmt.Errorf("snap %q already disabled", name) } if err := checkChangeConflict(s, name, nil); err != nil { return nil, err } ss := &SnapSetup{ SideInfo: &snap.SideInfo{ RealName: name, Revision: snapst.Current, }, } stopSnapServices := s.NewTask("stop-snap-services", fmt.Sprintf(i18n.G("Stop snap %q (%s) services"), ss.Name(), snapst.Current)) stopSnapServices.Set("snap-setup", &ss) unlinkSnap := s.NewTask("unlink-snap", fmt.Sprintf(i18n.G("Make snap %q (%s) unavailable to the system"), ss.Name(), snapst.Current)) unlinkSnap.Set("snap-setup-task", stopSnapServices.ID()) unlinkSnap.WaitFor(stopSnapServices) return state.NewTaskSet(stopSnapServices, unlinkSnap), nil }
// Disconnect returns a set of tasks for disconnecting an interface. func Disconnect(s *state.State, plugSnap, plugName, slotSnap, slotName string) (*state.TaskSet, error) { summary := fmt.Sprintf(i18n.G("Disconnect %s:%s from %s:%s"), plugSnap, plugName, slotSnap, slotName) task := s.NewTask("disconnect", summary) task.Set("slot", interfaces.SlotRef{Snap: slotSnap, Name: slotName}) task.Set("plug", interfaces.PlugRef{Snap: plugSnap, Name: plugName}) return state.NewTaskSet(task), nil }
func (ts *taskSuite) TestTaskSetWaitAll(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() t1 := st.NewTask("download", "1...") t2 := st.NewTask("check", "2...") t3 := st.NewTask("setup", "3...") t4 := st.NewTask("link", "4...") ts12 := state.NewTaskSet(t1, t2) ts34 := state.NewTaskSet(t3, t4) ts34.WaitAll(ts12) c.Assert(t3.WaitTasks(), DeepEquals, []*state.Task{t1, t2}) c.Assert(t4.WaitTasks(), DeepEquals, []*state.Task{t1, t2}) c.Assert(t1.HaltTasks(), HasLen, 2) c.Assert(t2.HaltTasks(), HasLen, 2) }
// Disconnect returns a set of tasks for disconnecting an interface. func Disconnect(s *state.State, plugSnap, plugName, slotSnap, slotName string) (*state.TaskSet, error) { // TODO: Remove the intent-to-connect from the state so that we no longer // automatically try to reconnect on reboot. summary := fmt.Sprintf(i18n.G("Disconnect %s:%s from %s:%s"), plugSnap, plugName, slotSnap, slotName) task := s.NewTask("disconnect", summary) task.Set("slot", interfaces.SlotRef{Snap: slotSnap, Name: slotName}) task.Set("plug", interfaces.PlugRef{Snap: plugSnap, Name: plugName}) return state.NewTaskSet(task), nil }
func (s *interfaceManagerSuite) addSetupSnapSecurityChange(c *C, snapsup *snapstate.SnapSetup) *state.Change { s.state.Lock() defer s.state.Unlock() task := s.state.NewTask("setup-profiles", "") task.Set("snap-setup", snapsup) taskset := state.NewTaskSet(task) change := s.state.NewChange("test", "") change.AddAll(taskset) return change }
// Connect returns a set of tasks for connecting an interface. // func Connect(s *state.State, plugSnap, plugName, slotSnap, slotName string) (*state.TaskSet, error) { // TODO: Store the intent-to-connect in the state so that we automatically // try to reconnect on reboot (reconnection can fail or can connect with // different parameters so we cannot store the actual connection details). summary := fmt.Sprintf(i18n.G("Connect %s:%s to %s:%s"), plugSnap, plugName, slotSnap, slotName) task := s.NewTask("connect", summary) task.Set("slot", interfaces.SlotRef{Snap: slotSnap, Name: slotName}) task.Set("plug", interfaces.PlugRef{Snap: plugSnap, Name: plugName}) return state.NewTaskSet(task), nil }
func (ts *taskSuite) TestTaskSetAddTaskAndAddAll(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() t1 := st.NewTask("download", "1...") t2 := st.NewTask("check", "2...") t3 := st.NewTask("setup", "3...") t4 := st.NewTask("link", "4...") ts0 := state.NewTaskSet(t1) ts0.AddTask(t2) ts0.AddAll(state.NewTaskSet(t3, t4)) // these do nothing ts0.AddTask(t2) ts0.AddAll(state.NewTaskSet(t3, t4)) c.Check(ts0.Tasks(), DeepEquals, []*state.Task{t1, t2, t3, t4}) }
func (m *DeviceManager) ensureOperational() error { m.state.Lock() defer m.state.Unlock() device, err := auth.Device(m.state) if err != nil { return err } if device.Serial != "" { // serial is set, we are all set return nil } if device.Brand == "" || device.Model == "" { // need first-boot, loading of model assertion info if release.OnClassic { // TODO: are we going to have model assertions on classic or need will need to cheat here? return nil } // cannot proceed yet, once first boot is done these will be set // and we can pick up from there return nil } for _, chg := range m.state.Changes() { if chg.Kind() == "become-operational" && !chg.Status().Ready() { // change already in motion return nil } } if serialRequestURL == "" { // cannot do anything actually return nil } // XXX: some of these will need to be split and use hooks // retries might need to embrace more than one "task" then, // need to be careful genKey := m.state.NewTask("generate-device-key", i18n.G("Generate device key")) requestSerial := m.state.NewTask("request-serial", i18n.G("Request device serial")) requestSerial.WaitFor(genKey) chg := m.state.NewChange("become-operational", i18n.G("Initialize device")) chg.AddAll(state.NewTaskSet(genKey, requestSerial)) return nil }
func (ts *taskSuite) TestTaskWaitAll(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() t1 := st.NewTask("download", "1...") t2 := st.NewTask("install", "2...") t3 := st.NewTask("setup", "3...") t3.WaitAll(state.NewTaskSet(t1, t2)) c.Assert(t3.WaitTasks(), HasLen, 2) c.Assert(t1.HaltTasks(), DeepEquals, []*state.Task{t3}) c.Assert(t2.HaltTasks(), DeepEquals, []*state.Task{t3}) }
func (ts *taskSuite) TestTaskSetWaitFor(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() t1 := st.NewTask("download", "1...") t2 := st.NewTask("install", "2...") t3 := st.NewTask("setup", "3...") ts23 := state.NewTaskSet(t2, t3) ts23.WaitFor(t1) c.Assert(t2.WaitTasks(), DeepEquals, []*state.Task{t1}) c.Assert(t3.WaitTasks(), DeepEquals, []*state.Task{t1}) c.Assert(t1.HaltTasks(), HasLen, 2) }
func (cs *changeSuite) TestAddAll(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() chg := st.NewChange("install", "...") t1 := st.NewTask("download", "1...") t2 := st.NewTask("verify", "2...") chg.AddAll(state.NewTaskSet(t1, t2)) tasks := chg.Tasks() c.Check(tasks, DeepEquals, []*state.Task{t1, t2}) c.Check(t1.Change(), Equals, chg) c.Check(t2.Change(), Equals, chg) }
func (s *interfaceManagerSuite) addDiscardConnsChange(c *C, snapName string) *state.Change { s.state.Lock() defer s.state.Unlock() task := s.state.NewTask("discard-conns", "") snapsup := snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ RealName: snapName, }, } task.Set("snap-setup", snapsup) taskset := state.NewTaskSet(task) change := s.state.NewChange("test", "") change.AddAll(taskset) return change }
func (s *interfaceManagerSuite) addRemoveSnapSecurityChange(c *C, snapName string) *state.Change { s.state.Lock() defer s.state.Unlock() task := s.state.NewTask("remove-profiles", "") ss := snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ RealName: snapName, }, } task.Set("snap-setup", ss) taskset := state.NewTaskSet(task) change := s.state.NewChange("test", "") change.AddAll(taskset) return change }
func removeInactiveRevision(s *state.State, name string, revision snap.Revision) *state.TaskSet { ss := SnapSetup{ SideInfo: &snap.SideInfo{ RealName: name, Revision: revision, }, } clearData := s.NewTask("clear-snap", fmt.Sprintf(i18n.G("Remove data for snap %q (%s)"), name, revision)) clearData.Set("snap-setup", ss) discardSnap := s.NewTask("discard-snap", fmt.Sprintf(i18n.G("Remove snap %q (%s) from the system"), name, revision)) discardSnap.WaitFor(clearData) discardSnap.Set("snap-setup-task", clearData.ID()) return state.NewTaskSet(clearData, discardSnap) }
func (s *deviceMgrSuite) TestDeviceManagerEnsureSeedYamlHappy(c *C) { release.OnClassic = false restore := devicestate.MockPopulateStateFromSeed(func(*state.State) (ts []*state.TaskSet, err error) { t := s.state.NewTask("test-task", "a random task") ts = append(ts, state.NewTaskSet(t)) return ts, nil }) defer restore() err := s.mgr.EnsureSeedYaml() c.Assert(err, IsNil) s.state.Lock() defer s.state.Unlock() c.Check(s.state.Changes(), HasLen, 1) }
// Configure returns a taskset to apply the given configuration patch. func Configure(s *state.State, snapName string, patch map[string]interface{}) *state.TaskSet { hooksup := &hookstate.HookSetup{ Snap: snapName, Hook: "configure", Optional: len(patch) == 0, } var contextData map[string]interface{} if len(patch) > 0 { contextData = map[string]interface{}{"patch": patch} } var summary string if hooksup.Optional { summary = fmt.Sprintf(i18n.G("Run configure hook of %q snap if present"), snapName) } else { summary = fmt.Sprintf(i18n.G("Run configure hook of %q snap"), snapName) } task := hookstate.HookTask(s, summary, hooksup, contextData) return state.NewTaskSet(task) }
func (cs *changeSuite) TestIsClean(c *C) { st := state.New(nil) st.Lock() defer st.Unlock() chg := st.NewChange("install", "...") t1 := st.NewTask("download", "1...") t2 := st.NewTask("verify", "2...") chg.AddAll(state.NewTaskSet(t1, t2)) t1.SetStatus(state.DoneStatus) c.Assert(t1.SetClean, PanicMatches, ".*while change not ready") t2.SetStatus(state.DoneStatus) t1.SetClean() c.Assert(chg.IsClean(), Equals, false) t2.SetClean() c.Assert(chg.IsClean(), Equals, true) }
func (ovs *overlordSuite) TestSettleChain(c *C) { restoreIntv := overlord.MockEnsureInterval(1 * time.Minute) defer restoreIntv() o, err := overlord.New() c.Assert(err, IsNil) se := o.Engine() s := se.State() rm1 := newRunnerManager(s) se.AddManager(rm1) defer o.Engine().Stop() s.Lock() defer s.Unlock() chg := s.NewChange("chg", "...") t1 := s.NewTask("runMgr1", "1...") t2 := s.NewTask("runMgr2", "2...") t2.WaitFor(t1) chg.AddAll(state.NewTaskSet(t1, t2)) s.Unlock() o.Settle() s.Lock() c.Check(t1.Status(), Equals, state.DoneStatus) c.Check(t2.Status(), Equals, state.DoneStatus) var v int err = s.Get("runMgr1Mark", &v) c.Check(err, IsNil) err = s.Get("runMgr2Mark", &v) c.Check(err, IsNil) }
func doInstall(s *state.State, snapst *SnapState, ss *SnapSetup) (*state.TaskSet, error) { if err := checkChangeConflict(s, ss.Name(), snapst); err != nil { return nil, err } targetRevision := ss.Revision() revisionStr := "" if ss.SideInfo != nil { revisionStr = fmt.Sprintf(" (%s)", targetRevision) } // check if we already have the revision locally (alters tasks) revisionIsLocal := snapst.LastIndex(targetRevision) >= 0 var prepare, prev *state.Task fromStore := false // if we have a local revision here we go back to that if ss.SnapPath != "" || revisionIsLocal { prepare = s.NewTask("prepare-snap", fmt.Sprintf(i18n.G("Prepare snap %q%s"), ss.SnapPath, revisionStr)) } else { fromStore = true prepare = s.NewTask("download-snap", fmt.Sprintf(i18n.G("Download snap %q%s from channel %q"), ss.Name(), revisionStr, ss.Channel)) } prepare.Set("snap-setup", ss) tasks := []*state.Task{prepare} addTask := func(t *state.Task) { t.Set("snap-setup-task", prepare.ID()) t.WaitFor(prev) tasks = append(tasks, t) } prev = prepare if fromStore { // fetch and check assertions checkAsserts := s.NewTask("validate-snap", fmt.Sprintf(i18n.G("Fetch and check assertions for snap %q%s"), ss.Name(), revisionStr)) addTask(checkAsserts) prev = checkAsserts } // mount if !revisionIsLocal { mount := s.NewTask("mount-snap", fmt.Sprintf(i18n.G("Mount snap %q%s"), ss.Name(), revisionStr)) addTask(mount) prev = mount } if snapst.Active { // unlink-current-snap (will stop services for copy-data) stop := s.NewTask("stop-snap-services", fmt.Sprintf(i18n.G("Stop snap %q services"), ss.Name())) addTask(stop) prev = stop unlink := s.NewTask("unlink-current-snap", fmt.Sprintf(i18n.G("Make current revision for snap %q unavailable"), ss.Name())) addTask(unlink) prev = unlink } // copy-data (needs stopped services by unlink) if !ss.Flags.Revert { copyData := s.NewTask("copy-snap-data", fmt.Sprintf(i18n.G("Copy snap %q data"), ss.Name())) addTask(copyData) prev = copyData } // security setupSecurity := s.NewTask("setup-profiles", fmt.Sprintf(i18n.G("Setup snap %q%s security profiles"), ss.Name(), revisionStr)) addTask(setupSecurity) prev = setupSecurity // finalize (wrappers+current symlink) linkSnap := s.NewTask("link-snap", fmt.Sprintf(i18n.G("Make snap %q%s available to the system"), ss.Name(), revisionStr)) addTask(linkSnap) prev = linkSnap // run new serices startSnapServices := s.NewTask("start-snap-services", fmt.Sprintf(i18n.G("Start snap %q%s services"), ss.Name(), revisionStr)) addTask(startSnapServices) prev = startSnapServices // Do not do that if we are reverting to a local revision if snapst.HasCurrent() && !ss.Flags.Revert { seq := snapst.Sequence currentIndex := snapst.LastIndex(snapst.Current) // discard everything after "current" (we may have reverted to // a previous versions earlier) for i := currentIndex + 1; i < len(seq); i++ { si := seq[i] if si.Revision == targetRevision { // but don't discard this one; its' the thing we're switching to! continue } ts := removeInactiveRevision(s, ss.Name(), si.Revision) ts.WaitFor(prev) tasks = append(tasks, ts.Tasks()...) prev = tasks[len(tasks)-1] } // make sure we're not scheduling the removal of the target // revision in the case where the target revision is already in // the sequence. for i := 0; i < currentIndex; i++ { si := seq[i] if si.Revision == targetRevision { // we do *not* want to removeInactiveRevision of this one copy(seq[i:], seq[i+1:]) seq = seq[:len(seq)-1] currentIndex-- } } // normal garbage collect for i := 0; i <= currentIndex-2; i++ { si := seq[i] ts := removeInactiveRevision(s, ss.Name(), si.Revision) ts.WaitFor(prev) tasks = append(tasks, ts.Tasks()...) prev = tasks[len(tasks)-1] } addTask(s.NewTask("cleanup", fmt.Sprintf("Clean up %q%s install", ss.Name(), revisionStr))) } var defaults map[string]interface{} if !snapst.HasCurrent() && ss.SideInfo != nil && ss.SideInfo.SnapID != "" { gadget, err := GadgetInfo(s) if err != nil && err != state.ErrNoState { return nil, err } if err == nil { gadgetInfo, err := snap.ReadGadgetInfo(gadget) if err != nil { return nil, err } defaults = gadgetInfo.Defaults[ss.SideInfo.SnapID] } } installSet := state.NewTaskSet(tasks...) configSet := Configure(s, ss.Name(), defaults) configSet.WaitAll(installSet) installSet.AddAll(configSet) return installSet, nil }
func (m *DeviceManager) ensureOperational() error { m.state.Lock() defer m.state.Unlock() device, err := auth.Device(m.state) if err != nil { return err } if device.Serial != "" { // serial is set, we are all set return nil } if device.Brand == "" || device.Model == "" { // need first-boot, loading of model assertion info if release.OnClassic { // TODO: are we going to have model assertions on classic or need will need to cheat here? return nil } // cannot proceed yet, once first boot is done these will be set // and we can pick up from there return nil } if m.changeInFlight("become-operational") { return nil } if serialRequestURL == "" { // cannot do anything actually return nil } gadgetInfo, err := snapstate.GadgetInfo(m.state) if err == state.ErrNoState { // no gadget installed yet, cannot proceed return nil } if err != nil { return err } // XXX: some of these will need to be split and use hooks // retries might need to embrace more than one "task" then, // need to be careful tasks := []*state.Task{} var prepareDevice *state.Task if gadgetInfo.Hooks["prepare-device"] != nil { summary := i18n.G("Run prepare-device hook") hooksup := &hookstate.HookSetup{ Snap: gadgetInfo.Name(), Hook: "prepare-device", } prepareDevice = hookstate.HookTask(m.state, summary, hooksup, nil) tasks = append(tasks, prepareDevice) } genKey := m.state.NewTask("generate-device-key", i18n.G("Generate device key")) if prepareDevice != nil { genKey.WaitFor(prepareDevice) } tasks = append(tasks, genKey) requestSerial := m.state.NewTask("request-serial", i18n.G("Request device serial")) requestSerial.WaitFor(genKey) tasks = append(tasks, requestSerial) chg := m.state.NewChange("become-operational", i18n.G("Initialize device")) chg.AddAll(state.NewTaskSet(tasks...)) return nil }
// Remove returns a set of tasks for removing snap. // Note that the state must be locked by the caller. func Remove(s *state.State, name string, revision snap.Revision) (*state.TaskSet, error) { var snapst SnapState err := Get(s, name, &snapst) if err != nil && err != state.ErrNoState { return nil, err } if !snapst.HasCurrent() { return nil, fmt.Errorf("cannot find snap %q", name) } if err := checkChangeConflict(s, name, nil); err != nil { return nil, err } active := snapst.Active var removeAll bool if revision.Unset() { removeAll = true revision = snapst.Current } else { removeAll = false if active { if revision == snapst.Current { msg := "cannot remove active revision %s of snap %q" if len(snapst.Sequence) > 1 { msg += " (revert first?)" } return nil, fmt.Errorf(msg, revision, name) } active = false } if !revisionInSequence(&snapst, revision) { return nil, fmt.Errorf("revision %s of snap %q is not installed", revision, name) } } info, err := Info(s, name, revision) if err != nil { return nil, err } // check if this is something that can be removed if !canRemove(info, active) { return nil, fmt.Errorf("snap %q is not removable", name) } // main/current SnapSetup ss := SnapSetup{ SideInfo: &snap.SideInfo{ RealName: name, Revision: revision, }, } // trigger remove full := state.NewTaskSet() var chain *state.TaskSet addNext := func(ts *state.TaskSet) { if chain != nil { ts.WaitAll(chain) } full.AddAll(ts) chain = ts } if active { // unlink stopSnapServices := s.NewTask("stop-snap-services", fmt.Sprintf(i18n.G("Stop snap %q services"), name)) stopSnapServices.Set("snap-setup", ss) unlink := s.NewTask("unlink-snap", fmt.Sprintf(i18n.G("Make snap %q unavailable to the system"), name)) unlink.Set("snap-setup-task", stopSnapServices.ID()) unlink.WaitFor(stopSnapServices) removeSecurity := s.NewTask("remove-profiles", fmt.Sprintf(i18n.G("Remove security profile for snap %q (%s)"), name, revision)) removeSecurity.WaitFor(unlink) removeSecurity.Set("snap-setup-task", stopSnapServices.ID()) addNext(state.NewTaskSet(stopSnapServices, unlink, removeSecurity)) } if removeAll || len(snapst.Sequence) == 1 { seq := snapst.Sequence for i := len(seq) - 1; i >= 0; i-- { si := seq[i] addNext(removeInactiveRevision(s, name, si.Revision)) } discardConns := s.NewTask("discard-conns", fmt.Sprintf(i18n.G("Discard interface connections for snap %q (%s)"), name, revision)) discardConns.Set("snap-setup", &SnapSetup{ SideInfo: &snap.SideInfo{ RealName: name, }, }) addNext(state.NewTaskSet(discardConns)) } else { addNext(removeInactiveRevision(s, name, revision)) } return full, nil }
func populateStateFromSeedImpl(st *state.State) ([]*state.TaskSet, error) { // check that the state is empty var seeded bool err := st.Get("seeded", &seeded) if err != nil && err != state.ErrNoState { return nil, err } if seeded { return nil, fmt.Errorf("cannot populate state: already seeded") } // ack all initial assertions if err := importAssertionsFromSeed(st); err != nil { return nil, err } seed, err := snap.ReadSeedYaml(filepath.Join(dirs.SnapSeedDir, "seed.yaml")) if err != nil { return nil, err } tsAll := []*state.TaskSet{} for i, sn := range seed.Snaps { var flags snapstate.Flags if sn.DevMode { flags.DevMode = true } path := filepath.Join(dirs.SnapSeedDir, "snaps", sn.File) var sideInfo snap.SideInfo if sn.Unasserted { sideInfo.RealName = sn.Name } else { si, err := snapasserts.DeriveSideInfo(path, assertstate.DB(st)) if err == asserts.ErrNotFound { return nil, fmt.Errorf("cannot find signatures with metadata for snap %q (%q)", sn.Name, path) } if err != nil { return nil, err } sideInfo = *si sideInfo.Private = sn.Private } ts, err := snapstate.InstallPath(st, &sideInfo, path, sn.Channel, flags) if i > 0 { ts.WaitAll(tsAll[i-1]) } if err != nil { return nil, err } tsAll = append(tsAll, ts) } if len(tsAll) == 0 { return nil, nil } ts := tsAll[len(tsAll)-1] markSeeded := st.NewTask("mark-seeded", i18n.G("Mark system seeded")) markSeeded.WaitAll(ts) tsAll = append(tsAll, state.NewTaskSet(markSeeded)) return tsAll, nil }