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}) }
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, ss *snapstate.SnapSetup) *state.Change { s.state.Lock() defer s.state.Unlock() task := s.state.NewTask("setup-profiles", "") task.Set("snap-setup", ss) 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 (s *interfaceManagerSuite) addDiscardConnsChange(c *C, snapName string) *state.Change { s.state.Lock() defer s.state.Unlock() task := s.state.NewTask("discard-conns", "") ss := snapstate.SnapSetup{Name: snapName} task.Set("snap-setup", ss) 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{Name: snapName} task.Set("snap-setup", ss) taskset := state.NewTaskSet(task) change := s.state.NewChange("test", "") change.AddAll(taskset) return change }
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 (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 installSnap(chg *state.Change, name, channel string, userID int, flags snappy.InstallFlags) error { st := chg.State() ts, err := snapstateInstall(st, name, channel, userID, flags) if err != nil { return err } // ensure that each of our task runs after the existing tasks chgts := state.NewTaskSet(chg.Tasks()...) for _, t := range ts.Tasks() { t.WaitAll(chgts) } chg.AddAll(ts) return nil }
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, curActive bool, snapName, snapPath, channel string, userID int, flags snappy.InstallFlags) (*state.TaskSet, error) { if err := checkChangeConflict(s, snapName); err != nil { return nil, err } if snapPath == "" && channel == "" { channel = "stable" } var prepare *state.Task ss := SnapSetup{ Channel: channel, UserID: userID, Flags: int(flags), } ss.Name = snapName ss.SnapPath = snapPath if snapPath != "" { prepare = s.NewTask("prepare-snap", fmt.Sprintf(i18n.G("Prepare snap %q"), snapPath)) } else { prepare = s.NewTask("download-snap", fmt.Sprintf(i18n.G("Download snap %q from channel %q"), snapName, channel)) } prepare.Set("snap-setup", ss) tasks := []*state.Task{prepare} addTask := func(t *state.Task) { t.Set("snap-setup-task", prepare.ID()) tasks = append(tasks, t) } // mount mount := s.NewTask("mount-snap", fmt.Sprintf(i18n.G("Mount snap %q"), snapName)) addTask(mount) mount.WaitFor(prepare) precopy := mount if curActive { // unlink-current-snap (will stop services for copy-data) unlink := s.NewTask("unlink-current-snap", fmt.Sprintf(i18n.G("Make current revision for snap %q unavailable"), snapName)) addTask(unlink) unlink.WaitFor(mount) precopy = unlink } // copy-data (needs stopped services by unlink) copyData := s.NewTask("copy-snap-data", fmt.Sprintf(i18n.G("Copy snap %q data"), snapName)) addTask(copyData) copyData.WaitFor(precopy) // security setupSecurity := s.NewTask("setup-profiles", fmt.Sprintf(i18n.G("Setup snap %q security profiles"), snapName)) addTask(setupSecurity) setupSecurity.WaitFor(copyData) // finalize (wrappers+current symlink) linkSnap := s.NewTask("link-snap", fmt.Sprintf(i18n.G("Make snap %q available to the system"), snapName)) addTask(linkSnap) linkSnap.WaitFor(setupSecurity) return state.NewTaskSet(tasks...), 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, flags snappy.RemoveFlags) (*state.TaskSet, error) { if err := checkChangeConflict(s, name); err != nil { return nil, err } var snapst SnapState err := Get(s, name, &snapst) if err != nil && err != state.ErrNoState { return nil, err } cur := snapst.Current() if cur == nil { return nil, fmt.Errorf("cannot find snap %q", name) } revision := snapst.Current().Revision active := snapst.Active info, err := Info(s, name, revision) if err != nil { return nil, err } ss := SnapSetup{ Name: name, Revision: revision, Flags: int(flags), } // check if this is something that can be removed if !backend.CanRemove(info, active) { return nil, fmt.Errorf("snap %q is not removable", ss.Name) } // trigger remove discardSnap := s.NewTask("discard-snap", fmt.Sprintf(i18n.G("Remove snap %q from the system"), name)) discardSnap.Set("snap-setup", ss) discardSnapID := discardSnap.ID() tasks := ([]*state.Task)(nil) var chain *state.Task addNext := func(t *state.Task) { if chain != nil { t.WaitFor(chain) } if t.ID() != discardSnapID { t.Set("snap-setup-task", discardSnapID) } tasks = append(tasks, t) chain = t } if active { unlink := s.NewTask("unlink-snap", fmt.Sprintf(i18n.G("Make snap %q unavailable to the system"), name)) addNext(unlink) } removeSecurity := s.NewTask("remove-profiles", fmt.Sprintf(i18n.G("Remove security profile for snap %q"), name)) addNext(removeSecurity) clearData := s.NewTask("clear-snap", fmt.Sprintf(i18n.G("Remove data for snap %q"), name)) addNext(clearData) addNext(discardSnap) if len(snapst.Sequence) == 1 { discardConns := s.NewTask("discard-conns", fmt.Sprintf(i18n.G("Discard interface connections for snap %q"), name)) addNext(discardConns) } return state.NewTaskSet(tasks...), nil }