// ConfigForName returns the configuration for the environment with // the given name from the default environments file. If the name is // blank, the default environment will be used. If the configuration // is not found, an errors.NotFoundError is returned. If the given // store contains an entry for the environment and it has associated // bootstrap config, that configuration will be returned. // ConfigForName also returns where the configuration was sourced from // (this is also valid even when there is an error. func ConfigForName(name string, store configstore.Storage) (*config.Config, ConfigSource, error) { envs, err := ReadEnvirons("") if err != nil { return nil, ConfigFromNowhere, err } if name == "" { name = envs.Default } // TODO(rog) 2013-10-04 https://bugs.github.com/juju/juju/+bug/1235217 // Don't fall back to reading from environments.yaml // when we can be sure that everyone has a // .jenv file for their currently bootstrapped environments. if name != "" { info, err := store.ReadInfo(name) if err == nil { if len(info.BootstrapConfig()) == 0 { return nil, ConfigFromNowhere, EmptyConfig{fmt.Errorf("environment has no bootstrap configuration data")} } logger.Debugf("ConfigForName found bootstrap config %#v", info.BootstrapConfig()) cfg, err := config.New(config.NoDefaults, info.BootstrapConfig()) return cfg, ConfigFromInfo, err } if err != nil && !errors.IsNotFound(err) { return nil, ConfigFromInfo, fmt.Errorf("cannot read environment info for %q: %v", name, err) } } cfg, err := envs.Config(name) return cfg, ConfigFromEnvirons, err }
func assertEnvironDestroyed(c *gc.C, env environs.Environ, store configstore.Storage) { _, err := store.ReadInfo(env.Config().Name()) c.Assert(err, jc.Satisfies, errors.IsNotFound) _, err = env.Instances([]instance.Id{"invalid"}) c.Assert(err, gc.ErrorMatches, "environment has been destroyed") }
// Prepare prepares a new environment based on the provided configuration. // If the environment is already prepared, it behaves like New. func Prepare(cfg *config.Config, ctx BootstrapContext, store configstore.Storage) (Environ, error) { if p, err := Provider(cfg.Type()); err != nil { return nil, err } else if info, err := store.ReadInfo(cfg.Name()); errors.IsNotFound(errors.Cause(err)) { info = store.CreateInfo(cfg.Name()) if env, err := prepare(ctx, cfg, info, p); err == nil { return env, decorateAndWriteInfo(info, env.Config()) } else { if err := info.Destroy(); err != nil { logger.Warningf("cannot destroy newly created environment info: %v", err) } return nil, err } } else if err != nil { return nil, errors.Annotatef(err, "error reading environment info %q", cfg.Name()) } else if !info.Initialized() { return nil, errors.Errorf( "found uninitialized environment info for %q; environment preparation probably in progress or interrupted", cfg.Name(), ) } else if len(info.BootstrapConfig()) == 0 { return nil, errors.New("found environment info but no bootstrap config") } else { cfg, err = config.New(config.NoDefaults, info.BootstrapConfig()) if err != nil { return nil, errors.Annotate(err, "cannot parse bootstrap config") } return New(cfg) } }
func (s *NewAPIClientSuite) bootstrapEnv(c *gc.C, envName string, store configstore.Storage) { if store == nil { store = configstore.NewMem() } ctx := envtesting.BootstrapContext(c) c.Logf("env name: %s", envName) env, err := environs.PrepareFromName(envName, ctx, store) c.Assert(err, jc.ErrorIsNil) storageDir := c.MkDir() s.PatchValue(&envtools.DefaultBaseURL, storageDir) stor, err := filestorage.NewFileStorageWriter(storageDir) c.Assert(err, jc.ErrorIsNil) envtesting.UploadFakeTools(c, stor, "released", "released") err = bootstrap.Bootstrap(ctx, env, bootstrap.BootstrapParams{}) c.Assert(err, jc.ErrorIsNil) info, err := store.ReadInfo(envName) c.Assert(err, jc.ErrorIsNil) creds := info.APICredentials() creds.User = dummy.AdminUserTag().Name() c.Logf("set creds: %#v", creds) info.SetAPICredentials(creds) err = info.Write() c.Assert(err, jc.ErrorIsNil) c.Logf("creds: %#v", info.APICredentials()) info, err = store.ReadInfo(envName) c.Assert(err, jc.ErrorIsNil) c.Logf("read creds: %#v", info.APICredentials()) c.Logf("store: %#v", store) }
func assertEnvironNotDestroyed(c *gc.C, env environs.Environ, store configstore.Storage) { info, err := store.ReadInfo(env.Config().Name()) c.Assert(err, gc.IsNil) c.Assert(info.Initialized(), jc.IsTrue) _, err = environs.NewFromName(env.Config().Name(), store) c.Assert(err, gc.IsNil) }
// Prepare prepares a new environment based on the provided configuration. // If the environment is already prepared, it behaves like New. func Prepare(cfg *config.Config, ctx BootstrapContext, store configstore.Storage) (Environ, error) { p, err := Provider(cfg.Type()) if err != nil { return nil, err } info, err := store.ReadInfo(cfg.Name()) if errors.IsNotFound(errors.Cause(err)) { info = store.CreateInfo(cfg.Name()) env, err := prepare(ctx, cfg, info, p) if err != nil { if err := info.Destroy(); err != nil { logger.Warningf("cannot destroy newly created environment info: %v", err) } return nil, err } cfg = env.Config() creds := configstore.APICredentials{ User: "******", // TODO(waigani) admin@local once we have that set Password: cfg.AdminSecret(), } info.SetAPICredentials(creds) endpoint := configstore.APIEndpoint{} var ok bool endpoint.CACert, ok = cfg.CACert() if !ok { return nil, errors.Errorf("CACert is not set") } endpoint.EnvironUUID, ok = cfg.UUID() if !ok { return nil, errors.Errorf("CACert is not set") } info.SetAPIEndpoint(endpoint) info.SetBootstrapConfig(env.Config().AllAttrs()) if err := info.Write(); err != nil { return nil, errors.Annotatef(err, "cannot create environment info %q", env.Config().Name()) } return env, nil } if err != nil { return nil, errors.Annotatef(err, "error reading environment info %q", cfg.Name()) } if !info.Initialized() { return nil, errors.Errorf("found uninitialized environment info for %q; environment preparation probably in progress or interrupted", cfg.Name()) } if len(info.BootstrapConfig()) == 0 { return nil, errors.New("found environment info but no bootstrap config") } cfg, err = config.New(config.NoDefaults, info.BootstrapConfig()) if err != nil { return nil, errors.Annotate(err, "cannot parse bootstrap config") } return New(cfg) }
func setEndpointAddress(c *gc.C, store configstore.Storage, envName string, addr string) { // Populate the environment's info with an endpoint // with a known address. info, err := store.ReadInfo(coretesting.SampleEnvName) c.Assert(err, gc.IsNil) info.SetAPIEndpoint(configstore.APIEndpoint{ Addresses: []string{addr}, CACert: "certificated", }) err = info.Write() c.Assert(err, gc.IsNil) }
// DestroyInfo destroys the configuration data for the named // environment from the given store. func DestroyInfo(envName string, store configstore.Storage) error { info, err := store.ReadInfo(envName) if err != nil { if errors.IsNotFound(err) { return nil } return err } if err := info.Destroy(); err != nil { return errors.Annotate(err, "cannot destroy environment configuration information") } return nil }
func setEndpointAddressAndHostname(c *gc.C, store configstore.Storage, envName string, addr, host string) { // Populate the environment's info with an endpoint // with a known address and hostname. info, err := store.ReadInfo(coretesting.SampleModelName) c.Assert(err, jc.ErrorIsNil) info.SetAPIEndpoint(configstore.APIEndpoint{ Addresses: []string{addr}, Hostnames: []string{host}, CACert: "certificated", }) err = info.Write() c.Assert(err, jc.ErrorIsNil) }
// Prepare prepares a new environment based on the provided configuration. // If the environment is already prepared, it behaves like New. func Prepare(cfg *config.Config, ctx BootstrapContext, store configstore.Storage) (Environ, error) { p, err := Provider(cfg.Type()) if err != nil { return nil, err } info, err := store.CreateInfo(cfg.Name()) if err == configstore.ErrEnvironInfoAlreadyExists { logger.Infof("environment info already exists; using New not Prepare") info, err := store.ReadInfo(cfg.Name()) if err != nil { return nil, fmt.Errorf("error reading environment info %q: %v", cfg.Name(), err) } if !info.Initialized() { return nil, fmt.Errorf("found uninitialized environment info for %q; environment preparation probably in progress or interrupted", cfg.Name()) } if len(info.BootstrapConfig()) == 0 { return nil, fmt.Errorf("found environment info but no bootstrap config") } cfg, err = config.New(config.NoDefaults, info.BootstrapConfig()) if err != nil { return nil, fmt.Errorf("cannot parse bootstrap config: %v", err) } return New(cfg) } if err != nil { return nil, fmt.Errorf("cannot create new info for environment %q: %v", cfg.Name(), err) } env, err := prepare(ctx, cfg, info, p) if err != nil { if err := info.Destroy(); err != nil { logger.Warningf("cannot destroy newly created environment info: %v", err) } return nil, err } info.SetBootstrapConfig(env.Config().AllAttrs()) if err := info.Write(); err != nil { return nil, fmt.Errorf("cannot create environment info %q: %v", env.Config().Name(), err) } return env, nil }
func apiEndpointInStore(envName string, refresh bool, store configstore.Storage, apiOpen apiOpenFunc) (configstore.APIEndpoint, error) { info, err := store.ReadInfo(envName) if err != nil { return configstore.APIEndpoint{}, err } endpoint := info.APIEndpoint() if !refresh && len(endpoint.Addresses) > 0 { logger.Debugf("found cached addresses, not connecting to API server") return endpoint, nil } // We need to connect to refresh our endpoint settings apiState, err := newAPIFromStore(envName, store, apiOpen) if err != nil { return configstore.APIEndpoint{}, err } apiState.Close() // The side effect of connecting is that we update the store with new API information info, err = store.ReadInfo(envName) if err != nil { return configstore.APIEndpoint{}, err } return info.APIEndpoint(), nil }
// ConfigForName returns the configuration for the environment with // the given name from the default environments file. If the name is // blank, the default environment will be used. If the configuration // is not found, an errors.NotFoundError is returned. If the given // store contains an entry for the environment and it has associated // bootstrap config, that configuration will be returned. // ConfigForName also returns where the configuration was sourced from // (this is also valid even when there is an error. func ConfigForName(name string, store configstore.Storage) (*config.Config, ConfigSource, error) { envs, err := ReadEnvirons("") if err != nil { return nil, ConfigFromNowhere, err } if name == "" { name = envs.Default } info, err := store.ReadInfo(name) if err == nil { if len(info.BootstrapConfig()) == 0 { return nil, ConfigFromNowhere, EmptyConfig{fmt.Errorf("environment has no bootstrap configuration data")} } logger.Debugf("ConfigForName found bootstrap config %#v", info.BootstrapConfig()) cfg, err := config.New(config.NoDefaults, info.BootstrapConfig()) return cfg, ConfigFromInfo, err } else if !errors.IsNotFound(err) { return nil, ConfigFromInfo, fmt.Errorf("cannot read environment info for %q: %v", name, err) } cfg, err := envs.Config(name) return cfg, ConfigFromEnvirons, err }
func checkEnvironmentExistsInStore(c *gc.C, name string, store configstore.Storage) { _, err := store.ReadInfo(name) c.Assert(err, jc.ErrorIsNil) }
// newAPIFromStore implements the bulk of NewAPIClientFromName // but is separate for testing purposes. func newAPIFromStore(envName string, store configstore.Storage, apiOpen apiOpenFunc) (apiState, error) { // Try to read the default environment configuration file. // If it doesn't exist, we carry on in case // there's some environment info for that environment. // This enables people to copy environment files // into their .juju/environments directory and have // them be directly useful with no further configuration changes. envs, err := environs.ReadEnvirons("") if err == nil { if envName == "" { envName = envs.Default } if envName == "" { return nil, fmt.Errorf("no default environment found") } } else if !environs.IsNoEnv(err) { return nil, err } // Try to connect to the API concurrently using two different // possible sources of truth for the API endpoint. Our // preference is for the API endpoint cached in the API info, // because we know that without needing to access any remote // provider. However, the addresses stored there may no longer // be current (and the network connection may take a very long // time to time out) so we also try to connect using information // found from the provider. We only start to make that // connection after some suitable delay, so that in the // hopefully usual case, we will make the connection to the API // and never hit the provider. By preference we use provider // attributes from the config store, but for backward // compatibility reasons, we fall back to information from // ReadEnvirons if that does not exist. chooseError := func(err0, err1 error) error { if err0 == nil { return err1 } if errorImportance(err0) < errorImportance(err1) { err0, err1 = err1, err0 } logger.Warningf("discarding API open error: %v", err1) return err0 } try := parallel.NewTry(0, chooseError) info, err := store.ReadInfo(envName) if err != nil && !errors.IsNotFound(err) { return nil, err } var delay time.Duration if info != nil && len(info.APIEndpoint().Addresses) > 0 { logger.Debugf( "trying cached API connection settings - endpoints %v", info.APIEndpoint().Addresses, ) try.Start(func(stop <-chan struct{}) (io.Closer, error) { return apiInfoConnect(info, apiOpen, stop) }) // Delay the config connection until we've spent // some time trying to connect to the cached info. delay = providerConnectDelay } else { logger.Debugf("no cached API connection settings found") } try.Start(func(stop <-chan struct{}) (io.Closer, error) { cfg, err := getConfig(info, envs, envName) if err != nil { return nil, err } return apiConfigConnect(cfg, apiOpen, stop, delay, environInfoUserTag(info)) }) try.Close() val0, err := try.Result() if err != nil { if ierr, ok := err.(*infoConnectError); ok { // lose error encapsulation: err = ierr.error } return nil, err } st := val0.(apiState) addrConnectedTo, err := serverAddress(st.Addr()) if err != nil { return nil, err } // Even though we are about to update API addresses based on // APIHostPorts in cacheChangedAPIInfo, we first cache the // addresses based on the provider lookup. This is because older API // servers didn't return their HostPort information on Login, and we // still want to cache our connection information to them. if cachedInfo, ok := st.(apiStateCachedInfo); ok { st = cachedInfo.apiState if cachedInfo.cachedInfo != nil && info != nil { // Cache the connection settings only if we used the // environment config, but any errors are just logged // as warnings, because they're not fatal. err = cacheAPIInfo(st, info, cachedInfo.cachedInfo) if err != nil { logger.Warningf("cannot cache API connection settings: %v", err.Error()) } else { logger.Infof("updated API connection settings cache") } addrConnectedTo, err = serverAddress(st.Addr()) if err != nil { return nil, err } } } // Update API addresses if they've changed. Error is non-fatal. // For older servers, the environ tag or server tag may not be set. // if they are not, we store empty values. var environUUID string var serverUUID string if envTag, err := st.EnvironTag(); err == nil { environUUID = envTag.Id() } if serverTag, err := st.ServerTag(); err == nil { serverUUID = serverTag.Id() } if localerr := cacheChangedAPIInfo(info, st.APIHostPorts(), addrConnectedTo, environUUID, serverUUID); localerr != nil { logger.Warningf("cannot cache API addresses: %v", localerr) } return st, nil }
func checkEnvironmentRemovedFromStore(c *gc.C, name string, store configstore.Storage) { _, err := store.ReadInfo(name) c.Assert(err, jc.Satisfies, errors.IsNotFound) }
func checkControllerExistsInStore(c *gc.C, name string, store configstore.Storage) { _, err := store.ReadInfo(name) c.Check(err, jc.ErrorIsNil) }
func checkControllerRemovedFromStore(c *gc.C, name string, store configstore.Storage) { _, err := store.ReadInfo(name) c.Check(err, jc.Satisfies, errors.IsNotFound) }