func (a *UnitAgent) APIWorkers() (worker.Worker, error) { agentConfig := a.CurrentConfig() dataDir := agentConfig.DataDir() hookLock, err := hookExecutionLock(dataDir) if err != nil { return nil, err } st, entity, err := openAPIState(agentConfig, a) if err != nil { return nil, err } runner := worker.NewRunner(connectionIsFatal(st), moreImportant) runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.NewUpgrader(st.Upgrader(), agentConfig), nil }) runner.StartWorker("logger", func() (worker.Worker, error) { return workerlogger.NewLogger(st.Logger(), agentConfig), nil }) runner.StartWorker("uniter", func() (worker.Worker, error) { return uniter.NewUniter(st.Uniter(), entity.Tag(), dataDir, hookLock), nil }) runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) { return apiaddressupdater.NewAPIAddressUpdater(st.Uniter(), a), nil }) runner.StartWorker("rsyslog", func() (worker.Worker, error) { return newRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding) }) return newCloseWorker(runner, st), nil }
func (s *APIAddressUpdaterSuite) TestAddressChange(c *gc.C) { setter := &apiAddressSetter{servers: make(chan [][]network.HostPort, 1)} st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits) worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter) defer func() { c.Assert(worker.Wait(), gc.IsNil) }() defer worker.Kill() s.BackingState.StartSync() updatedServers := [][]network.HostPort{network.AddressesWithPort( network.NewAddresses("localhost", "127.0.0.1"), 1234, )} // SetAPIHostPorts should be called with the initial value (empty), // and then the updated value. select { case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for SetAPIHostPorts to be called first") case servers := <-setter.servers: c.Assert(servers, gc.HasLen, 0) } err := s.State.SetAPIHostPorts(updatedServers) c.Assert(err, gc.IsNil) s.BackingState.StartSync() select { case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for SetAPIHostPorts to be called second") case servers := <-setter.servers: c.Assert(servers, gc.DeepEquals, updatedServers) } }
func (s *APIAddressUpdaterSuite) TestStartStop(c *gc.C) { st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits) worker, err := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), &apiAddressSetter{}) c.Assert(err, jc.ErrorIsNil) worker.Kill() c.Assert(worker.Wait(), gc.IsNil) }
func (a *UnitAgent) APIWorkers() (worker.Worker, error) { agentConfig := a.CurrentConfig() dataDir := agentConfig.DataDir() hookLock, err := hookExecutionLock(dataDir) if err != nil { return nil, err } st, entity, err := openAPIState(agentConfig, a) if err != nil { return nil, err } // Before starting any workers, ensure we record the Juju version this unit // agent is running. currentTools := &tools.Tools{Version: version.Current} if err := st.Upgrader().SetVersion(agentConfig.Tag().String(), currentTools.Version); err != nil { return nil, errors.Annotate(err, "cannot set unit agent version") } runner := worker.NewRunner(connectionIsFatal(st), moreImportant) runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.NewUpgrader( st.Upgrader(), agentConfig, agentConfig.UpgradedToVersion(), func() bool { return false }, ), nil }) runner.StartWorker("logger", func() (worker.Worker, error) { return workerlogger.NewLogger(st.Logger(), agentConfig), nil }) runner.StartWorker("uniter", func() (worker.Worker, error) { return uniter.NewUniter(st.Uniter(), entity.Tag(), dataDir, hookLock), nil }) runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) { return apiaddressupdater.NewAPIAddressUpdater(st.Uniter(), a), nil }) runner.StartWorker("rsyslog", func() (worker.Worker, error) { return newRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding) }) return newCloseWorker(runner, st), nil }
func (s *APIAddressUpdaterSuite) TestAddressInitialUpdate(c *gc.C) { updatedServers := [][]network.HostPort{ network.NewHostPorts(1234, "localhost", "127.0.0.1"), } err := s.State.SetAPIHostPorts(updatedServers) c.Assert(err, jc.ErrorIsNil) setter := &apiAddressSetter{servers: make(chan [][]network.HostPort, 1)} st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits) worker := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter) defer func() { c.Assert(worker.Wait(), gc.IsNil) }() defer worker.Kill() // SetAPIHostPorts should be called with the initial value. select { case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for SetAPIHostPorts to be called") case servers := <-setter.servers: c.Assert(servers, gc.DeepEquals, updatedServers) } }
func (s *APIAddressUpdaterSuite) TestLXCBridgeAddressesFiltering(c *gc.C) { lxcFakeNetConfig := filepath.Join(c.MkDir(), "lxc-net") netConf := []byte(` # comments ignored LXC_BR= ignored LXC_ADDR = "fooo" LXC_BRIDGE="foobar" # detected anything else ignored LXC_BRIDGE="ignored"`[1:]) err := ioutil.WriteFile(lxcFakeNetConfig, netConf, 0644) c.Assert(err, jc.ErrorIsNil) s.PatchValue(&network.InterfaceByNameAddrs, func(name string) ([]net.Addr, error) { c.Assert(name, gc.Equals, "foobar") return []net.Addr{ &net.IPAddr{IP: net.IPv4(10, 0, 3, 1)}, &net.IPAddr{IP: net.IPv4(10, 0, 3, 4)}, }, nil }) s.PatchValue(&network.LXCNetDefaultConfig, lxcFakeNetConfig) initialServers := [][]network.HostPort{ network.NewHostPorts(1234, "localhost", "127.0.0.1"), network.NewHostPorts( 4321, "10.0.3.1", // filtered "10.0.3.3", // not filtered (not a lxc bridge address) ), network.NewHostPorts(4242, "10.0.3.4"), // filtered } err = s.State.SetAPIHostPorts(initialServers) c.Assert(err, jc.ErrorIsNil) setter := &apiAddressSetter{servers: make(chan [][]network.HostPort, 1)} st, _ := s.OpenAPIAsNewMachine(c, state.JobHostUnits) worker, err := apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), setter) c.Assert(err, jc.ErrorIsNil) defer func() { c.Assert(worker.Wait(), gc.IsNil) }() defer worker.Kill() s.BackingState.StartSync() updatedServers := [][]network.HostPort{ network.NewHostPorts(1234, "localhost", "127.0.0.1"), network.NewHostPorts( 4001, "10.0.3.1", // filtered "10.0.3.3", // not filtered (not a lxc bridge address) ), network.NewHostPorts(4200, "10.0.3.4"), // filtered } // SetAPIHostPorts should be called with the initial value, and // then the updated value, but filtering occurs in both cases. select { case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for SetAPIHostPorts to be called initially") case servers := <-setter.servers: c.Assert(servers, gc.HasLen, 2) c.Assert(servers, jc.DeepEquals, [][]network.HostPort{ network.NewHostPorts(1234, "localhost", "127.0.0.1"), network.NewHostPorts(4321, "10.0.3.3"), }) } err = s.State.SetAPIHostPorts(updatedServers) c.Assert(err, gc.IsNil) s.BackingState.StartSync() select { case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for SetAPIHostPorts to be called after update") case servers := <-setter.servers: c.Assert(servers, gc.HasLen, 2) c.Assert(servers, jc.DeepEquals, [][]network.HostPort{ network.NewHostPorts(1234, "localhost", "127.0.0.1"), network.NewHostPorts(4001, "10.0.3.3"), }) } }
func (a *UnitAgent) APIWorkers() (_ worker.Worker, err error) { agentConfig := a.CurrentConfig() dataDir := agentConfig.DataDir() hookLock, err := cmdutil.HookExecutionLock(dataDir) if err != nil { return nil, err } st, entity, err := OpenAPIState(agentConfig, a) if err != nil { return nil, err } unitTag, err := names.ParseUnitTag(entity.Tag()) if err != nil { return nil, errors.Trace(err) } // Ensure that the environment uuid is stored in the agent config. // Luckily the API has it recorded for us after we connect. if agentConfig.Environment().Id() == "" { err := a.ChangeConfig(func(setter agent.ConfigSetter) error { environTag, err := st.EnvironTag() if err != nil { return errors.Annotate(err, "no environment uuid set on api") } return setter.Migrate(agent.MigrateParams{ Environment: environTag, }) }) if err != nil { logger.Warningf("unable to save environment uuid: %v", err) // Not really fatal, just annoying. } } defer func() { if err != nil { st.Close() reportClosedUnitAPI(st) } }() // Before starting any workers, ensure we record the Juju version this unit // agent is running. currentTools := &tools.Tools{Version: version.Current} apiStateUpgrader := a.getUpgrader(st) if err := apiStateUpgrader.SetVersion(agentConfig.Tag().String(), currentTools.Version); err != nil { return nil, errors.Annotate(err, "cannot set unit agent version") } runner := worker.NewRunner(cmdutil.ConnectionIsFatal(logger, st), cmdutil.MoreImportant) // start proxyupdater first to ensure proxy settings are correct runner.StartWorker("proxyupdater", func() (worker.Worker, error) { return proxyupdater.New(st.Environment(), false), nil }) runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.NewAgentUpgrader( st.Upgrader(), agentConfig, agentConfig.UpgradedToVersion(), func() bool { return false }, a.initialAgentUpgradeCheckComplete, ), nil }) runner.StartWorker("logger", func() (worker.Worker, error) { return workerlogger.NewLogger(st.Logger(), agentConfig), nil }) runner.StartWorker("uniter", func() (worker.Worker, error) { uniterFacade, err := st.Uniter() if err != nil { return nil, errors.Trace(err) } uniterParams := uniter.UniterParams{ uniterFacade, unitTag, leadership.NewClient(st), dataDir, hookLock, uniter.NewMetricsTimerChooser(), uniter.NewUpdateStatusTimer(), } return uniter.NewUniter(&uniterParams), nil }) runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) { uniterFacade, err := st.Uniter() if err != nil { return nil, errors.Trace(err) } return apiaddressupdater.NewAPIAddressUpdater(uniterFacade, a), nil }) runner.StartWorker("rsyslog", func() (worker.Worker, error) { return cmdutil.NewRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding) }) return cmdutil.NewCloseWorker(logger, runner, st), nil }
// APIWorker returns a Worker that connects to the API and starts any // workers that need an API connection. func (a *MachineAgent) APIWorker() (worker.Worker, error) { agentConfig := a.CurrentConfig() st, entity, err := openAPIState(agentConfig, a) if err != nil { return nil, err } reportOpenedAPI(st) // Check if the network management is disabled. envConfig, err := st.Environment().EnvironConfig() if err != nil { return nil, fmt.Errorf("cannot read environment config: %v", err) } disableNetworkManagement, _ := envConfig.DisableNetworkManagement() if disableNetworkManagement { logger.Infof("network management is disabled") } // Refresh the configuration, since it may have been updated after opening state. agentConfig = a.CurrentConfig() for _, job := range entity.Jobs() { if job.NeedsState() { info, err := st.Agent().StateServingInfo() if err != nil { return nil, fmt.Errorf("cannot get state serving info: %v", err) } err = a.ChangeConfig(func(config agent.ConfigSetter) error { config.SetStateServingInfo(info) return nil }) if err != nil { return nil, err } agentConfig = a.CurrentConfig() break } } rsyslogMode := rsyslog.RsyslogModeForwarding runner := newRunner(connectionIsFatal(st), moreImportant) var singularRunner worker.Runner for _, job := range entity.Jobs() { if job == params.JobManageEnviron { rsyslogMode = rsyslog.RsyslogModeAccumulate conn := singularAPIConn{st, st.Agent()} singularRunner, err = newSingularRunner(runner, conn) if err != nil { return nil, fmt.Errorf("cannot make singular API Runner: %v", err) } break } } // Before starting any workers, ensure we record the Juju version this machine // agent is running. currentTools := &coretools.Tools{Version: version.Current} if err := st.Upgrader().SetVersion(agentConfig.Tag().String(), currentTools.Version); err != nil { return nil, errors.Annotate(err, "cannot set machine agent version") } providerType := agentConfig.Value(agent.ProviderType) // Run the upgrader and the upgrade-steps worker without waiting for // the upgrade steps to complete. runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.NewUpgrader( st.Upgrader(), agentConfig, a.previousAgentVersion, a.upgradeWorkerContext.IsUpgradeRunning, ), nil }) runner.StartWorker("upgrade-steps", func() (worker.Worker, error) { return a.upgradeWorkerContext.Worker(a, st, entity.Jobs()), nil }) // All other workers must wait for the upgrade steps to complete // before starting. a.startWorkerAfterUpgrade(runner, "machiner", func() (worker.Worker, error) { return machiner.NewMachiner(st.Machiner(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "apiaddressupdater", func() (worker.Worker, error) { return apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), a), nil }) a.startWorkerAfterUpgrade(runner, "logger", func() (worker.Worker, error) { return workerlogger.NewLogger(st.Logger(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "machineenvironmentworker", func() (worker.Worker, error) { return machineenvironmentworker.NewMachineEnvironmentWorker(st.Environment(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "rsyslog", func() (worker.Worker, error) { return newRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslogMode) }) // TODO (mfoord 8/8/2014) improve the way we detect networking capabilities. Bug lp:1354365 writeNetworkConfig := providerType == "maas" if disableNetworkManagement || !writeNetworkConfig { a.startWorkerAfterUpgrade(runner, "networker", func() (worker.Worker, error) { return newSafeNetworker(st.Networker(), agentConfig, networker.DefaultConfigDir) }) } else if !disableNetworkManagement && writeNetworkConfig { a.startWorkerAfterUpgrade(runner, "networker", func() (worker.Worker, error) { return newNetworker(st.Networker(), agentConfig, networker.DefaultConfigDir) }) } // If not a local provider bootstrap machine, start the worker to // manage SSH keys. if providerType != provider.Local || a.MachineId != bootstrapMachineId { a.startWorkerAfterUpgrade(runner, "authenticationworker", func() (worker.Worker, error) { return authenticationworker.NewWorker(st.KeyUpdater(), agentConfig), nil }) } // Perform the operations needed to set up hosting for containers. if err := a.setupContainerSupport(runner, st, entity, 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) } for _, job := range entity.Jobs() { switch job { case params.JobHostUnits: a.startWorkerAfterUpgrade(runner, "deployer", func() (worker.Worker, error) { apiDeployer := st.Deployer() context := newDeployContext(apiDeployer, agentConfig) return deployer.NewDeployer(apiDeployer, context), nil }) case params.JobManageEnviron: a.startWorkerAfterUpgrade(singularRunner, "environ-provisioner", func() (worker.Worker, error) { return provisioner.NewEnvironProvisioner(st.Provisioner(), agentConfig), nil }) // TODO(axw) 2013-09-24 bug #1229506 // Make another job to enable the firewaller. Not all // environments are capable of managing ports // centrally. a.startWorkerAfterUpgrade(singularRunner, "firewaller", func() (worker.Worker, error) { return firewaller.NewFirewaller(st.Firewaller()) }) a.startWorkerAfterUpgrade(singularRunner, "charm-revision-updater", func() (worker.Worker, error) { return charmrevisionworker.NewRevisionUpdateWorker(st.CharmRevisionUpdater()), nil }) case params.JobManageStateDeprecated: // Legacy environments may set this, but we ignore it. 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. }
// APIWorker returns a Worker that connects to the API and starts any // workers that need an API connection. func (a *MachineAgent) APIWorker() (worker.Worker, error) { agentConfig := a.CurrentConfig() st, entity, err := openAPIState(agentConfig, a) if err != nil { return nil, err } reportOpenedAPI(st) // Refresh the configuration, since it may have been updated after opening state. agentConfig = a.CurrentConfig() for _, job := range entity.Jobs() { if job.NeedsState() { info, err := st.Agent().StateServingInfo() if err != nil { return nil, fmt.Errorf("cannot get state serving info: %v", err) } err = a.ChangeConfig(func(config agent.ConfigSetter) { config.SetStateServingInfo(info) }) if err != nil { return nil, err } agentConfig = a.CurrentConfig() break } } rsyslogMode := rsyslog.RsyslogModeForwarding runner := newRunner(connectionIsFatal(st), moreImportant) var singularRunner worker.Runner for _, job := range entity.Jobs() { if job == params.JobManageEnviron { rsyslogMode = rsyslog.RsyslogModeAccumulate conn := singularAPIConn{st, st.Agent()} singularRunner, err = newSingularRunner(runner, conn) if err != nil { return nil, fmt.Errorf("cannot make singular API Runner: %v", err) } break } } // Run the upgrader and the upgrade-steps worker without waiting for // the upgrade steps to complete. runner.StartWorker("upgrader", func() (worker.Worker, error) { return upgrader.NewUpgrader(st.Upgrader(), agentConfig), nil }) runner.StartWorker("upgrade-steps", func() (worker.Worker, error) { return a.upgradeWorker(st, entity.Jobs(), agentConfig), nil }) // All other workers must wait for the upgrade steps to complete // before starting. a.startWorkerAfterUpgrade(runner, "machiner", func() (worker.Worker, error) { return machiner.NewMachiner(st.Machiner(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "apiaddressupdater", func() (worker.Worker, error) { return apiaddressupdater.NewAPIAddressUpdater(st.Machiner(), a), nil }) a.startWorkerAfterUpgrade(runner, "logger", func() (worker.Worker, error) { return workerlogger.NewLogger(st.Logger(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "machineenvironmentworker", func() (worker.Worker, error) { return machineenvironmentworker.NewMachineEnvironmentWorker(st.Environment(), agentConfig), nil }) a.startWorkerAfterUpgrade(runner, "rsyslog", func() (worker.Worker, error) { return newRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslogMode) }) // If not a local provider bootstrap machine, start the worker to // manage SSH keys. providerType := agentConfig.Value(agent.ProviderType) if providerType != provider.Local || a.MachineId != bootstrapMachineId { a.startWorkerAfterUpgrade(runner, "authenticationworker", func() (worker.Worker, error) { return authenticationworker.NewWorker(st.KeyUpdater(), agentConfig), nil }) } // Perform the operations needed to set up hosting for containers. if err := a.setupContainerSupport(runner, st, entity, agentConfig); err != nil { return nil, fmt.Errorf("setting up container support: %v", err) } for _, job := range entity.Jobs() { switch job { case params.JobHostUnits: a.startWorkerAfterUpgrade(runner, "deployer", func() (worker.Worker, error) { apiDeployer := st.Deployer() context := newDeployContext(apiDeployer, agentConfig) return deployer.NewDeployer(apiDeployer, context), nil }) case params.JobManageEnviron: a.startWorkerAfterUpgrade(singularRunner, "environ-provisioner", func() (worker.Worker, error) { return provisioner.NewEnvironProvisioner(st.Provisioner(), agentConfig), nil }) // TODO(axw) 2013-09-24 bug #1229506 // Make another job to enable the firewaller. Not all // environments are capable of managing ports // centrally. a.startWorkerAfterUpgrade(singularRunner, "firewaller", func() (worker.Worker, error) { return firewaller.NewFirewaller(st.Firewaller()) }) a.startWorkerAfterUpgrade(singularRunner, "charm-revision-updater", func() (worker.Worker, error) { return charmrevisionworker.NewRevisionUpdateWorker(st.CharmRevisionUpdater()), nil }) case params.JobManageStateDeprecated: // Legacy environments may set this, but we ignore it. 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. }