// Run updates the configuration of a service. func (c *SetCommand) Run(ctx *cmd.Context) error { api, err := c.getAPI() if err != nil { return err } defer api.Close() if c.SettingsYAML.Path != "" { b, err := c.SettingsYAML.Read(ctx) if err != nil { return err } return block.ProcessBlockedError(api.ServiceSetYAML(c.ServiceName, string(b)), block.BlockChange) } else if len(c.SettingsStrings) == 0 { return nil } settings := map[string]string{} for k, v := range c.SettingsStrings { //empty string is also valid as a setting value if v == "" { settings[k] = v continue } if v[0] != '@' { if !utf8.ValidString(v) { return fmt.Errorf("value for option %q contains non-UTF-8 sequences", k) } settings[k] = v continue } nv, err := readValue(ctx, v[1:]) if err != nil { return err } if !utf8.ValidString(nv) { return fmt.Errorf("value for option %q contains non-UTF-8 sequences", k) } settings[k] = nv } result, err := api.ServiceGet(c.ServiceName) if err != nil { return err } for k, v := range settings { configValue := result.Config[k] configValueMap, ok := configValue.(map[string]interface{}) if ok { // convert the value to string and compare if fmt.Sprintf("%v", configValueMap["value"]) == v { logger.Warningf("the configuration setting %q already has the value %q", k, v) } } } return block.ProcessBlockedError(api.ServiceSet(c.ServiceName, settings), block.BlockChange) }
// Run connects to the specified environment and starts the charm // upgrade process. func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() oldURL, err := client.ServiceGetCharmURL(c.ServiceName) if err != nil { return err } conf, err := service.GetClientConfig(client) if err != nil { return errors.Trace(err) } var newRef *charm.Reference if c.SwitchURL != "" { newRef, err = charm.ParseReference(c.SwitchURL) if err != nil { return err } } else { // No new URL specified, but revision might have been. newRef = oldURL.WithRevision(c.Revision).Reference() } httpClient, err := c.HTTPClient() if err != nil { return errors.Trace(err) } csClient := newCharmStoreClient(httpClient) newURL, repo, err := resolveCharmStoreEntityURL(newRef.String(), csClient.params, ctx.AbsPath(c.RepoPath), conf) if err != nil { return errors.Trace(err) } // If no explicit revision was set with either SwitchURL // or Revision flags, discover the latest. if *newURL == *oldURL { if newRef.Revision != -1 { return fmt.Errorf("already running specified charm %q", newURL) } if newURL.Schema == "cs" { // No point in trying to upgrade a charm store charm when // we just determined that's the latest revision // available. return fmt.Errorf("already running latest charm %q", newURL) } } addedURL, err := addCharmViaAPI(client, newURL, repo, csClient) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } ctx.Infof("Added charm %q to the environment.", addedURL) return block.ProcessBlockedError(client.ServiceSetCharm(c.ServiceName, addedURL.String(), c.Force), block.BlockChange) }
// Run connects to the specified environment and starts the charm // upgrade process. func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() serviceClient, err := c.newServiceAPIClient() if err != nil { return err } oldURL, err := serviceClient.GetCharmURL(c.ServiceName) if err != nil { return err } newRef := c.SwitchURL if newRef == "" { newRef = c.CharmPath } if c.SwitchURL == "" && c.CharmPath == "" { // No new URL specified, but revision might have been. newRef = oldURL.WithRevision(c.Revision).String() } bakeryClient, err := c.BakeryClient() if err != nil { return errors.Trace(err) } csClient := newCharmStoreClient(bakeryClient).WithChannel(c.Channel) conf, err := getClientConfig(client) if err != nil { return errors.Trace(err) } resolver := newCharmURLResolver(conf, csClient, ctx.AbsPath(c.RepoPath)) chID, csMac, err := c.addCharm(oldURL, newRef, client, resolver) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } ctx.Infof("Added charm %q to the model.", chID.URL) ids, err := c.upgradeResources(client, chID, csMac) if err != nil { return errors.Trace(err) } cfg := apiservice.SetCharmConfig{ ServiceName: c.ServiceName, CharmID: chID, ForceSeries: c.ForceSeries, ForceUnits: c.ForceUnits, ResourceIDs: ids, } return block.ProcessBlockedError(serviceClient.SetCharm(cfg), block.BlockChange) }
func (s *BlockCommandSuite) processErrorTest(c *gc.C, tstError error, blockType block.Block, expectedError error, expectedWarning string) { if tstError != nil { c.Assert(errors.Cause(block.ProcessBlockedError(tstError, blockType)), gc.Equals, expectedError) } else { c.Assert(block.ProcessBlockedError(tstError, blockType), jc.ErrorIsNil) } // warning displayed logOutputText := strings.Replace(c.GetTestLog(), "\n", "", -1) c.Assert(logOutputText, gc.Matches, expectedWarning) }
// Run connects to the environment specified on the command line // and calls EnsureAvailability. func (c *ensureAvailabilityCommand) Run(ctx *cmd.Context) error { haClient, err := c.getHAClient() if err != nil { return err } defer haClient.Close() ensureAvailabilityResult, err := haClient.EnsureAvailability( c.NumStateServers, c.Constraints, c.Series, c.Placement, ) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } result := availabilityInfo{ Added: machineTagsToIds(ensureAvailabilityResult.Added...), Removed: machineTagsToIds(ensureAvailabilityResult.Removed...), Maintained: machineTagsToIds(ensureAvailabilityResult.Maintained...), Promoted: machineTagsToIds(ensureAvailabilityResult.Promoted...), Demoted: machineTagsToIds(ensureAvailabilityResult.Demoted...), Converted: machineTagsToIds(ensureAvailabilityResult.Converted...), } return c.out.Write(ctx, result) }
// Run implements Command.Run. func (c *addCommand) Run(ctx *cmd.Context) error { if c.api == nil { api, err := c.NewUserManagerAPIClient() if err != nil { return errors.Trace(err) } c.api = api defer c.api.Close() } password, err := utils.RandomPassword() if err != nil { return errors.Annotate(err, "failed to generate random password") } randomPasswordNotify(password) if _, err := c.api.AddUser(c.User, c.DisplayName, password); err != nil { return block.ProcessBlockedError(err, block.BlockChange) } displayName := c.User if c.DisplayName != "" { displayName = fmt.Sprintf("%s (%s)", c.DisplayName, c.User) } ctx.Infof("user %q added", displayName) return writeServerFile(c, ctx, c.User, password, c.OutPath) }
// Run connects to the environment specified on the command line // and calls EnableHA. func (c *enableHACommand) Run(ctx *cmd.Context) error { var err error c.Constraints, err = common.ParseConstraints(ctx, c.ConstraintsStr) if err != nil { return err } haClient, err := c.newHAClientFunc() if err != nil { return err } defer haClient.Close() enableHAResult, err := haClient.EnableHA( c.NumControllers, c.Constraints, c.Placement, ) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } result := availabilityInfo{ Added: machineTagsToIds(enableHAResult.Added...), Removed: machineTagsToIds(enableHAResult.Removed...), Maintained: machineTagsToIds(enableHAResult.Maintained...), Promoted: machineTagsToIds(enableHAResult.Promoted...), Demoted: machineTagsToIds(enableHAResult.Demoted...), Converted: machineTagsToIds(enableHAResult.Converted...), } return c.out.Write(ctx, result) }
func (c *DeployCommand) Run(ctx *cmd.Context) error { var err error c.Constraints, err = common.ParseConstraints(ctx, c.ConstraintsStr) if err != nil { return err } apiRoot, err := c.NewAPIRoot() if err != nil { return errors.Trace(err) } defer apiRoot.Close() deploy, err := findDeployerFIFO( c.maybeReadLocalBundle, c.maybeReadLocalCharm, c.maybePredeployedLocalCharm, c.maybeReadCharmstoreBundleFn(apiRoot), c.charmStoreCharm, // This always returns a deployer ) if err != nil { return errors.Trace(err) } return block.ProcessBlockedError(deploy(ctx, apiRoot), block.BlockChange) }
// setConfig is the run action when we are setting new attribute values as args // or as a file passed in. func (c *configCommand) setConfig(client configCommandAPI, ctx *cmd.Context) error { if c.useFile { return c.setConfigFromFile(client, ctx) } settings, err := c.validateValues(ctx) if err != nil { return errors.Trace(err) } result, err := client.Get(c.applicationName) if err != nil { return err } for k, v := range settings { configValue := result.Config[k] configValueMap, ok := configValue.(map[string]interface{}) if ok { // convert the value to string and compare if fmt.Sprintf("%v", configValueMap["value"]) == v { logger.Warningf("the configuration setting %q already has the value %q", k, v) } } } return block.ProcessBlockedError(client.Set(c.applicationName, settings), block.BlockChange) }
// Run implements Command.Run. func (c *removeCommand) Run(ctx *cmd.Context) error { api := c.api // This is for testing. if api == nil { // The real McCoy. var err error api, err = c.NewUserManagerAPIClient() if err != nil { return errors.Trace(err) } defer api.Close() } // Confirm deletion if the user didn't specify -y/--yes in the command. if !c.ConfirmDelete { if err := confirmDelete(ctx, c.ControllerName(), c.UserName); err != nil { return err } } err := api.RemoveUser(c.UserName) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } fmt.Fprintf(ctx.Stdout, "User %q removed\n", c.UserName) return nil }
// Run implements Command.Run. func (c *changePasswordCommand) Run(ctx *cmd.Context) error { if c.api == nil { api, err := c.NewUserManagerAPIClient() if err != nil { return errors.Trace(err) } c.api = api defer c.api.Close() } password, err := c.generateOrReadPassword(ctx, c.Generate) if err != nil { return errors.Trace(err) } var writer EnvironInfoCredsWriter var creds configstore.APICredentials if c.User == "" { // We get the creds writer before changing the password just to // minimise the things that could go wrong after changing the password // in the server. if c.writer == nil { writer, err = c.ConnectionInfo() if err != nil { return errors.Trace(err) } } else { writer = c.writer } creds = writer.APICredentials() } else { creds.User = c.User } oldPassword := creds.Password creds.Password = password if err = c.api.SetPassword(creds.User, password); err != nil { return block.ProcessBlockedError(err, block.BlockChange) } if c.User != "" { return writeServerFile(c, ctx, c.User, password, c.OutPath) } writer.SetAPICredentials(creds) if err := writer.Write(); err != nil { logger.Errorf("updating the cached credentials failed, reverting to original password") setErr := c.api.SetPassword(creds.User, oldPassword) if setErr != nil { logger.Errorf("failed to set password back, you will need to edit your environments file by hand to specify the password: %q", password) return errors.Annotate(setErr, "failed to set password back") } return errors.Annotate(err, "failed to write new password to environments file") } ctx.Infof("Your password has been updated.") return nil }
// Run resets the configuration of a service. func (c *UnsetCommand) Run(ctx *cmd.Context) error { apiclient, err := c.getAPI() if err != nil { return err } defer apiclient.Close() return block.ProcessBlockedError(apiclient.ServiceUnset(c.ServiceName, c.Options), block.BlockChange) }
// Run changes the juju-managed firewall to expose any // ports that were also explicitly marked by units as open. func (c *exposeCommand) Run(_ *cmd.Context) error { client, err := c.getAPI() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.Expose(c.ApplicationName), block.BlockChange) }
// reset unsets the keys provided to the command. func (c *configCommand) resetConfig(client configCommandAPI, ctx *cmd.Context) error { // ctx unused in this method if err := c.verifyKnownKeys(client); err != nil { return errors.Trace(err) } return block.ProcessBlockedError(client.ModelUnset(c.resetKeys...), block.BlockChange) }
func (c *resolvedCommand) Run(_ *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.Resolved(c.UnitName, c.NoRetry), block.BlockChange) }
func (c *defaultsCommand) setDefaults(client defaultsCommandAPI, ctx *cmd.Context) error { // ctx unused in this method. if err := c.verifyKnownKeys(client); err != nil { return errors.Trace(err) } // TODO(wallyworld) - call with cloud and region when that bit is done return block.ProcessBlockedError(client.SetModelDefaults("", "", c.values), block.BlockChange) }
// Run changes the juju-managed firewall to hide any // ports that were also explicitly marked by units as closed. func (c *unexposeCommand) Run(_ *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.ServiceUnexpose(c.ServiceName), block.BlockChange) }
func (c *removeServiceCommand) Run(_ *cmd.Context) error { client, err := c.getAPI() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.ServiceDestroy(c.ServiceName), block.BlockRemove) }
// Run connects to the environment specified on the command line and destroys // units therein. func (c *RemoveUnitCommand) Run(_ *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.DestroyServiceUnits(c.UnitNames...), block.BlockRemove) }
func (c *removeRelationCommand) Run(_ *cmd.Context) error { client, err := c.getAPI() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.DestroyRelation(c.Endpoints...), block.BlockRemove) }
// Run implements Command.Run. func (c *ChangePasswordCommand) Run(ctx *cmd.Context) error { var err error c.Password, err = c.generateOrReadPassword(ctx, c.Generate) if err != nil { return errors.Trace(err) } var credsWriter EnvironInfoCredsWriter var creds configstore.APICredentials if c.User == "" { // We get the creds writer before changing the password just to // minimise the things that could go wrong after changing the password // in the server. credsWriter, err = getEnvironInfoWriter(c) if err != nil { return errors.Trace(err) } creds, err = getConnectionCredentials(c) if err != nil { return errors.Trace(err) } } else { creds.User = c.User } client, err := getChangePasswordAPI(c) if err != nil { return err } defer client.Close() oldPassword := creds.Password creds.Password = c.Password err = client.SetPassword(creds.User, c.Password) if err != nil { return block.ProcessBlockedError(err, block.BlockChange) } if c.User != "" { return c.writeEnvironmentFile(ctx) } credsWriter.SetAPICredentials(creds) if err := credsWriter.Write(); err != nil { logger.Errorf("updating the environments file failed, reverting to original password") setErr := client.SetPassword(creds.User, oldPassword) if setErr != nil { logger.Errorf("failed to set password back, you will need to edit your environments file by hand to specify the password: %q", c.Password) return errors.Annotate(setErr, "failed to set password back") } return errors.Annotate(err, "failed to write new password to environments file") } ctx.Infof("Your password has been updated.") return nil }
func (c *AddRelationCommand) Run(_ *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() _, err = client.AddRelation(c.Endpoints...) return block.ProcessBlockedError(err, block.BlockChange) }
func (c *unshareCommand) Run(ctx *cmd.Context) error { client, err := c.getAPI() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.UnshareModel(c.Users...), block.BlockChange) }
func (c *revokeCommand) runForController() error { client, err := c.getControllerAPI() if err != nil { return err } defer client.Close() return block.ProcessBlockedError(client.RevokeController(c.User, c.Access), block.BlockChange) }
// setDefaults sets defaults as provided in c.values. func (c *defaultsCommand) setDefaults(client defaultsCommandAPI, ctx *cmd.Context) error { // ctx unused in this method. if err := c.verifyKnownKeys(client); err != nil { return errors.Trace(err) } return block.ProcessBlockedError( client.SetModelDefaults( c.cloudName, c.regionName, c.values), block.BlockChange) }
func (c *destroyCommand) handleError(err error, modelName string) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(`failed to destroy model %q`, modelName) return err }
func (c *serviceSetConstraintsCommand) Run(_ *cmd.Context) (err error) { apiclient, err := c.getAPI() if err != nil { return err } defer apiclient.Close() err = apiclient.SetServiceConstraints(c.ServiceName, c.Constraints) return block.ProcessBlockedError(err, block.BlockChange) }
func (c *DeployCommand) Run(ctx *cmd.Context) error { client, err := c.NewAPIClient() if err != nil { return err } defer client.Close() err = c.deployCharmOrBundle(ctx, client) return block.ProcessBlockedError(err, block.BlockChange) }
func (c *destroyCommand) handleError(err error) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(`failed to destroy environment %q`, c.envName) return err }
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed // in a user-friendly manner with readable and digestable error message. func (c *destroyEnvironmentCommand) ensureUserFriendlyErrorLog(err error) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(stdFailureMsg, c.EnvName()) return err }