func (s *filesSuite) TestSetCurrentEnvironment(c *gc.C) { ctx := testing.Context(c) err := envcmd.SetCurrentEnvironment(ctx, "new-env") c.Assert(err, jc.ErrorIsNil) s.assertCurrentEnvironment(c, "new-env") c.Assert(testing.Stderr(ctx), gc.Equals, "-> new-env\n") }
func (s *filesSuite) TestSetCurrentEnvironmentExistingController(c *gc.C) { err := envcmd.WriteCurrentController("fubar") c.Assert(err, jc.ErrorIsNil) ctx := testing.Context(c) err = envcmd.SetCurrentEnvironment(ctx, "new-env") c.Assert(err, jc.ErrorIsNil) s.assertCurrentEnvironment(c, "new-env") c.Assert(testing.Stderr(ctx), gc.Equals, "fubar (controller) -> new-env\n") }
// Run implements Command.Run func (c *UseEnvironmentCommand) Run(ctx *cmd.Context) error { client, err := c.getAPI() if err != nil { return errors.Trace(err) } defer client.Close() creds, err := c.getConnectionCredentials() if err != nil { return errors.Trace(err) } endpoint, err := c.getConnectionEndpoint() if err != nil { return errors.Trace(err) } username := names.NewUserTag(creds.User).Username() env, err := c.findMatchingEnvironment(ctx, client, creds) if err != nil { return errors.Trace(err) } if c.LocalName == "" { if env.Owner == username { c.LocalName = env.Name } else { envOwner := names.NewUserTag(env.Owner) c.LocalName = envOwner.Name() + "-" + env.Name } } // Check with the store to see if we have an environment with that name. store, err := configstore.Default() if err != nil { return errors.Trace(err) } existing, err := store.ReadInfo(c.LocalName) if err == nil { // We have an existing environment with the same name. If it is the // same environment with the same user, then this is fine, and we just // change the current envrionment. endpoint := existing.APIEndpoint() existingCreds := existing.APICredentials() // Need to make sure we check the username of the credentials, // not just matching tags. existingUsername := names.NewUserTag(existingCreds.User).Username() if endpoint.EnvironUUID == env.UUID && existingUsername == username { ctx.Infof("You already have environment details for %q cached locally.", c.LocalName) return envcmd.SetCurrentEnvironment(ctx, c.LocalName) } ctx.Infof("You have an existing environment called %q, use --name to specify a different local name.", c.LocalName) return errors.New("existing environment") } info := store.CreateInfo(c.LocalName) if err := c.updateCachedInfo(info, env.UUID, creds, endpoint); err != nil { return errors.Annotatef(err, "failed to cache environment details") } return envcmd.SetCurrentEnvironment(ctx, c.LocalName) }
func (c *createEnvironmentCommand) Run(ctx *cmd.Context) (return_err error) { client, err := c.getAPI() if err != nil { return err } defer client.Close() creds, err := c.ConnectionCredentials() if err != nil { return errors.Trace(err) } creatingForSelf := true envOwner := creds.User if c.Owner != "" { owner := names.NewUserTag(c.Owner) user := names.NewUserTag(creds.User) creatingForSelf = owner == user envOwner = c.Owner } var info configstore.EnvironInfo var endpoint configstore.APIEndpoint if creatingForSelf { logger.Debugf("create cache entry for %q", c.Name) // Create the configstore entry and write it to disk, as this will error // if one with the same name already exists. endpoint, err = c.ConnectionEndpoint() if err != nil { return errors.Trace(err) } store, err := configstore.Default() if err != nil { return errors.Trace(err) } info = store.CreateInfo(c.Name) info.SetAPICredentials(creds) endpoint.EnvironUUID = "" if err := info.Write(); err != nil { if errors.Cause(err) == configstore.ErrEnvironInfoAlreadyExists { newErr := errors.AlreadyExistsf("environment %q", c.Name) return errors.Wrap(err, newErr) } return errors.Trace(err) } defer func() { if return_err != nil { logger.Debugf("error found, remove cache entry") e := info.Destroy() if e != nil { logger.Errorf("could not remove environment file: %v", e) } } }() } else { logger.Debugf("skipping cache entry for %q as owned %q", c.Name, c.Owner) } serverSkeleton, err := client.ConfigSkeleton("", "") if err != nil { return errors.Trace(err) } attrs, err := c.getConfigValues(ctx, serverSkeleton) if err != nil { return errors.Trace(err) } // We pass nil through for the account details until we implement that bit. env, err := client.CreateEnvironment(envOwner, nil, attrs) if err != nil { // cleanup configstore return errors.Trace(err) } if creatingForSelf { // update the cached details with the environment uuid endpoint.EnvironUUID = env.UUID info.SetAPIEndpoint(endpoint) if err := info.Write(); err != nil { return errors.Trace(err) } ctx.Infof("created environment %q", c.Name) return envcmd.SetCurrentEnvironment(ctx, c.Name) } else { ctx.Infof("created environment %q for %q", c.Name, c.Owner) } return 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) } }
// Run connects to the environment specified on the command line and bootstraps // a juju in that environment if none already exists. If there is as yet no environments.yaml file, // the user is informed how to create one. func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) { bootstrapFuncs := getBootstrapFuncs() envName := getEnvName(c) if envName == "" { return errors.Errorf("the name of the environment must be specified") } if err := checkProviderType(envName); errors.IsNotFound(err) { // This error will get handled later. } else if err != nil { return errors.Trace(err) } environ, cleanup, err := environFromName( ctx, envName, "Bootstrap", bootstrapFuncs.EnsureNotBootstrapped, ) // If we error out for any reason, clean up the environment. defer func() { if resultErr != nil && cleanup != nil { if c.KeepBrokenEnvironment { logger.Warningf("bootstrap failed but --keep-broken was specified so environment is not being destroyed.\n" + "When you are finished diagnosing the problem, remember to run juju destroy-environment --force\n" + "to clean up the environment.") } else { handleBootstrapError(ctx, resultErr, cleanup) } } }() // Handle any errors from environFromName(...). if err != nil { return errors.Annotatef(err, "there was an issue examining the environment") } // Check to see if this environment is already bootstrapped. If it // is, we inform the user and exit early. If an error is returned // but it is not that the environment is already bootstrapped, // then we're in an unknown state. if err := bootstrapFuncs.EnsureNotBootstrapped(environ); nil != err { if environs.ErrAlreadyBootstrapped == err { logger.Warningf("This juju environment is already bootstrapped. If you want to start a new Juju\nenvironment, first run juju destroy-environment to clean up, or switch to an\nalternative environment.") return err } return errors.Annotatef(err, "cannot determine if environment is already bootstrapped.") } // Block interruption during bootstrap. Providers may also // register for interrupt notification so they can exit early. interrupted := make(chan os.Signal, 1) defer close(interrupted) ctx.InterruptNotify(interrupted) defer ctx.StopInterruptNotify(interrupted) go func() { for _ = range interrupted { ctx.Infof("Interrupt signalled: waiting for bootstrap to exit") } }() // If --metadata-source is specified, override the default tools metadata source so // SyncTools can use it, and also upload any image metadata. var metadataDir string if c.MetadataSource != "" { metadataDir = ctx.AbsPath(c.MetadataSource) } // TODO (wallyworld): 2013-09-20 bug 1227931 // We can set a custom tools data source instead of doing an // unnecessary upload. if environ.Config().Type() == provider.Local { c.UploadTools = true } // Merge environ and bootstrap-specific constraints. constraintsValidator, err := environ.ConstraintsValidator() if err != nil { return errors.Trace(err) } bootstrapConstraints, err := constraintsValidator.Merge( c.Constraints, c.BootstrapConstraints, ) if err != nil { return errors.Trace(err) } logger.Infof("combined bootstrap constraints: %v", bootstrapConstraints) err = bootstrapFuncs.Bootstrap(envcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{ EnvironConstraints: c.Constraints, BootstrapConstraints: bootstrapConstraints, BootstrapSeries: c.BootstrapSeries, BootstrapImage: c.BootstrapImage, Placement: c.Placement, UploadTools: c.UploadTools, AgentVersion: c.AgentVersion, MetadataDir: metadataDir, }) if err != nil { return errors.Annotate(err, "failed to bootstrap environment") } err = c.SetBootstrapEndpointAddress(environ) if err != nil { return errors.Annotate(err, "saving bootstrap endpoint address") } err = envcmd.SetCurrentEnvironment(ctx, envName) if err != nil { return errors.Trace(err) } // To avoid race conditions when running scripted bootstraps, wait // for the state server's machine agent to be ready to accept commands // before exiting this bootstrap command. return c.waitForAgentInitialisation(ctx) }