Example #1
0
// Run implements Command.Run
func (c *listControllersCommand) Run(ctx *cmd.Context) error {
	controllers, err := c.store.AllControllers()
	if err != nil {
		return errors.Annotate(err, "failed to list controllers")
	}
	details, errs := c.convertControllerDetails(controllers)
	if len(errs) > 0 {
		fmt.Fprintln(ctx.Stderr, strings.Join(errs, "\n"))
	}
	currentController, err := modelcmd.ReadCurrentController()
	if err != nil {
		return errors.Annotate(err, "getting current controller")
	}
	if _, ok := controllers[currentController]; !ok {
		// TODO(axw) move handling of current-controller to
		// the jujuclient code, and make sure the file is
		// kept in-sync with the controllers.yaml file.
		currentController = ""
	}
	controllerSet := ControllerSet{
		Controllers:       details,
		CurrentController: currentController,
	}
	return c.out.Write(ctx, controllerSet)
}
Example #2
0
func (s *BootstrapSuite) TestBootstrapErrorRestoresOldMetadata(c *gc.C) {
	s.patchVersionAndSeries(c, "raring")
	s.PatchValue(&environsPrepare, func(
		environs.BootstrapContext,
		jujuclient.ClientStore,
		environs.PrepareParams,
	) (environs.Environ, error) {
		s.writeControllerModelAccountInfo(c, "foo", "bar", "foobar@local")
		return nil, fmt.Errorf("mock-prepare")
	})

	s.writeControllerModelAccountInfo(c, "local.olddevcontroller", "fredmodel", "fred@local")
	_, err := coretesting.RunCommand(c, s.newBootstrapCommand(), "devcontroller", "dummy", "--auto-upgrade")
	c.Assert(err, gc.ErrorMatches, "mock-prepare")

	oldCurrentController, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(oldCurrentController, gc.Equals, bootstrappedControllerName("olddevcontroller"))
	oldCurrentAccount, err := s.store.CurrentAccount(oldCurrentController)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(oldCurrentAccount, gc.Equals, "fred@local")
	oldCurrentModel, err := s.store.CurrentModel(oldCurrentController, oldCurrentAccount)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(oldCurrentModel, gc.Equals, "fredmodel")
}
Example #3
0
func (s *LoginSuite) TestWritesCurrentController(c *gc.C) {
	_, err := s.runServerFile(c)
	c.Assert(err, jc.ErrorIsNil)
	currentController, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currentController, gc.Equals, "foo")
}
Example #4
0
// Run implements Command.Run
func (c *showControllerCommand) Run(ctx *cmd.Context) error {
	controllerNames := c.controllerNames
	if len(controllerNames) == 0 {
		currentController, err := modelcmd.ReadCurrentController()
		if err != nil {
			return errors.Trace(err)
		}
		if currentController == "" {
			return errors.New("there is no active controller")
		}
		controllerNames = []string{currentController}
	}
	controllers := make(map[string]ShowControllerDetails)
	for _, name := range controllerNames {
		actualName, err := modelcmd.ResolveControllerName(c.store, name)
		if err != nil {
			return err
		}
		one, err := c.store.ControllerByName(actualName)
		if err != nil {
			return err
		}
		controllers[name] = c.convertControllerForShow(actualName, one)
	}
	return c.out.Write(ctx, controllers)
}
Example #5
0
func (s *SwitchSimpleSuite) TestSettingWritesControllerFile(c *gc.C) {
	s.addTestController(c)
	context, err := testing.RunCommand(c, newSwitchCommand(), "a-controller")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(testing.Stderr(context), gc.Equals, "-> a-controller (controller)\n")
	currController, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currController, gc.Equals, "a-controller")
}
Example #6
0
func (s *BootstrapSuite) TestBootstrapSetsCurrentModel(c *gc.C) {
	s.patchVersionAndSeries(c, "raring")

	_, err := coretesting.RunCommand(c, s.newBootstrapCommand(), "devcontroller", "dummy", "--auto-upgrade")
	c.Assert(err, jc.ErrorIsNil)
	currentController, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currentController, gc.Equals, bootstrappedControllerName("devcontroller"))
	modelName, err := s.store.CurrentModel(currentController, "admin@local")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(modelName, gc.Equals, "default")
}
Example #7
0
func (s *BootstrapSuite) TestBootstrapAlreadyExists(c *gc.C) {
	const controllerName = "devcontroller"
	expectedBootstrappedName := bootstrappedControllerName(controllerName)
	s.patchVersionAndSeries(c, "raring")

	s.writeControllerModelAccountInfo(c, "local.devcontroller", "fredmodel", "fred@local")

	ctx := coretesting.Context(c)
	_, errc := cmdtesting.RunCommand(ctx, s.newBootstrapCommand(), controllerName, "dummy", "--auto-upgrade")
	err := <-errc
	c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
	c.Assert(err, gc.ErrorMatches, fmt.Sprintf(`controller %q already exists`, expectedBootstrappedName))
	currentController, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currentController, gc.Equals, "local.devcontroller")
	currentAccount, err := s.store.CurrentAccount(currentController)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currentAccount, gc.Equals, "fred@local")
	currentModel, err := s.store.CurrentModel(currentController, currentAccount)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(currentModel, gc.Equals, "fredmodel")
}
Example #8
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()

	// Get the cloud definition identified by c.Cloud. If c.Cloud does not
	// identify a cloud in clouds.yaml, but is the name of a provider, and
	// that provider implements environs.CloudRegionDetector, we'll
	// synthesise a Cloud structure with the detected regions and no auth-
	// types.
	cloud, err := jujucloud.CloudByName(c.Cloud)
	if errors.IsNotFound(err) {
		ctx.Verbosef("cloud %q not found, trying as a provider name", c.Cloud)
		provider, err := environs.Provider(c.Cloud)
		if errors.IsNotFound(err) {
			return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
		} else if err != nil {
			return errors.Trace(err)
		}
		detector, ok := provider.(environs.CloudRegionDetector)
		if !ok {
			ctx.Verbosef(
				"provider %q does not support detecting regions",
				c.Cloud,
			)
			return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
		}
		regions, err := detector.DetectRegions()
		if err != nil && !errors.IsNotFound(err) {
			// It's not an error to have no regions.
			return errors.Annotatef(err,
				"detecting regions for %q cloud provider",
				c.Cloud,
			)
		}
		cloud = &jujucloud.Cloud{
			Type:    c.Cloud,
			Regions: regions,
		}
	} else if err != nil {
		return errors.Trace(err)
	}
	if err := checkProviderType(cloud.Type); errors.IsNotFound(err) {
		// This error will get handled later.
	} else if err != nil {
		return errors.Trace(err)
	}

	// Get the credentials and region name.
	store := c.ClientStore()
	credential, credentialName, regionName, err := modelcmd.GetCredentials(
		store, c.Region, c.CredentialName, c.Cloud, cloud.Type,
	)
	if errors.IsNotFound(err) && c.CredentialName == "" {
		// No credential was explicitly specified, and no credential
		// was found in credentials.yaml; have the provider detect
		// credentials from the environment.
		ctx.Verbosef("no credentials found, checking environment")
		detected, err := modelcmd.DetectCredential(c.Cloud, cloud.Type)
		if errors.Cause(err) == modelcmd.ErrMultipleCredentials {
			return ambiguousCredentialError
		} else if err != nil {
			return errors.Trace(err)
		}
		// We have one credential so extract it from the map.
		var oneCredential jujucloud.Credential
		for _, oneCredential = range detected.AuthCredentials {
		}
		credential = &oneCredential
		regionName = c.Region
		if regionName == "" {
			regionName = detected.DefaultRegion
		}
		logger.Tracef("authenticating with region %q and %v", regionName, credential)
	} else if err != nil {
		return errors.Trace(err)
	}

	region, err := getRegion(cloud, c.Cloud, regionName)
	if err != nil {
		return errors.Trace(err)
	}

	hostedModelUUID, err := utils.NewUUID()
	if err != nil {
		return errors.Trace(err)
	}
	controllerUUID, err := utils.NewUUID()
	if err != nil {
		return errors.Trace(err)
	}

	// Create an environment config from the cloud and credentials.
	configAttrs := map[string]interface{}{
		"type":                   cloud.Type,
		"name":                   environs.ControllerModelName,
		config.UUIDKey:           controllerUUID.String(),
		config.ControllerUUIDKey: controllerUUID.String(),
	}
	userConfigAttrs, err := c.config.ReadAttrs(ctx)
	if err != nil {
		return errors.Trace(err)
	}
	for k, v := range userConfigAttrs {
		configAttrs[k] = v
	}
	logger.Debugf("preparing controller with config: %v", configAttrs)

	// Read existing current controller, account, model so we can clean up on error.
	var oldCurrentController string
	oldCurrentController, err = modelcmd.ReadCurrentController()
	if err != nil {
		return errors.Annotate(err, "error reading current controller")
	}

	defer func() {
		if resultErr == nil || errors.IsAlreadyExists(resultErr) {
			return
		}
		if oldCurrentController != "" {
			if err := modelcmd.WriteCurrentController(oldCurrentController); err != nil {
				logger.Warningf(
					"cannot reset current controller to %q: %v",
					oldCurrentController, err,
				)
			}
		}
		if err := store.RemoveController(c.controllerName); err != nil {
			logger.Warningf(
				"cannot destroy newly created controller %q details: %v",
				c.controllerName, err,
			)
		}
	}()

	environ, err := environsPrepare(
		modelcmd.BootstrapContext(ctx), store,
		environs.PrepareParams{
			BaseConfig:           configAttrs,
			ControllerName:       c.controllerName,
			CloudName:            c.Cloud,
			CloudRegion:          region.Name,
			CloudEndpoint:        region.Endpoint,
			CloudStorageEndpoint: region.StorageEndpoint,
			Credential:           *credential,
			CredentialName:       credentialName,
		},
	)
	if err != nil {
		return errors.Trace(err)
	}

	// Set the current model to the initial hosted model.
	accountName, err := store.CurrentAccount(c.controllerName)
	if err != nil {
		return errors.Trace(err)
	}
	if err := store.UpdateModel(c.controllerName, accountName, c.hostedModelName, jujuclient.ModelDetails{
		hostedModelUUID.String(),
	}); err != nil {
		return errors.Trace(err)
	}
	if err := store.SetCurrentModel(c.controllerName, accountName, c.hostedModelName); err != nil {
		return errors.Trace(err)
	}

	// Set the current controller so "juju status" can be run while
	// bootstrapping is underway.
	if err := modelcmd.WriteCurrentController(c.controllerName); err != nil {
		return errors.Trace(err)
	}

	cloudRegion := c.Cloud
	if region.Name != "" {
		cloudRegion = fmt.Sprintf("%s/%s", cloudRegion, region.Name)
	}
	ctx.Infof(
		"Creating Juju controller %q on %s",
		c.controllerName, cloudRegion,
	)

	// If we error out for any reason, clean up the environment.
	defer func() {
		if resultErr != nil {
			if c.KeepBrokenEnvironment {
				logger.Warningf(`
bootstrap failed but --keep-broken was specified so model is not being destroyed.
When you are finished diagnosing the problem, remember to run juju destroy-model --force
to clean up the model.`[1:])
			} else {
				handleBootstrapError(ctx, resultErr, func() error {
					return environsDestroy(
						c.controllerName, environ, store,
					)
				})
			}
		}
	}()

	// 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)
	}

	// 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)

	hostedModelConfig := map[string]interface{}{
		"name":         c.hostedModelName,
		config.UUIDKey: hostedModelUUID.String(),
	}

	// We copy across any user supplied attributes to the hosted model config.
	// But only if the attributes have not been removed from the controller
	// model config as part of preparing the controller model.
	controllerConfigAttrs := environ.Config().AllAttrs()
	for k, v := range userConfigAttrs {
		if _, ok := controllerConfigAttrs[k]; ok {
			hostedModelConfig[k] = v
		}
	}
	// Ensure that certain config attributes are not included in the hosted
	// model config. These attributes may be modified during bootstrap; by
	// removing them from this map, we ensure the modified values are
	// inherited.
	delete(hostedModelConfig, config.AuthKeysConfig)
	delete(hostedModelConfig, config.AgentVersionKey)

	// Check whether the Juju GUI must be installed in the controller.
	// Leaving this value empty means no GUI will be installed.
	var guiDataSourceBaseURL string
	if !c.noGUI {
		guiDataSourceBaseURL = common.GUIDataSourceBaseURL()
	}

	err = bootstrapFuncs.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{
		ModelConstraints:     c.Constraints,
		BootstrapConstraints: bootstrapConstraints,
		BootstrapSeries:      c.BootstrapSeries,
		BootstrapImage:       c.BootstrapImage,
		Placement:            c.Placement,
		UploadTools:          c.UploadTools,
		AgentVersion:         c.AgentVersion,
		MetadataDir:          metadataDir,
		HostedModelConfig:    hostedModelConfig,
		GUIDataSourceBaseURL: guiDataSourceBaseURL,
	})
	if err != nil {
		return errors.Annotate(err, "failed to bootstrap model")
	}

	if err := c.SetModelName(c.hostedModelName); err != nil {
		return errors.Trace(err)
	}

	err = c.setBootstrapEndpointAddress(environ)
	if err != nil {
		return errors.Annotate(err, "saving bootstrap endpoint address")
	}

	// To avoid race conditions when running scripted bootstraps, wait
	// for the controller's machine agent to be ready to accept commands
	// before exiting this bootstrap command.
	return c.waitForAgentInitialisation(ctx)
}
Example #9
0
func (s *filesSuite) assertCurrentController(c *gc.C, controllerName string) {
	current, err := modelcmd.ReadCurrentController()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(current, gc.Equals, controllerName)
}