func (*suite) TestNoEnv(c *gc.C) { envPath := gitjujutesting.HomePath(".juju", "environments.yaml") err := os.Remove(envPath) c.Assert(err, jc.ErrorIsNil) es, err := environs.ReadEnvirons("") c.Assert(es, gc.IsNil) c.Assert(err, jc.Satisfies, environs.IsNoEnv) }
// There is simple ordering for the default environment. Firstly check the // JUJU_ENV environment variable. If that is set, it gets used. If it isn't // set, look in the $JUJU_HOME/current-environment file. If neither are // available, read environments.yaml and use the default environment therein. func getDefaultEnvironment() (string, error) { if defaultEnv := os.Getenv(osenv.JujuEnvEnvKey); defaultEnv != "" { return defaultEnv, nil } if currentEnv := ReadCurrentEnvironment(); currentEnv != "" { return currentEnv, nil } envs, err := environs.ReadEnvirons("") if err != nil { return "", err } if envs.Default == "" { return "", ErrNoEnvironmentSpecified } return envs.Default, nil }
// GetDefaultEnvironment returns the name of the Juju default environment. // There is simple ordering for the default environment. Firstly check the // JUJU_ENV environment variable. If that is set, it gets used. If it isn't // set, look in the $JUJU_HOME/current-environment file. If neither are // available, read environments.yaml and use the default environment therein. // If no default is specified in the environments file, an empty string is returned. // Not having a default environment specified is not an error. func GetDefaultEnvironment() (string, error) { if defaultEnv := os.Getenv(osenv.JujuEnvEnvKey); defaultEnv != "" { return defaultEnv, nil } if currentEnv := ReadCurrentEnvironment(); currentEnv != "" { return currentEnv, nil } envs, err := environs.ReadEnvirons("") if environs.IsNoEnv(err) { // That's fine, not an error here. return "", nil } else if err != nil { return "", errors.Trace(err) } return envs.Default, nil }
func (*suite) TestDefaultConfigFile(c *gc.C) { env := ` environments: only: type: dummy state-server: false authorized-keys: i-am-a-key ` outfile, err := environs.WriteEnvirons("", env) c.Assert(err, jc.ErrorIsNil) path := gitjujutesting.HomePath(".juju", "environments.yaml") c.Assert(path, gc.Equals, outfile) envs, err := environs.ReadEnvirons("") c.Assert(err, jc.ErrorIsNil) cfg, err := envs.Config("") c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.Name(), gc.Equals, "only") }
func (*suite) TestNamedConfigFile(c *gc.C) { env := ` environments: only: type: dummy state-server: false authorized-keys: i-am-a-key ` path := filepath.Join(c.MkDir(), "a-file") outfile, err := environs.WriteEnvirons(path, env) c.Assert(err, jc.ErrorIsNil) c.Assert(path, gc.Equals, outfile) envs, err := environs.ReadEnvirons(path) c.Assert(err, jc.ErrorIsNil) cfg, err := envs.Config("") c.Assert(err, jc.ErrorIsNil) c.Assert(cfg.Name(), gc.Equals, "only") }
// Run checks to see if there is already an environments.yaml file. In one does not exist already, // a boilerplate version is created so that the user can edit it to get started. func (c *initCommand) Run(context *cmd.Context) error { out := context.Stdout config := environs.BoilerplateConfig() if c.Show { fmt.Fprint(out, config) return nil } _, err := environs.ReadEnvirons("") if err == nil && !c.WriteFile { return errJujuEnvExists } if err != nil && !environs.IsNoEnv(err) { return err } filename, err := environs.WriteEnvirons("", config) if err != nil { return fmt.Errorf("A boilerplate environment configuration file could not be created: %s", err.Error()) } fmt.Fprintf(out, "A boilerplate environment configuration file has been written to %s.\n", filename) fmt.Fprint(out, "Edit the file to configure your juju environment and run bootstrap.\n") return nil }
// GetDefaultModel returns the name of the Juju default model. // There is simple ordering for the default model. Firstly check the // JUJU_MODEL environment variable. If that is set, it gets used. If it isn't // set, look in the $JUJU_DATA/current-model file. If neither are // available, read environments.yaml and use the default model therein. // If no default is specified in the environments file, an empty string is returned. // Not having a default model specified is not an error. func GetDefaultModel() (string, error) { if defaultModel := os.Getenv(osenv.JujuModelEnvKey); defaultModel != "" { return defaultModel, nil } if currentModel, err := ReadCurrentModel(); err != nil { return "", errors.Trace(err) } else if currentModel != "" { return currentModel, nil } if currentController, err := ReadCurrentController(); err != nil { return "", errors.Trace(err) } else if currentController != "" { return "", errors.Errorf("not operating on an model, using controller %q", currentController) } models, err := environs.ReadEnvirons("") if environs.IsNoEnv(err) { // That's fine, not an error here. return "", nil } else if err != nil { return "", errors.Trace(err) } return models.Default, nil }
// GetDefaultEnvironment returns the name of the Juju default environment. // There is simple ordering for the default environment. Firstly check the // JUJU_ENV environment variable. If that is set, it gets used. If it isn't // set, look in the $JUJU_HOME/current-environment file. If neither are // available, read environments.yaml and use the default environment therein. // If no default is specified in the environments file, an empty string is returned. // Not having a default environment specified is not an error. func GetDefaultEnvironment() (string, error) { if defaultEnv := os.Getenv(osenv.JujuEnvEnvKey); defaultEnv != "" { return defaultEnv, nil } if currentEnv, err := ReadCurrentEnvironment(); err != nil { return "", errors.Trace(err) } else if currentEnv != "" { return currentEnv, nil } if currentSystem, err := ReadCurrentSystem(); err != nil { return "", errors.Trace(err) } else if currentSystem != "" { return "", errors.Errorf("not operating on an environment, using system %q", currentSystem) } envs, err := environs.ReadEnvirons("") if environs.IsNoEnv(err) { // That's fine, not an error here. return "", nil } else if err != nil { return "", errors.Trace(err) } return envs.Default, nil }
func (c *SwitchCommand) Run(ctx *cmd.Context) error { // Switch is an alternative way of dealing with environments than using // the JUJU_ENV environment setting, and as such, doesn't play too well. // If JUJU_ENV is set we should report that as the current environment, // and not allow switching when it is set. // Passing through the empty string reads the default environments.yaml file. environments, err := environs.ReadEnvirons("") if err != nil { return errors.New("couldn't read the environment") } names := environments.Names() sort.Strings(names) if c.List { // List all environments. if c.EnvName != "" { return errors.New("cannot switch and list at the same time") } for _, name := range names { fmt.Fprintf(ctx.Stdout, "%s\n", name) } return nil } jujuEnv := os.Getenv("JUJU_ENV") if jujuEnv != "" { if c.EnvName == "" { fmt.Fprintf(ctx.Stdout, "%s\n", jujuEnv) return nil } else { return fmt.Errorf("cannot switch when JUJU_ENV is overriding the environment (set to %q)", jujuEnv) } } currentEnv := envcmd.ReadCurrentEnvironment() if currentEnv == "" { currentEnv = environments.Default } // Handle the different operation modes. switch { case c.EnvName == "" && currentEnv == "": // Nothing specified and nothing to switch to. return errors.New("no currently specified environment") case c.EnvName == "": // Simply print the current environment. fmt.Fprintf(ctx.Stdout, "%s\n", currentEnv) default: // Switch the environment. if !validEnvironmentName(c.EnvName, names) { return fmt.Errorf("%q is not a name of an existing defined environment", c.EnvName) } if err := envcmd.WriteCurrentEnvironment(c.EnvName); err != nil { return err } if currentEnv == "" { fmt.Fprintf(ctx.Stdout, "-> %s\n", c.EnvName) } else { fmt.Fprintf(ctx.Stdout, "%s -> %s\n", currentEnv, c.EnvName) } } return nil }
// 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 (c *switchCommand) Run(ctx *cmd.Context) error { // Switch is an alternative way of dealing with environments than using // the JUJU_ENV environment setting, and as such, doesn't play too well. // If JUJU_ENV is set we should report that as the current environment, // and not allow switching when it is set. // Passing through the empty string reads the default environments.yaml file. // If the environments.yaml file doesn't exist, just list environments in // the configstore. envFileExists := true names := set.NewStrings() environments, err := environs.ReadEnvirons("") if err != nil { if !environs.IsNoEnv(err) { return errors.Annotate(err, "couldn't read the environment") } envFileExists = false } else { for _, name := range environments.Names() { names.Add(name) } } configEnvirons, configControllers, err := getConfigstoreOptions() if err != nil { return err } names = names.Union(configEnvirons) names = names.Union(configControllers) if c.List { // List all environments and controllers. if c.EnvName != "" { return errors.New("cannot switch and list at the same time") } for _, name := range names.SortedValues() { if configControllers.Contains(name) && !configEnvirons.Contains(name) { name += controllerSuffix } fmt.Fprintf(ctx.Stdout, "%s\n", name) } return nil } jujuEnv := os.Getenv("JUJU_ENV") if jujuEnv != "" { if c.EnvName == "" { fmt.Fprintf(ctx.Stdout, "%s\n", jujuEnv) return nil } else { return errors.Errorf("cannot switch when JUJU_ENV is overriding the environment (set to %q)", jujuEnv) } } current, isController, err := envcmd.CurrentConnectionName() if err != nil { return errors.Trace(err) } if current == "" { if envFileExists { current = environments.Default } } else if isController { current += controllerSuffix } // Handle the different operation modes. switch { case c.EnvName == "" && current == "": // Nothing specified and nothing to switch to. return errors.New("no currently specified environment") case c.EnvName == "": // Simply print the current environment. fmt.Fprintf(ctx.Stdout, "%s\n", current) return nil default: // Switch the environment. if !names.Contains(c.EnvName) { return errors.Errorf("%q is not a name of an existing defined environment or controller", c.EnvName) } // If the name is not in the environment set, but is in the controller // set, then write the name into the current controller file. logger.Debugf("controllers: %v", configControllers) logger.Debugf("environs: %v", configEnvirons) newEnv := c.EnvName if configControllers.Contains(newEnv) && !configEnvirons.Contains(newEnv) { return envcmd.SetCurrentController(ctx, newEnv) } return envcmd.SetCurrentEnvironment(ctx, newEnv) } }