Example #1
0
File: wait.go Project: bac/juju
// 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)
		}
	}
}
Example #2
0
File: subnets.go Project: bac/juju
// 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")
}
Example #3
0
File: spaces.go Project: bac/juju
// 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
}
Example #4
0
File: subnets.go Project: bac/juju
// 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"
}
Example #5
0
// 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
}
Example #6
0
File: types.go Project: bac/juju
// 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
}
Example #7
0
File: environ.go Project: bac/juju
// 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
}
Example #8
0
File: tools.go Project: bac/juju
// 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
}
Example #9
0
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)
}
Example #10
0
File: client.go Project: bac/juju
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,
	)
}
Example #11
0
// 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
}
Example #12
0
File: config.go Project: bac/juju
// 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)
	}
}
Example #13
0
// 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
}