github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/cloud/showcredential.go (about)

     1  // Copyright 2018 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  
    11  	apicloud "github.com/juju/juju/api/cloud"
    12  	"github.com/juju/juju/apiserver/params"
    13  	jujucmd "github.com/juju/juju/cmd"
    14  	"github.com/juju/juju/cmd/modelcmd"
    15  	"github.com/juju/juju/jujuclient"
    16  )
    17  
    18  type showCredentialCommand struct {
    19  	modelcmd.CommandBase
    20  	store jujuclient.ClientStore
    21  
    22  	out cmd.Output
    23  
    24  	newAPIFunc func() (CredentialContentAPI, error)
    25  
    26  	CloudName      string
    27  	CredentialName string
    28  
    29  	ShowSecrets bool
    30  }
    31  
    32  // NewShowCredentialCommand returns a command to show information about
    33  // credentials stored on the controller.
    34  func NewShowCredentialCommand() cmd.Command {
    35  	cmd := &showCredentialCommand{
    36  		store: jujuclient.NewFileClientStore(),
    37  	}
    38  	cmd.newAPIFunc = func() (CredentialContentAPI, error) {
    39  		return cmd.NewCredentialAPI()
    40  	}
    41  	return modelcmd.WrapBase(cmd)
    42  }
    43  
    44  func (c *showCredentialCommand) SetFlags(f *gnuflag.FlagSet) {
    45  	c.CommandBase.SetFlags(f)
    46  	// We only support yaml for display purposes.
    47  	c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{
    48  		"yaml": cmd.FormatYaml,
    49  	})
    50  	f.BoolVar(&c.ShowSecrets, "show-secrets", false, "Display credential secret attributes")
    51  }
    52  
    53  func (c *showCredentialCommand) Init(args []string) error {
    54  	switch len(args) {
    55  	case 0:
    56  		// will get all credentials stored on the controller for this user.
    57  		break
    58  	case 1:
    59  		return errors.New("both cloud and credential name are needed")
    60  	case 2:
    61  		c.CloudName = args[0]
    62  		c.CredentialName = args[1]
    63  	default:
    64  		return errors.New("only cloud and credential names are supported")
    65  	}
    66  	return nil
    67  }
    68  
    69  func (c *showCredentialCommand) Info() *cmd.Info {
    70  	return jujucmd.Info(&cmd.Info{
    71  		Name:    "show-credential",
    72  		Args:    "[<cloud name> <credential name>]",
    73  		Purpose: "Shows credential information on a controller.",
    74  		Doc:     showCredentialDoc,
    75  		Aliases: []string{"show-credentials"},
    76  	})
    77  }
    78  
    79  func (c *showCredentialCommand) Run(ctxt *cmd.Context) error {
    80  	client, err := c.newAPIFunc()
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer client.Close()
    85  
    86  	if client.BestAPIVersion() < 2 {
    87  		ctxt.Infof("credential content lookup is not supported by this version of Juju")
    88  		return nil
    89  	}
    90  	contents, err := client.CredentialContents(c.CloudName, c.CredentialName, c.ShowSecrets)
    91  	if err != nil {
    92  		ctxt.Infof("Getting credential content failed with: %v", err)
    93  		return err
    94  	}
    95  	return c.parseContents(ctxt, contents)
    96  }
    97  
    98  type CredentialContentAPI interface {
    99  	CredentialContents(cloud, credential string, withSecrets bool) ([]params.CredentialContentResult, error)
   100  	BestAPIVersion() int
   101  	Close() error
   102  }
   103  
   104  func (c *showCredentialCommand) NewCredentialAPI() (CredentialContentAPI, error) {
   105  	currentController, err := c.store.CurrentController()
   106  	if err != nil {
   107  		if errors.IsNotFound(err) {
   108  			return nil, errors.New("there is no active controller")
   109  		}
   110  		return nil, errors.Trace(err)
   111  	}
   112  	api, err := c.NewAPIRoot(c.store, currentController, "")
   113  	if err != nil {
   114  		return nil, errors.Annotate(err, "opening API connection")
   115  	}
   116  	return apicloud.NewClient(api), nil
   117  }
   118  
   119  type CredentialContent struct {
   120  	AuthType   string            `yaml:"auth-type"`
   121  	Attributes map[string]string `yaml:",inline"`
   122  }
   123  
   124  type CredentialDetails struct {
   125  	Content CredentialContent `yaml:"content"`
   126  	Models  map[string]string `yaml:"models"`
   127  }
   128  
   129  type NamedCredentials map[string]CredentialDetails
   130  
   131  type CloudCredentials map[string]NamedCredentials
   132  
   133  type ControllerCredentials struct {
   134  	All CloudCredentials `yaml:"controller-credentials"`
   135  }
   136  
   137  func (c *showCredentialCommand) parseContents(ctxt *cmd.Context, in []params.CredentialContentResult) error {
   138  	if len(in) == 0 {
   139  		ctxt.Infof("No credential to display")
   140  		return nil
   141  	}
   142  
   143  	out := CloudCredentials{}
   144  	for _, result := range in {
   145  		if result.Error != nil {
   146  			ctxt.Infof("%v", result.Error)
   147  			continue
   148  		}
   149  
   150  		info := result.Result
   151  		_, ok := out[info.Content.Cloud]
   152  		if !ok {
   153  			out[info.Content.Cloud] = NamedCredentials{}
   154  			//cloudGroup = out[info.Content.Cloud]
   155  		}
   156  
   157  		models := make(map[string]string, len(info.Models))
   158  		for _, m := range info.Models {
   159  			ownerAccess := m.Access
   160  			if ownerAccess == "" {
   161  				ownerAccess = "no access"
   162  			}
   163  			models[m.Model] = ownerAccess
   164  		}
   165  		out[info.Content.Cloud][info.Content.Name] = CredentialDetails{
   166  			Content: CredentialContent{
   167  				AuthType:   info.Content.AuthType,
   168  				Attributes: info.Content.Attributes,
   169  			},
   170  			Models: models,
   171  		}
   172  	}
   173  	return c.out.Write(ctxt, ControllerCredentials{out})
   174  }
   175  
   176  var showCredentialDoc = `
   177  This command displays information about credential(s) stored on the controller
   178  for this user.
   179  
   180  To see the contents of a specific credential, supply its cloud and name.
   181  To see all credentials stored for you, supply no arguments.
   182  
   183  To see secrets, content attributes marked as hidden, use --show-secrets option.
   184  
   185  To see locally stored credentials, use "juju credentials' command.
   186  
   187  Examples:
   188  
   189      juju show-credential google my-admin-credential
   190      juju show-credentials 
   191      juju show-credentials --show-secrets
   192  
   193  See also: 
   194      credentials
   195  `