Ejemplo n.º 1
0
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	w, err := NewWorker(keyupdater.NewState(apiCaller), a.CurrentConfig())
	if err != nil {
		return nil, errors.Annotate(err, "cannot start ssh auth-keys updater worker")
	}
	return w, nil
}
Ejemplo n.º 2
0
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	cfg := a.CurrentConfig()
	// Grab the tag and ensure that it's for a machine.
	tag, ok := cfg.Tag().(names.MachineTag)
	if !ok {
		return nil, errors.New("this manifold may only be used inside a machine agent")
	}

	// Get the machine agent's jobs.
	// TODO(fwereade): this functionality should be on the
	// deployer facade instead.
	agentFacade := apiagent.NewState(apiCaller)
	entity, err := agentFacade.Entity(tag)
	if err != nil {
		return nil, err
	}

	var isModelManager bool
	for _, job := range entity.Jobs() {
		if job == multiwatcher.JobManageModel {
			isModelManager = true
			break
		}
	}
	if !isModelManager {
		return nil, dependency.ErrMissing
	}

	return NewResumer(apiresumer.NewAPI(apiCaller)), nil
}
Ejemplo n.º 3
0
// Manifold returns a dependency.Manifold which wraps the machine
// agent's voyeur.Value which gets set whenever it the machine agent's
// config is changed. Whenever the config is updated the presence of
// state serving info is checked and if state serving info was added
// or removed the manifold worker will bounce itself.
//
// The manifold offes a single boolean output which will be true if
// state serving info is available (i.e. the machine agent should be a
// state server) and false otherwise.
//
// This manifold is intended to be used as a dependency for the state
// manifold.
func Manifold(config ManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{config.AgentName},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {
			var a agent.Agent
			if err := getResource(config.AgentName, &a); err != nil {
				return nil, err
			}

			if config.AgentConfigChanged == nil {
				return nil, errors.NotValidf("nil AgentConfigChanged")
			}

			if _, ok := a.CurrentConfig().Tag().(names.MachineTag); !ok {
				return nil, errors.New("manifold can only be used with a machine agent")
			}

			w := &stateConfigWatcher{
				agent:              a,
				agentConfigChanged: config.AgentConfigChanged,
			}
			go func() {
				defer w.tomb.Done()
				w.tomb.Kill(w.loop())
			}()
			return w, nil
		},
		Output: outputFunc,
	}
}
Ejemplo n.º 4
0
func (config MachineManifoldConfig) newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	if config.Clock == nil {
		return nil, dependency.ErrMissing
	}

	cfg := a.CurrentConfig()
	api, err := storageprovisioner.NewState(apiCaller, cfg.Tag())
	if err != nil {
		return nil, errors.Trace(err)
	}

	tag, ok := cfg.Tag().(names.MachineTag)
	if !ok {
		return nil, errors.Errorf("this manifold may only be used inside a machine agent")
	}

	storageDir := filepath.Join(cfg.DataDir(), "storage")
	w, err := NewStorageProvisioner(Config{
		Scope:       tag,
		StorageDir:  storageDir,
		Volumes:     api,
		Filesystems: api,
		Life:        api,
		Registry:    provider.CommonStorageProviders(),
		Machines:    api,
		Status:      api,
		Clock:       config.Clock,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return w, nil
}
Ejemplo n.º 5
0
Archivo: manifold.go Proyecto: bac/juju
// newWorker trivially wraps NewWorker for use in a engine.AgentAPIManifold.
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	cfg := a.CurrentConfig()

	// Grab the tag and ensure that it's for a machine.
	tag, ok := cfg.Tag().(names.MachineTag)
	if !ok {
		return nil, errors.New("this manifold may only be used inside a machine agent")
	}

	// Get the machine agent's jobs.
	entity, err := apiagent.NewState(apiCaller).Entity(tag)
	if err != nil {
		return nil, err
	}

	var isModelManager bool
	for _, job := range entity.Jobs() {
		if job == multiwatcher.JobManageModel {
			isModelManager = true
			break
		}
	}

	if !isModelManager {
		return nil, dependency.ErrMissing
	}

	return NewWorker(cfg)
}
Ejemplo n.º 6
0
// startFunc returns a StartFunc that creates a worker based on the manifolds
// named in the supplied config.
func startFunc(config ManifoldConfig) dependency.StartFunc {
	return func(getResource dependency.GetResourceFunc) (worker.Worker, error) {

		// Get dependencies and open a connection.
		var a agent.Agent
		if err := getResource(config.AgentName, &a); err != nil {
			return nil, err
		}
		conn, err := openConnection(a)
		if err != nil {
			return nil, errors.Annotate(err, "cannot open api")
		}

		// Add the environment uuid to agent config if not present.
		currentConfig := a.CurrentConfig()
		if currentConfig.Environment().Id() == "" {
			err := a.ChangeConfig(func(setter agent.ConfigSetter) error {
				environTag, err := conn.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.
			}
		}

		// Return the worker.
		return newApiConnWorker(conn)
	}
}
Ejemplo n.º 7
0
// newWorker creates a degenerate worker that provides access to an fslock.
func newWorker(a agent.Agent) (worker.Worker, error) {
	dataDir := a.CurrentConfig().DataDir()
	lock, err := createLock(dataDir)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return util.NewValueWorker(lock)
}
Ejemplo n.º 8
0
func getAPIAddresses(a agent.Agent) []string {
	config := a.CurrentConfig()
	addrs, err := config.APIAddresses()
	if err != nil {
		logger.Errorf("retrieving API addresses: %s", err)
		addrs = nil
	}
	sort.Strings(addrs)
	return addrs
}
Ejemplo n.º 9
0
Archivo: manifold.go Proyecto: bac/juju
// Manifold returns a manifold whose worker which wraps a
// *state.State, which is in turn wrapper by a StateTracker.  It will
// exit if the State's associated mongodb session dies.
func Manifold(config ManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.AgentName,
			config.StateConfigWatcherName,
		},
		Start: func(context dependency.Context) (worker.Worker, error) {
			// First, a sanity check.
			if config.OpenState == nil {
				return nil, errors.New("OpenState is nil in config")
			}

			// Get the agent.
			var agent coreagent.Agent
			if err := context.Get(config.AgentName, &agent); err != nil {
				return nil, err
			}

			// Confirm we're running in a state server by asking the
			// stateconfigwatcher manifold.
			var haveStateConfig bool
			if err := context.Get(config.StateConfigWatcherName, &haveStateConfig); err != nil {
				return nil, err
			}
			if !haveStateConfig {
				return nil, dependency.ErrMissing
			}

			st, err := config.OpenState(agent.CurrentConfig())
			if err != nil {
				return nil, errors.Trace(err)
			}
			stTracker := newStateTracker(st)

			pingInterval := config.PingInterval
			if pingInterval == 0 {
				pingInterval = defaultPingInterval
			}

			w := &stateWorker{
				stTracker:    stTracker,
				pingInterval: pingInterval,
			}
			go func() {
				defer w.tomb.Done()
				w.tomb.Kill(w.loop())
				if err := stTracker.Done(); err != nil {
					logger.Errorf("error releasing state: %v", err)
				}
			}()
			return w, nil
		},
		Output: outputFunc,
	}
}
Ejemplo n.º 10
0
// newWorker trivially wraps NewWorker for use in a engine.AgentApiManifold.
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	t := a.CurrentConfig().Tag()
	tag, ok := t.(names.MachineTag)
	if !ok {
		return nil, errors.Errorf("expected MachineTag, got %#v", t)
	}

	api := apidiskmanager.NewState(apiCaller, tag)

	return NewWorker(DefaultListBlockDevices, api), nil
}
Ejemplo n.º 11
0
// OnlyConnect logs into the API using the supplied agent's credentials.
func OnlyConnect(a agent.Agent, apiOpen api.OpenFunc) (api.Connection, error) {
	agentConfig := a.CurrentConfig()
	info, ok := agentConfig.APIInfo()
	if !ok {
		return nil, errors.New("API info not available")
	}
	conn, _, err := connectFallback(apiOpen, info, agentConfig.OldPassword())
	if err != nil {
		return nil, errors.Trace(err)
	}
	return conn, nil
}
Ejemplo n.º 12
0
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	apiConn, ok := apiCaller.(api.Connection)
	if !ok {
		return nil, errors.New("unable to obtain api.Connection")
	}

	w, err := NewWorker(keyupdater.NewState(apiConn), a.CurrentConfig())
	if err != nil {
		return nil, errors.Annotate(err, "cannot start ssh auth-keys updater worker")
	}
	return w, nil
}
Ejemplo n.º 13
0
// ServingInfoSetterManifold defines a simple start function which
// runs after the API connection has come up. If the machine agent is
// a controller, it grabs the state serving info over the API and
// records it to agent configuration, and then stops.
func ServingInfoSetterManifold(config ServingInfoSetterConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.AgentName,
			config.APICallerName,
		},
		Start: func(context dependency.Context) (worker.Worker, error) {
			// Get the agent.
			var agent coreagent.Agent
			if err := context.Get(config.AgentName, &agent); err != nil {
				return nil, err
			}

			// Grab the tag and ensure that it's for a machine.
			tag, ok := agent.CurrentConfig().Tag().(names.MachineTag)
			if !ok {
				return nil, errors.New("agent's tag is not a machine tag")
			}

			// Get API connection.
			var apiCaller base.APICaller
			if err := context.Get(config.APICallerName, &apiCaller); err != nil {
				return nil, err
			}
			apiState := apiagent.NewState(apiCaller)

			// If the machine needs State, grab the state serving info
			// over the API and write it to the agent configuration.
			machine, err := apiState.Entity(tag)
			if err != nil {
				return nil, err
			}
			for _, job := range machine.Jobs() {
				if job.NeedsState() {
					info, err := apiState.StateServingInfo()
					if err != nil {
						return nil, errors.Errorf("cannot get state serving info: %v", err)
					}
					err = agent.ChangeConfig(func(config coreagent.ConfigSetter) error {
						config.SetStateServingInfo(info)
						return nil
					})
					if err != nil {
						return nil, err
					}
				}
			}

			// All is well - we're done (no actual worker is actually returned).
			return nil, dependency.ErrUninstall
		},
	}
}
Ejemplo n.º 14
0
// start is used by util.AgentApiManifold to create a StartFunc.
func (config ManifoldConfig) start(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	machineTag, ok := a.CurrentConfig().Tag().(names.MachineTag)
	if !ok {
		return nil, errors.Errorf("this manifold can only be used inside a machine")
	}
	machineActionsFacade := config.NewFacade(apiCaller)
	return config.NewWorker(WorkerConfig{
		Facade:       machineActionsFacade,
		MachineTag:   machineTag,
		HandleAction: HandleAction,
	})
}
Ejemplo n.º 15
0
// newWorker creates a degenerate worker that provides access to the metrics
// spool directory path.
func newWorker(a agent.Agent) (worker.Worker, error) {
	metricsSpoolDir := a.CurrentConfig().MetricsSpoolDir()
	err := checkSpoolDir(metricsSpoolDir)
	if err != nil {
		return nil, errors.Annotatef(err, "error checking spool directory %q", metricsSpoolDir)
	}
	w := &spoolWorker{factory: newFactory(metricsSpoolDir)}
	go func() {
		defer w.tomb.Done()
		<-w.tomb.Dying()
	}()
	return w, nil
}
Ejemplo n.º 16
0
// newWorker is not currently tested; it should eventually replace New as the
// package's exposed factory func, and then all tests should pass through it.
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	agentConfig := a.CurrentConfig()
	switch tag := agentConfig.Tag().(type) {
	case names.MachineTag, names.UnitTag:
	default:
		return nil, errors.Errorf("unknown agent type: %T", tag)
	}

	// TODO(fwereade): This shouldn't be an "environment" facade, it
	// should be specific to the proxyupdater, and be watching for
	// *proxy settings* changes, not just watching the "environment".
	return NewWorker(proxyupdater.NewFacade(apiCaller))
}
Ejemplo n.º 17
0
Archivo: manifold.go Proyecto: bac/juju
func (mc ManifoldConfig) start(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	agentTag := a.CurrentConfig().Tag()
	retryStrategyFacade := mc.NewFacade(apiCaller)
	initialRetryStrategy, err := retryStrategyFacade.RetryStrategy(agentTag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return mc.NewWorker(WorkerConfig{
		Facade:        retryStrategyFacade,
		AgentTag:      agentTag,
		RetryStrategy: initialRetryStrategy,
	})
}
Ejemplo n.º 18
0
Archivo: manifold.go Proyecto: bac/juju
// isModelManager returns whether the agent has JobManageModel,
// or an error.
func isModelManager(a agent.Agent, apiCaller base.APICaller) (bool, error) {
	agentFacade := apiagent.NewState(apiCaller)
	entity, err := agentFacade.Entity(a.CurrentConfig().Tag())
	if err != nil {
		return false, errors.Trace(err)
	}
	for _, job := range entity.Jobs() {
		if job == multiwatcher.JobManageModel {
			return true, nil
		}
	}
	return false, nil
}
Ejemplo n.º 19
0
func newStatusWorker(config ManifoldConfig, getResource dependency.GetResourceFunc) (worker.Worker, error) {
	var agent agent.Agent
	if err := getResource(config.AgentName, &agent); err != nil {
		return nil, err
	}

	var machineLock *fslock.Lock
	if err := getResource(config.MachineLockName, &machineLock); err != nil {
		return nil, err
	}

	tag := agent.CurrentConfig().Tag()
	unitTag, ok := tag.(names.UnitTag)
	if !ok {
		return nil, errors.Errorf("expected unit tag, got %v", tag)
	}

	agentConfig := agent.CurrentConfig()
	stateFile := NewStateFile(path.Join(agentConfig.DataDir(), "meter-status.yaml"))
	runner := config.NewHookRunner(unitTag, machineLock, agentConfig)

	// If we don't have a valid APICaller, start a meter status
	// worker that works without an API connection.
	var apiCaller base.APICaller
	err := getResource(config.APICallerName, &apiCaller)
	if errors.Cause(err) == dependency.ErrMissing {
		logger.Tracef("API caller dependency not available, starting isolated meter status worker.")
		cfg := IsolatedConfig{
			Runner:           runner,
			StateFile:        stateFile,
			Clock:            clock.WallClock,
			AmberGracePeriod: defaultAmberGracePeriod,
			RedGracePeriod:   defaultRedGracePeriod,
			TriggerFactory:   GetTriggers,
		}
		return config.NewIsolatedStatusWorker(cfg)
	} else if err != nil {
		return nil, err
	}
	logger.Tracef("Starting connected meter status worker.")
	status := config.NewMeterStatusAPIClient(apiCaller, unitTag)

	cfg := ConnectedConfig{
		Runner:    runner,
		StateFile: stateFile,
		Status:    status,
	}
	return config.NewConnectedStatusWorker(cfg)

}
Ejemplo n.º 20
0
Archivo: manifold.go Proyecto: bac/juju
// Manifold returns a dependency manifold that runs an upgrader
// worker, using the resource names defined in the supplied config.
func Manifold(config ManifoldConfig) dependency.Manifold {
	inputs := []string{
		config.AgentName,
		config.APICallerName,
	}
	// The machine agent uses these but the unit agent doesn't.
	if config.UpgradeStepsGateName != "" {
		inputs = append(inputs, config.UpgradeStepsGateName)
	}
	if config.UpgradeCheckGateName != "" {
		inputs = append(inputs, config.UpgradeCheckGateName)
	}

	return dependency.Manifold{
		Inputs: inputs,
		Start: func(context dependency.Context) (worker.Worker, error) {

			var agent agent.Agent
			if err := context.Get(config.AgentName, &agent); err != nil {
				return nil, err
			}
			currentConfig := agent.CurrentConfig()

			var apiCaller base.APICaller
			if err := context.Get(config.APICallerName, &apiCaller); err != nil {
				return nil, err
			}
			upgraderFacade := upgrader.NewState(apiCaller)

			var upgradeStepsWaiter gate.Waiter
			if config.UpgradeStepsGateName == "" {
				upgradeStepsWaiter = gate.NewLock()
			} else {
				if config.PreviousAgentVersion == version.Zero {
					return nil, errors.New("previous agent version not specified")
				}
				if err := context.Get(config.UpgradeStepsGateName, &upgradeStepsWaiter); err != nil {
					return nil, err
				}
			}

			var initialCheckUnlocker gate.Unlocker
			if config.UpgradeCheckGateName == "" {
				initialCheckUnlocker = gate.NewLock()
			} else {
				if err := context.Get(config.UpgradeCheckGateName, &initialCheckUnlocker); err != nil {
					return nil, err
				}
			}

			return NewAgentUpgrader(
				upgraderFacade,
				currentConfig,
				config.PreviousAgentVersion,
				upgradeStepsWaiter,
				initialCheckUnlocker,
			)
		},
	}
}
Ejemplo n.º 21
0
// start is a method on ManifoldConfig because it's more readable than a closure.
func (config ManifoldConfig) start(getResource dependency.GetResourceFunc) (worker.Worker, error) {
	var clock clock.Clock
	if err := getResource(config.ClockName, &clock); err != nil {
		return nil, errors.Trace(err)
	}
	var apiCaller base.APICaller
	if err := getResource(config.APICallerName, &apiCaller); err != nil {
		return nil, errors.Trace(err)
	}
	var agent agent.Agent
	if err := getResource(config.AgentName, &agent); err != nil {
		return nil, errors.Trace(err)
	}
	agentTag := agent.CurrentConfig().Tag()
	machineTag, ok := agentTag.(names.MachineTag)
	if !ok {
		return nil, errors.New("singular flag expected a machine agent")
	}

	// TODO(fwereade): model id is implicit in apiCaller, would
	// be better if explicit.
	facade, err := config.NewFacade(apiCaller, machineTag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	flag, err := config.NewWorker(FlagConfig{
		Clock:    clock,
		Facade:   facade,
		Duration: config.Duration,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return flag, nil
}
Ejemplo n.º 22
0
Archivo: worker.go Proyecto: bac/juju
// NewWorker returns a new instance of the upgradesteps worker. It
// will run any required steps to upgrade to the currently running
// Juju version.
func NewWorker(
	upgradeComplete gate.Lock,
	agent agent.Agent,
	apiConn api.Connection,
	jobs []multiwatcher.MachineJob,
	openState func() (*state.State, error),
	preUpgradeSteps func(st *state.State, agentConf agent.Config, isController, isMasterServer bool) error,
	machine StatusSetter,
) (worker.Worker, error) {
	tag, ok := agent.CurrentConfig().Tag().(names.MachineTag)
	if !ok {
		return nil, errors.New("machine agent's tag is not a MachineTag")
	}
	w := &upgradesteps{
		upgradeComplete: upgradeComplete,
		agent:           agent,
		apiConn:         apiConn,
		jobs:            jobs,
		openState:       openState,
		preUpgradeSteps: preUpgradeSteps,
		machine:         machine,
		tag:             tag,
	}
	go func() {
		defer w.tomb.Done()
		w.tomb.Kill(w.run())
	}()
	return w, nil
}
Ejemplo n.º 23
0
// changePassword generates a new random password and records it in
// local agent configuration and on the remote state server. The supplied
// oldPassword -- which must be the current valid password -- is set as a
// fallback in local config, in case we fail to update the remote password.
func changePassword(oldPassword string, a agent.Agent, facade apiagent.ConnFacade) error {
	newPassword, err := utils.RandomPassword()
	if err != nil {
		return errors.Trace(err)
	}
	if err := a.ChangeConfig(func(c agent.ConfigSetter) error {
		c.SetPassword(newPassword)
		c.SetOldPassword(oldPassword)
		return nil
	}); err != nil {
		return err
	}
	// This has to happen *after* we record the old/new passwords
	// locally, lest we change it remotely, crash suddenly, and
	// end up locked out forever.
	return facade.SetPassword(a.CurrentConfig().Tag(), newPassword)
}
Ejemplo n.º 24
0
// maybeSetAgentModelTag tries to update the agent configuration if
// it's missing a model tag. It doesn't *really* matter if it fails,
// because we can demonstrably connect without it, so we log any
// errors encountered and never return any to the client.
func maybeSetAgentModelTag(a agent.Agent, conn api.Connection) {
	if a.CurrentConfig().Model().Id() == "" {
		err := a.ChangeConfig(func(setter agent.ConfigSetter) error {
			modelTag, err := conn.ModelTag()
			if err != nil {
				return errors.Annotate(err, "no model uuid set on api")
			}
			return setter.Migrate(agent.MigrateParams{
				Model: modelTag,
			})
		})
		if err != nil {
			logger.Warningf("unable to save model uuid: %v", err)
			// Not really fatal, just annoying.
		}
	}
}
Ejemplo n.º 25
0
// Manifold returns a dependency manifold that runs a uniter worker,
// using the resource names defined in the supplied config.
func Manifold(config ManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.AgentName,
			config.APICallerName,
			config.LeadershipTrackerName,
			config.MachineLockName,
			config.CharmDirName,
		},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {

			// Collect all required resources.
			var agent agent.Agent
			if err := getResource(config.AgentName, &agent); err != nil {
				return nil, err
			}
			var apiCaller base.APICaller
			if err := getResource(config.APICallerName, &apiCaller); err != nil {
				// TODO(fwereade): absence of an APICaller shouldn't be the end of
				// the world -- we ought to return a type that can at least run the
				// leader-deposed hook -- but that's not done yet.
				return nil, err
			}
			var machineLock *fslock.Lock
			if err := getResource(config.MachineLockName, &machineLock); err != nil {
				return nil, err
			}
			var leadershipTracker leadership.Tracker
			if err := getResource(config.LeadershipTrackerName, &leadershipTracker); err != nil {
				return nil, err
			}
			var charmDirGuard fortress.Guard
			if err := getResource(config.CharmDirName, &charmDirGuard); err != nil {
				return nil, err
			}

			// Configure and start the uniter.
			config := agent.CurrentConfig()
			tag := config.Tag()
			unitTag, ok := tag.(names.UnitTag)
			if !ok {
				return nil, errors.Errorf("expected a unit tag, got %v", tag)
			}
			uniterFacade := uniter.NewState(apiCaller, unitTag)
			return NewUniter(&UniterParams{
				UniterFacade:         uniterFacade,
				UnitTag:              unitTag,
				LeadershipTracker:    leadershipTracker,
				DataDir:              config.DataDir(),
				MachineLock:          machineLock,
				CharmDirGuard:        charmDirGuard,
				UpdateStatusSignal:   NewUpdateStatusTimer(),
				NewOperationExecutor: operation.NewExecutor,
				Clock:                clock.WallClock,
			}), nil
		},
	}
}
Ejemplo n.º 26
0
// startFunc returns a StartFunc that creates a worker based on the manifolds
// named in the supplied config.
func startFunc(config ManifoldConfig) dependency.StartFunc {
	return func(getResource dependency.GetResourceFunc) (worker.Worker, error) {

		// Get dependencies and open a connection.
		var gate gate.Unlocker
		if err := getResource(config.APIInfoGateName, &gate); err != nil {
			return nil, err
		}
		var a agent.Agent
		if err := getResource(config.AgentName, &a); err != nil {
			return nil, err
		}
		conn, err := openConnection(a)
		if err != nil {
			return nil, errors.Annotate(err, "cannot open api")
		}

		// Add the environment uuid to agent config if not present.
		currentConfig := a.CurrentConfig()
		if currentConfig.Environment().Id() == "" {
			err := a.ChangeConfig(func(setter agent.ConfigSetter) error {
				environTag, err := conn.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.
			}
		}

		// Now we know the agent config has been fixed up, notify everyone
		// else who might depend upon its stability/correctness.
		gate.Unlock()

		// Return the worker.
		return newApiConnWorker(conn)
	}
}
Ejemplo n.º 27
0
// newWorker trivially wraps NewReboot for use in a util.PostUpgradeManifold.
//
// TODO(mjs) - It's not tested at the moment, because the scaffolding
// necessary is too unwieldy/distracting to introduce at this point.
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	apiConn, ok := apiCaller.(api.Connection)
	if !ok {
		return nil, errors.New("unable to obtain api.Connection")
	}
	rebootState, err := apiConn.Reboot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	lock, err := cmdutil.HookExecutionLock(cmdutil.DataDir)
	if err != nil {
		return nil, errors.Trace(err)
	}
	w, err := NewReboot(rebootState, a.CurrentConfig(), lock)
	if err != nil {
		return nil, errors.Annotate(err, "cannot start reboot worker")
	}
	return w, nil
}
Ejemplo n.º 28
0
// newWorker is not currently tested; it should eventually replace New as the
// package's exposed factory func, and then all tests should pass through it.
func newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
	agentConfig := a.CurrentConfig()
	switch tag := agentConfig.Tag().(type) {
	case names.MachineTag, names.UnitTag:
	default:
		return nil, errors.Errorf("unknown agent type: %T", tag)
	}

	proxyAPI, err := proxyupdater.NewAPI(apiCaller, agentConfig.Tag())
	if err != nil {
		return nil, err
	}
	return NewWorker(Config{
		Directory:    "/home/ubuntu",
		RegistryPath: `HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings`,
		Filename:     ".juju-proxy",
		API:          proxyAPI,
	})
}
Ejemplo n.º 29
0
// New starts a logsender worker which reads log message structs from
// a channel and sends them to the JES via the logsink API.
func New(logs LogRecordCh, apiInfoGate gate.Waiter, agent agent.Agent) worker.Worker {
	loop := func(stop <-chan struct{}) error {
		logger.Debugf("started log-sender worker; waiting for api info")
		select {
		case <-apiInfoGate.Unlocked():
		case <-stop:
			return nil
		}

		logger.Debugf("dialing log-sender connection")
		apiInfo := agent.CurrentConfig().APIInfo()
		conn, err := dialLogsinkAPI(apiInfo)
		if err != nil {
			return errors.Annotate(err, "logsender dial failed")
		}
		defer conn.Close()

		for {
			select {
			case rec := <-logs:
				err := sendLogRecord(conn, rec.Time, rec.Module, rec.Location, rec.Level, rec.Message)
				if err != nil {
					return errors.Trace(err)
				}
				if rec.DroppedAfter > 0 {
					// If messages were dropped after this one, report
					// the count (the source of the log messages -
					// BufferedLogWriter - handles the actual dropping
					// and counting).
					//
					// Any logs indicated as dropped here are will
					// never end up in the logs DB in the JES
					// (although will still be in the local agent log
					// file). Message dropping by the
					// BufferedLogWriter is last resort protection
					// against memory exhaustion and should only
					// happen if API connectivity is lost for extended
					// periods. The maximum in-memory log buffer is
					// quite large (see the InstallBufferedLogWriter
					// call in jujuDMain).
					err := sendLogRecord(conn, rec.Time, loggerName, "", loggo.WARNING,
						fmt.Sprintf("%d log messages dropped due to lack of API connectivity", rec.DroppedAfter))
					if err != nil {
						return errors.Trace(err)
					}
				}

			case <-stop:
				return nil
			}
		}
	}
	return worker.NewSimpleWorker(loop)
}
Ejemplo n.º 30
0
// uninstallerManifold defines a simple start function which retrieves
// some dependencies, checks if the machine is dead and causes the
// agent to uninstall itself if it is. This doubles up on part of the
// machiner's functionality but the machiner doesn't run until
// upgrades are complete, and the upgrade related workers may not be
// able to make API requests if the machine is dead.
func uninstallerManifold(config uninstallerManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.AgentName,
			config.APICallerName,
		},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {
			if config.WriteUninstallFile == nil {
				return nil, errors.New("WriteUninstallFile not specified")
			}

			// Get the agent.
			var agent agent.Agent
			if err := getResource(config.AgentName, &agent); err != nil {
				return nil, err
			}

			// Grab the tag and ensure that it's for a machine.
			tag, ok := agent.CurrentConfig().Tag().(names.MachineTag)
			if !ok {
				return nil, errors.New("agent's tag is not a machine tag")
			}

			// Get API connection.
			//
			// TODO(mjs) - this should really be a base.APICaller to
			// remove the possibility of the API connection being closed
			// here.
			var apiConn api.Connection
			if err := getResource(config.APICallerName, &apiConn); err != nil {
				return nil, err
			}

			// Check if the machine is dead and set the agent to
			// uninstall if it is.
			//
			// TODO(mjs) - ideally this would be using its own facade.
			machine, err := apiConn.Agent().Entity(tag)
			if err != nil {
				return nil, err
			}
			if machine.Life() == params.Dead {
				if err := config.WriteUninstallFile(); err != nil {
					return nil, errors.Annotate(err, "writing uninstall agent file")
				}
				return nil, worker.ErrTerminateAgent
			}

			// All is well - we're done (no actual worker is actually returned).
			return nil, dependency.ErrUninstall
		},
	}
}