// APIWorker returns a Worker that connects to the API and starts any // workers that need an API connection. // // If a state worker is necessary, APIWorker calls ensureStateWorker. func (a *MachineAgent) APIWorker(ensureStateWorker func()) (worker.Worker, error) { st, entity, err := openAPIState(a.Conf.Conf, a) if err != nil { // There was an error connecting to the API, // https://launchpad.net/bugs/1199915 means that we may just // not have an API password set. So force a state connection at // this point. // TODO(jam): Once we can reliably trust that we have API // passwords set, and we no longer need state // connections (and possibly agents will be blocked // from connecting directly to state) we can remove // this. Currently needed because 1.10 does not set // the API password and 1.11 requires it ensureStateWorker() return nil, err } needsStateWorker := false for _, job := range entity.Jobs() { needsStateWorker = needsStateWorker || stateJobs[job] } if needsStateWorker { ensureStateWorker() } runner := worker.NewRunner(allFatal, moreImportant) // Only the machiner currently connects to the API. // Add other workers here as they are ready. runner.StartWorker("machiner", func() (worker.Worker, error) { return machiner.NewMachiner(st.Machiner(), a.Tag()), nil }) runner.StartWorker("upgrader", func() (worker.Worker, error) { // TODO(rog) use id instead of *Machine (or introduce Clone method) return upgrader.New(st.Upgrader(), a.Tag(), a.Conf.DataDir), nil }) for _, job := range entity.Jobs() { switch job { case params.JobHostUnits: deployerTask, err := newDeployer(st.Deployer(), a.Tag(), a.Conf.DataDir) if err != nil { return nil, err } runner.StartWorker("deployer", func() (worker.Worker, error) { return deployerTask, nil }) case params.JobManageEnviron: // Not yet implemented with the API. case params.JobManageState: // Not yet implemented with the API. default: // TODO(dimitern): Once all workers moved over to using // the API, report "unknown job type" here. } } return newCloseWorker(runner, st), nil // Note: a worker.Runner is itself a worker.Worker. }
func (a *UnitAgent) APIWorkers() (worker.Worker, error) { st, entity, err := openAPIState(a.Conf.Conf, a) if err != nil { return nil, err } dataDir := a.Conf.DataDir runner := worker.NewRunner(allFatal, moreImportant) runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.New(st.Upgrader(), entity.Tag(), dataDir), nil }) return newCloseWorker(runner, st), nil }
func (s *UpgraderSuite) TestUpgraderRetryAndChanged(c *gc.C) { oldTools := s.primeTools(c, version.MustParseBinary("5.4.3-foo-bar")) newTools := s.uploadTools(c, version.MustParseBinary("5.4.5-foo-bar")) err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) c.Assert(err, gc.IsNil) retryc := make(chan time.Time) *upgrader.RetryAfter = func() <-chan time.Time { c.Logf("replacement retry after") return retryc } dummy.Poison(s.Conn.Environ.Storage(), tools.StorageName(newTools.Version), fmt.Errorf("a non-fatal dose")) u := upgrader.New(s.state.Upgrader(), s.machine.Tag(), s.DataDir()) defer u.Stop() for i := 0; i < 3; i++ { select { case retryc <- time.Now(): case <-time.After(coretesting.LongWait): c.Fatalf("upgrader did not retry (attempt %d)", i) } } // Make it upgrade to some newer tools that can be // downloaded ok; it should stop retrying, download // the newer tools and exit. newerTools := s.uploadTools(c, version.MustParseBinary("5.4.6-foo-bar")) err = statetesting.SetAgentVersion(s.State, newerTools.Version.Number) c.Assert(err, gc.IsNil) s.BackingState.Sync() done := make(chan error) go func() { done <- u.Wait() }() select { case err := <-done: c.Assert(err, gc.DeepEquals, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag(), OldTools: oldTools, NewTools: newerTools, DataDir: s.DataDir(), }) case <-time.After(coretesting.LongWait): c.Fatalf("upgrader did not quit after upgrading") } }
func (s *UpgraderSuite) TestUpgraderSetsTools(c *gc.C) { vers := version.MustParseBinary("5.4.3-foo-bar") err := statetesting.SetAgentVersion(s.State, vers.Number) c.Assert(err, gc.IsNil) agentTools := s.primeTools(c, vers) _, err = s.machine.AgentTools() c.Assert(err, jc.Satisfies, errors.IsNotFoundError) u := upgrader.New(s.state.Upgrader(), s.machine.Tag(), s.DataDir()) statetesting.AssertStop(c, u) s.machine.Refresh() gotTools, err := s.machine.AgentTools() c.Assert(err, gc.IsNil) c.Assert(gotTools, gc.DeepEquals, agentTools) }
func (s *UpgraderSuite) TestUpgraderSetToolsEvenWithNoToolsToRead(c *gc.C) { vers := version.MustParseBinary("5.4.3-foo-bar") s.primeTools(c, vers) err := os.RemoveAll(filepath.Join(s.DataDir(), "tools")) c.Assert(err, gc.IsNil) _, err = s.machine.AgentTools() c.Assert(err, jc.Satisfies, errors.IsNotFoundError) err = statetesting.SetAgentVersion(s.State, vers.Number) c.Assert(err, gc.IsNil) u := upgrader.New(s.state.Upgrader(), s.machine.Tag(), s.DataDir()) statetesting.AssertStop(c, u) s.machine.Refresh() gotTools, err := s.machine.AgentTools() c.Assert(err, gc.IsNil) c.Assert(gotTools, gc.DeepEquals, &tools.Tools{Version: version.Current}) }
func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { oldTools := s.primeTools(c, version.MustParseBinary("5.4.3-foo-bar")) newTools := s.uploadTools(c, version.MustParseBinary("5.4.5-foo-bar")) err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) c.Assert(err, gc.IsNil) // Make the download take a while so that we verify that // the download happens before the upgrader checks if // it's been stopped. dummy.SetStorageDelay(coretesting.ShortWait) u := upgrader.New(s.state.Upgrader(), s.machine.Tag(), s.DataDir()) err = u.Stop() c.Assert(err, gc.DeepEquals, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag(), OldTools: oldTools, NewTools: newTools, DataDir: s.DataDir(), }) foundTools, err := tools.ReadTools(s.DataDir(), newTools.Version) c.Assert(err, gc.IsNil) c.Assert(foundTools, gc.DeepEquals, newTools) }