// 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) }
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") }
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") }
// 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) }
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") }
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") }
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") }
// 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) }
func (s *filesSuite) assertCurrentController(c *gc.C, controllerName string) { current, err := modelcmd.ReadCurrentController() c.Assert(err, jc.ErrorIsNil) c.Assert(current, gc.Equals, controllerName) }