// WaitForEnviron waits for an valid environment to arrive from the given // watcher. It terminates with ErrWaitAborted if it receives a value on abort. // // In practice, it shouldn't wait at all: juju *should* never deliver invalid // environ configs. Regardless, it should be considered deprecated; clients // should prefer to access an Environ via a shared Tracker. // // It never takes responsibility for the supplied watcher; the client remains // responsible for detecting and handling any watcher errors that may occur, // whether this func succeeds or fails. func WaitForEnviron( // TODO(wallyworld) - pass in credential watcher w watcher.NotifyWatcher, getter environs.EnvironConfigGetter, newEnviron environs.NewEnvironFunc, abort <-chan struct{}, ) (environs.Environ, error) { for { select { case <-abort: return nil, ErrWaitAborted case _, ok := <-w.Changes(): if !ok { return nil, errors.New("environ config watch closed") } // First check the model config is valid as we want to exit with // an error if we have received a config but it is not valid. // This distinguishes from the case where environ construction fails // because no config has been received yet. if _, err := getter.ModelConfig(); err != nil { return nil, errors.Annotate(err, "cannot read environ config") } environ, err := environs.GetEnviron(getter, newEnviron) if err == nil { return environ, nil } logger.Errorf("loaded invalid environment configuration: %v", err) } } }
// zonedEnviron returns a providercommon.ZonedEnviron instance from the current // model config. If the model does not support zones, an error satisfying // errors.IsNotSupported() will be returned. func zonedEnviron(api NetworkBacking) (providercommon.ZonedEnviron, error) { env, err := environs.GetEnviron(api, environs.New) if err != nil { return nil, errors.Annotate(err, "opening environment") } if zonedEnv, ok := env.(providercommon.ZonedEnviron); ok { return zonedEnv, nil } return nil, errors.NotSupportedf("availability zones") }
// SupportsSpaces checks if the environment implements NetworkingEnviron // and also if it supports spaces. func SupportsSpaces(backing environs.EnvironConfigGetter) error { env, err := environs.GetEnviron(backing, environs.New) if err != nil { return errors.Annotate(err, "getting environ") } if !environs.SupportsSpaces(env) { return errors.NotSupportedf("spaces") } return nil }
// networkingEnviron returns a environs.NetworkingEnviron instance from the // current model config, if supported. If the model does not support // environs.Networking, an error satisfying errors.IsNotSupported() will be // returned. func networkingEnviron(getter environs.EnvironConfigGetter) (environs.NetworkingEnviron, error) { env, err := environs.GetEnviron(getter, environs.New) if err != nil { return nil, errors.Annotate(err, "opening environment") } if netEnv, ok := environs.SupportsNetworking(env); ok { return netEnv, nil } return nil, errors.NotSupportedf("model networking features") // " not supported" }
// obtainEnvCloudConfig returns environment specific cloud information // to be used in search for compatible images and their metadata. func (p *ProvisionerAPI) obtainEnvCloudConfig() (*simplestreams.CloudSpec, environs.Environ, error) { env, err := environs.GetEnviron(p.configGetter, environs.New) if err != nil { return nil, nil, errors.Annotate(err, "could not get model") } if inst, ok := env.(simplestreams.HasRegion); ok { cloud, err := inst.Region() if err != nil { // can't really find images if we cannot determine cloud region // TODO (anastasiamac 2015-12-03) or can we? return nil, nil, errors.Annotate(err, "getting provider region information (cloud spec)") } return &cloud, env, nil } return nil, env, nil }
// NetworkingEnvironFromModelConfig constructs and returns // environs.NetworkingEnviron using the given configGetter. Returns an error // satisfying errors.IsNotSupported() if the model config does not support // networking features. func NetworkingEnvironFromModelConfig(configGetter environs.EnvironConfigGetter) (environs.NetworkingEnviron, error) { modelConfig, err := configGetter.ModelConfig() if err != nil { return nil, errors.Annotate(err, "failed to get model config") } if modelConfig.Type() == "dummy" { return nil, errors.NotSupportedf("dummy provider network config") } env, err := environs.GetEnviron(configGetter, environs.New) if err != nil { return nil, errors.Annotate(err, "failed to construct a model from config") } netEnviron, supported := environs.SupportsNetworking(env) if !supported { // " not supported" will be appended to the message below. return nil, errors.NotSupportedf("model %q networking", modelConfig.Name()) } return netEnviron, nil }
// NewTracker loads an environment from the observer and returns a new Tracker, // or an error if anything goes wrong. If a tracker is returned, its Environ() // method is immediately usable. // // The caller is responsible for Kill()ing the returned Tracker and Wait()ing // for any errors it might return. func NewTracker(config Config) (*Tracker, error) { if err := config.Validate(); err != nil { return nil, errors.Trace(err) } environ, err := environs.GetEnviron(config.Observer, config.NewEnvironFunc) if err != nil { return nil, errors.Annotate(err, "cannot create environ") } t := &Tracker{ config: config, environ: environ, } err = catacomb.Invoke(catacomb.Plan{ Site: &t.catacomb, Work: t.loop, }) if err != nil { return nil, errors.Trace(err) } return t, nil }
// findMatchingTools searches tools storage and simplestreams for tools matching the // given parameters. If an exact match is specified (number, series and arch) // and is found in tools storage, then simplestreams will not be searched. func (f *ToolsFinder) findMatchingTools(args params.FindToolsParams) (coretools.List, error) { exactMatch := args.Number != version.Zero && args.Series != "" && args.Arch != "" storageList, err := f.matchingStorageTools(args) if err == nil && exactMatch { return storageList, nil } else if err != nil && err != coretools.ErrNoMatches { return nil, err } // Look for tools in simplestreams too, but don't replace // any versions found in storage. env, err := environs.GetEnviron(f.configGetter, environs.New) if err != nil { return nil, err } filter := toolsFilter(args) cfg := env.Config() stream := envtools.PreferredStream(&args.Number, cfg.Development(), cfg.AgentStream()) simplestreamsList, err := envtoolsFindTools( env, args.MajorVersion, args.MinorVersion, stream, filter, ) if len(storageList) == 0 && err != nil { return nil, err } list := storageList found := make(map[version.Binary]bool) for _, tools := range storageList { found[tools.Version] = true } for _, tools := range simplestreamsList { if !found[tools.Version] { list = append(list, tools) } } sort.Sort(list) return list, nil }
func (s *serverSuite) SetUpTest(c *gc.C) { s.ConfigAttrs = map[string]interface{}{ "authorized-keys": coretesting.FakeAuthKeys, } s.baseSuite.SetUpTest(c) var err error auth := testing.FakeAuthorizer{ Tag: s.AdminUserTag(c), EnvironManager: true, } urlGetter := common.NewToolsURLGetter(s.State.ModelUUID(), s.State) configGetter := stateenvirons.EnvironConfigGetter{s.State} statusSetter := common.NewStatusSetter(s.State, common.AuthAlways()) toolsFinder := common.NewToolsFinder(configGetter, s.State, urlGetter) s.newEnviron = func() (environs.Environ, error) { return environs.GetEnviron(configGetter, environs.New) } newEnviron := func() (environs.Environ, error) { return s.newEnviron() } blockChecker := common.NewBlockChecker(s.State) modelConfigAPI, err := modelconfig.NewModelConfigAPI(s.State, auth) c.Assert(err, jc.ErrorIsNil) s.client, err = client.NewClient( client.NewStateBackend(s.State), modelConfigAPI, common.NewResources(), auth, statusSetter, toolsFinder, newEnviron, blockChecker, ) c.Assert(err, jc.ErrorIsNil) }
func newClient(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*Client, error) { urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st) configGetter := stateenvirons.EnvironConfigGetter{st} statusSetter := common.NewStatusSetter(st, common.AuthAlways()) toolsFinder := common.NewToolsFinder(configGetter, st, urlGetter) newEnviron := func() (environs.Environ, error) { return environs.GetEnviron(configGetter, environs.New) } blockChecker := common.NewBlockChecker(st) modelConfigAPI, err := modelconfig.NewModelConfigAPI(st, authorizer) if err != nil { return nil, errors.Trace(err) } return NewClient( NewStateBackend(st), modelConfigAPI, resources, authorizer, statusSetter, toolsFinder, newEnviron, blockChecker, ) }
// NewProvisionerAPI creates a new server-side ProvisionerAPI facade. func NewProvisionerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*ProvisionerAPI, error) { if !authorizer.AuthMachineAgent() && !authorizer.AuthModelManager() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { isModelManager := authorizer.AuthModelManager() isMachineAgent := authorizer.AuthMachineAgent() authEntityTag := authorizer.GetAuthTag() return func(tag names.Tag) bool { if isMachineAgent && tag == authEntityTag { // A machine agent can always access its own machine. return true } switch tag := tag.(type) { case names.MachineTag: parentId := state.ParentId(tag.Id()) if parentId == "" { // All top-level machines are accessible by the // environment manager. return isModelManager } // All containers with the authenticated machine as a // parent are accessible by it. // TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is // only equal to nil, but it suggests someone is passing an authorizer // with a nil tag. return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag default: return false } }, nil } getAuthOwner := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } model, err := st.Model() if err != nil { return nil, err } configGetter := stateenvirons.EnvironConfigGetter{st} env, err := environs.GetEnviron(configGetter, environs.New) if err != nil { return nil, err } urlGetter := common.NewToolsURLGetter(model.UUID(), st) storageProviderRegistry := stateenvirons.NewStorageProviderRegistry(env) return &ProvisionerAPI{ Remover: common.NewRemover(st, false, getAuthFunc), StatusSetter: common.NewStatusSetter(st, getAuthFunc), StatusGetter: common.NewStatusGetter(st, getAuthFunc), DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), LifeGetter: common.NewLifeGetter(st, getAuthFunc), StateAddresser: common.NewStateAddresser(st), APIAddresser: common.NewAPIAddresser(st, resources), ModelWatcher: common.NewModelWatcher(st, resources, authorizer), ModelMachinesWatcher: common.NewModelMachinesWatcher(st, resources, authorizer), ControllerConfigAPI: common.NewControllerConfig(st), InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFunc), ToolsFinder: common.NewToolsFinder(configGetter, st, urlGetter), ToolsGetter: common.NewToolsGetter(st, configGetter, st, urlGetter, getAuthOwner), st: st, resources: resources, authorizer: authorizer, configGetter: configGetter, storageProviderRegistry: storageProviderRegistry, storagePoolManager: poolmanager.New(state.NewStateSettings(st), storageProviderRegistry), getAuthFunc: getAuthFunc, }, nil }
// GetNewEnvironFunc returns a NewEnvironFunc, that constructs Environs // using the given environs.NewEnvironFunc. func GetNewEnvironFunc(newEnviron environs.NewEnvironFunc) NewEnvironFunc { return func(st *state.State) (environs.Environ, error) { g := EnvironConfigGetter{st} return environs.GetEnviron(g, newEnviron) } }
// 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) } }() // 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, errors.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 := environs.GetEnviron(apiagent.NewState(apiConn), newEnvirons) 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 }