示例#1
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)
	}
}
示例#2
0
文件: worker.go 项目: bac/juju
// NewLock creates a gate.Lock to be used to synchronise workers which
// need to start after upgrades have completed. If no upgrade steps
// are required the Lock is unlocked and the version in agent's
// configuration is updated to the currently running version.
//
// The returned Lock should be passed to NewWorker.
func NewLock(a agent.Agent) (gate.Lock, error) {
	lock := gate.NewLock()

	if wrench.IsActive("machine-agent", "always-try-upgrade") {
		// Always enter upgrade mode. This allows test of upgrades
		// even when there's actually no upgrade steps to run.
		return lock, nil
	}

	err := a.ChangeConfig(func(agentConfig agent.ConfigSetter) error {
		if !upgrades.AreUpgradesDefined(agentConfig.UpgradedToVersion()) {
			logger.Infof("no upgrade steps required or upgrade steps for %v "+
				"have already been run.", jujuversion.Current)
			lock.Unlock()

			// Even if no upgrade is required the version number in
			// the agent's config still needs to be bumped.
			agentConfig.SetUpgradedToVersion(jujuversion.Current)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return lock, nil
}
示例#3
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
		},
	}
}
示例#4
0
文件: open.go 项目: exekias/juju
func setAgentPassword(newPw, oldPw string, a agent.Agent, entity *apiagent.Entity) error {
	// Change the configuration *before* setting the entity
	// password, so that we avoid the possibility that
	// we might successfully change the entity's
	// password but fail to write the configuration,
	// thus locking us out completely.
	if err := a.ChangeConfig(func(c agent.ConfigSetter) error {
		c.SetPassword(newPw)
		c.SetOldPassword(oldPw)
		return nil
	}); err != nil {
		return err
	}
	return entity.SetPassword(newPw)
}
示例#5
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)
}
示例#6
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.
		}
	}
}
示例#7
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)
	}
}
示例#8
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
			}
			existing, hasInfo := agent.CurrentConfig().StateServingInfo()
			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)
					}
					if hasInfo {
						// Use the existing Cert as it may have been updated already
						// by the cert updater worker to have this machine's IP address
						// as part of the cert. This changed cert is never put back into
						// the database, so it isn't reflected in the copy we have got
						// from apiState.
						info.Cert = existing.Cert
					}
					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
		},
	}
}
示例#9
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.
			if controller, err := isController(apiState, tag); err != nil {
				return nil, errors.Annotate(err, "checking controller status")
			} else if !controller {
				// Not a controller, nothing to do.
				return nil, dependency.ErrUninstall
			}

			info, err := apiState.StateServingInfo()
			if err != nil {
				return nil, errors.Annotate(err, "getting state serving info")
			}
			err = agent.ChangeConfig(func(config coreagent.ConfigSetter) error {
				existing, hasInfo := config.StateServingInfo()
				if hasInfo {
					// Use the existing cert and key as they appear to
					// have been already updated by the cert updater
					// worker to have this machine's IP address as
					// part of the cert. This changed cert is never
					// put back into the database, so it isn't
					// reflected in the copy we have got from
					// apiState.
					info.Cert = existing.Cert
					info.PrivateKey = existing.PrivateKey
				}
				config.SetStateServingInfo(info)
				return nil
			})
			if err != nil {
				return nil, errors.Trace(err)
			}

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