// startAPIWorkers is called to start workers which rely on the // machine agent's API connection (via the apiworkers manifold). It // returns a Runner with a number of workers attached to it. // // The workers started here need to be converted to run under the // dependency engine. Once they have all been converted, this method - // and the apiworkers manifold - can be removed. func (a *MachineAgent) startAPIWorkers(apiConn api.Connection) (_ worker.Worker, outErr error) { agentConfig := a.CurrentConfig() entity, err := apiagent.NewState(apiConn).Entity(a.Tag()) if err != nil { return nil, errors.Trace(err) } var isModelManager bool for _, job := range entity.Jobs() { switch job { case multiwatcher.JobManageModel: isModelManager = true default: // TODO(dimitern): Once all workers moved over to using // the API, report "unknown job type" here. } } runner := newConnRunner(apiConn) defer func() { // If startAPIWorkers exits early with an error, stop the // runner so that any already started runners aren't leaked. if outErr != nil { worker.Stop(runner) } }() modelConfig, err := apiagent.NewState(apiConn).ModelConfig() if err != nil { return nil, fmt.Errorf("cannot read model config: %v", err) } // Perform the operations needed to set up hosting for containers. if err := a.setupContainerSupport(runner, apiConn, agentConfig); err != nil { cause := errors.Cause(err) if params.IsCodeDead(cause) || cause == worker.ErrTerminateAgent { return nil, worker.ErrTerminateAgent } return nil, fmt.Errorf("setting up container support: %v", err) } if isModelManager { // Published image metadata for some providers are in simple streams. // Providers that do not depend on simple streams do not need this worker. env, err := newEnvirons(modelConfig) if err != nil { return nil, errors.Annotate(err, "getting environ") } if _, ok := env.(simplestreams.HasRegion); ok { // Start worker that stores published image metadata in state. runner.StartWorker("imagemetadata", func() (worker.Worker, error) { return newMetadataUpdater(apiConn.MetadataUpdater()), nil }) } // We don't have instance info set and the network config for the // bootstrap machine only, so update it now. All the other machines will // have instance info including network config set at provisioning time. if err := a.setControllerNetworkConfig(apiConn); err != nil { return nil, errors.Annotate(err, "setting controller network config") } } else { runner.StartWorker("stateconverter", func() (worker.Worker, error) { // TODO(fwereade): this worker needs its own facade. facade := apimachiner.NewState(apiConn) handler := conv2state.New(facade, a) w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{ Handler: handler, }) if err != nil { return nil, errors.Annotate(err, "cannot start controller promoter worker") } return w, nil }) } return runner, nil }