github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/cloud/updatecredential.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloud 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 "github.com/juju/gnuflag" 10 "gopkg.in/juju/names.v2" 11 12 apicloud "github.com/juju/juju/api/cloud" 13 "github.com/juju/juju/apiserver/params" 14 jujucloud "github.com/juju/juju/cloud" 15 jujucmd "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/juju/common" 17 "github.com/juju/juju/cmd/modelcmd" 18 ) 19 20 var usageUpdateCredentialSummary = ` 21 Updates a controller credential for a cloud.`[1:] 22 23 var usageUpdateCredentialDetails = ` 24 Cloud credentials for controller are used for model operations and manipulations. 25 Since it is common to have long-running models, it is also common to 26 have these cloud credentials become invalid during models' lifetime. 27 When this happens, a user must update the cloud credential that 28 a model was created with to the new and valid details on controller. 29 30 This command allows to update an existing, already-stored, named, 31 cloud-specific controller credential. 32 33 NOTE: 34 This is the only command that will allow you to manipulate cloud 35 credential for a controller. 36 All other credential related commands, such as 37 ` + "`add-credential`" + `, ` + "`remove-credential`" + ` and ` + "`credentials`" + ` 38 deal with credentials stored locally on the client not on the controller. 39 40 Examples: 41 juju update-credential aws mysecrets 42 43 See also: 44 add-credential 45 credentials`[1:] 46 47 type updateCredentialCommand struct { 48 modelcmd.ControllerCommandBase 49 50 api credentialAPI 51 52 cloud string 53 credential string 54 } 55 56 // NewUpdateCredentialCommand returns a command to update credential details. 57 func NewUpdateCredentialCommand() cmd.Command { 58 return modelcmd.WrapController(&updateCredentialCommand{}) 59 } 60 61 // Init implements Command.Init. 62 func (c *updateCredentialCommand) Init(args []string) error { 63 if len(args) < 2 { 64 return errors.New("Usage: juju update-credential <cloud-name> <credential-name>") 65 } 66 c.cloud = args[0] 67 c.credential = args[1] 68 return cmd.CheckEmpty(args[2:]) 69 } 70 71 // Info implements Command.Info 72 func (c *updateCredentialCommand) Info() *cmd.Info { 73 return jujucmd.Info(&cmd.Info{ 74 Name: "update-credential", 75 Args: "<cloud-name> <credential-name>", 76 Purpose: usageUpdateCredentialSummary, 77 Doc: usageUpdateCredentialDetails, 78 }) 79 } 80 81 // SetFlags implements Command.SetFlags. 82 func (c *updateCredentialCommand) SetFlags(f *gnuflag.FlagSet) { 83 c.ControllerCommandBase.SetFlags(f) 84 f.StringVar(&c.credential, "credential", "", "Name of credential to update") 85 } 86 87 type credentialAPI interface { 88 UpdateCredentialsCheckModels(tag names.CloudCredentialTag, credential jujucloud.Credential) ([]params.UpdateCredentialModelResult, error) 89 Close() error 90 } 91 92 func (c *updateCredentialCommand) getAPI() (credentialAPI, error) { 93 if c.api != nil { 94 return c.api, nil 95 } 96 api, err := c.NewAPIRoot() 97 if err != nil { 98 return nil, errors.Annotate(err, "opening API connection") 99 } 100 return apicloud.NewClient(api), nil 101 } 102 103 // Run implements Command.Run 104 func (c *updateCredentialCommand) Run(ctx *cmd.Context) error { 105 cloud, err := common.CloudByName(c.cloud) 106 if errors.IsNotFound(err) { 107 ctx.Infof("Cloud %q not found", c.cloud) 108 return nil 109 } else if err != nil { 110 return err 111 } 112 getCredentialsParams := modelcmd.GetCredentialsParams{ 113 Cloud: *cloud, 114 CredentialName: c.credential, 115 } 116 credToUpdate, _, _, err := modelcmd.GetCredentials(ctx, c.ClientStore(), getCredentialsParams) 117 if errors.IsNotFound(err) { 118 ctx.Infof("No credential called %q exists for cloud %q", c.credential, c.cloud) 119 return nil 120 } else if err != nil { 121 return err 122 } 123 accountDetails, err := c.CurrentAccountDetails() 124 if err != nil { 125 return err 126 } 127 credentialTag, err := common.ResolveCloudCredentialTag( 128 names.NewUserTag(accountDetails.User), names.NewCloudTag(c.cloud), c.credential, 129 ) 130 client, err := c.getAPI() 131 if err != nil { 132 return err 133 } 134 defer client.Close() 135 136 models, err := client.UpdateCredentialsCheckModels(credentialTag, *credToUpdate) 137 138 // We always want to display models information if there is any. 139 common.OutputUpdateCredentialModelResult(ctx, models, true) 140 if err != nil { 141 ctx.Infof("Controller credential %q for user %q on cloud %q not updated: %v.", c.credential, accountDetails.User, c.cloud, err) 142 // TODO (anastasiamac 2018-09-21) When set-credential is done, also direct user to it. 143 // Something along the lines of: 144 // " 145 // Failed models may require a different credential. 146 // Use ‘juju set-credential’ to change credential for these models before repeating this update. 147 // " 148 // 149 // We do not want to return err here as we have already displayed it on the console. 150 return cmd.ErrSilent 151 } 152 ctx.Infof(` 153 Controller credential %q for user %q on cloud %q updated. 154 For more information, see ‘juju show-credential %v %v’.`[1:], 155 c.credential, accountDetails.User, c.cloud, 156 c.cloud, c.credential) 157 return nil 158 }