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  }