Exemple #1
0
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")
}
Exemple #2
0
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
}
Exemple #5
0
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)
	}
}
Exemple #6
0
// 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)
}