github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/user/list.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for infos.
     3  
     4  package user
     5  
     6  import (
     7  	"io"
     8  
     9  	"github.com/juju/ansiterm"
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/gnuflag"
    13  	"github.com/juju/utils/clock"
    14  	"github.com/juju/utils/set"
    15  	"gopkg.in/juju/names.v2"
    16  
    17  	"github.com/juju/juju/api/usermanager"
    18  	"github.com/juju/juju/apiserver/params"
    19  	"github.com/juju/juju/cmd/juju/common"
    20  	"github.com/juju/juju/cmd/modelcmd"
    21  	"github.com/juju/juju/cmd/output"
    22  )
    23  
    24  var usageListUsersSummary = `
    25  Lists Juju users allowed to connect to a controller or model.`[1:]
    26  
    27  var usageListUsersDetails = `
    28  When used without a model name argument, users relevant to a controller are printed.
    29  When used with a model name, users relevant to the specified model are printed.
    30  
    31  Examples:
    32      Print the users relevant to the current controller: 
    33      juju users
    34      
    35      Print the users relevant to the controller "another":
    36      juju users -c another
    37  
    38      Print the users relevant to the model "mymodel":
    39      juju users mymodel
    40  
    41  See also: 
    42      add-user
    43      register
    44      show-user
    45      disable-user
    46      enable-user`[1:]
    47  
    48  func NewListCommand() cmd.Command {
    49  	return modelcmd.WrapController(&listCommand{
    50  		infoCommandBase: infoCommandBase{
    51  			clock: clock.WallClock,
    52  		},
    53  	})
    54  }
    55  
    56  // listCommand shows all the users in the Juju server.
    57  type listCommand struct {
    58  	infoCommandBase
    59  	modelUserAPI modelUsersAPI
    60  
    61  	All         bool
    62  	modelName   string
    63  	currentUser string
    64  }
    65  
    66  // ModelUsersAPI defines the methods on the client API that the
    67  // users command calls.
    68  type modelUsersAPI interface {
    69  	Close() error
    70  	ModelUserInfo() ([]params.ModelUserInfo, error)
    71  }
    72  
    73  func (c *listCommand) getModelAPI() (modelUsersAPI, error) {
    74  	if c.modelUserAPI != nil {
    75  		return c.modelUserAPI, nil
    76  	}
    77  	conn, err := c.NewModelAPIRoot(c.modelName)
    78  	if err != nil {
    79  		return nil, errors.Trace(err)
    80  	}
    81  	return conn.Client(), nil
    82  }
    83  
    84  // Info implements Command.Info.
    85  func (c *listCommand) Info() *cmd.Info {
    86  	return &cmd.Info{
    87  		Name:    "users",
    88  		Purpose: usageListUsersSummary,
    89  		Doc:     usageListUsersDetails,
    90  		Aliases: []string{"list-users"},
    91  	}
    92  }
    93  
    94  // SetFlags implements Command.SetFlags.
    95  func (c *listCommand) SetFlags(f *gnuflag.FlagSet) {
    96  	c.infoCommandBase.SetFlags(f)
    97  	f.BoolVar(&c.All, "all", false, "Include disabled users")
    98  	c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{
    99  		"yaml":    cmd.FormatYaml,
   100  		"json":    cmd.FormatJson,
   101  		"tabular": c.formatTabular,
   102  	})
   103  }
   104  
   105  // Init implements Command.Init.
   106  func (c *listCommand) Init(args []string) (err error) {
   107  	c.modelName, err = cmd.ZeroOrOneArgs(args)
   108  	if err != nil {
   109  		return err
   110  	}
   111  	return err
   112  }
   113  
   114  // Run implements Command.Run.
   115  func (c *listCommand) Run(ctx *cmd.Context) (err error) {
   116  	if c.out.Name() == "tabular" {
   117  		// Only the tabular outputters need to know the current user,
   118  		// but both of them do, so do it in one place.
   119  		accountDetails, err := c.ClientStore().AccountDetails(c.ControllerName())
   120  		if err != nil {
   121  			return err
   122  		}
   123  		c.currentUser = names.NewUserTag(accountDetails.User).Id()
   124  	}
   125  	if c.modelName == "" {
   126  		return c.controllerUsers(ctx)
   127  	}
   128  	return c.modelUsers(ctx)
   129  }
   130  
   131  func (c *listCommand) modelUsers(ctx *cmd.Context) error {
   132  	client, err := c.getModelAPI()
   133  	if err != nil {
   134  		return err
   135  	}
   136  	defer client.Close()
   137  
   138  	result, err := client.ModelUserInfo()
   139  	if err != nil {
   140  		return err
   141  	}
   142  	if len(result) == 0 {
   143  		ctx.Infof("No users to display.")
   144  		return nil
   145  	}
   146  	return c.out.Write(ctx, common.ModelUserInfoFromParams(result, c.clock.Now()))
   147  }
   148  
   149  func (c *listCommand) controllerUsers(ctx *cmd.Context) error {
   150  	// Note: the InfoCommandBase and the UserInfo struct are defined
   151  	// in info.go.
   152  	client, err := c.getUserInfoAPI()
   153  	if err != nil {
   154  		return err
   155  	}
   156  	defer client.Close()
   157  
   158  	result, err := client.UserInfo(nil, usermanager.IncludeDisabled(c.All))
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	if len(result) == 0 {
   164  		ctx.Infof("No users to display.")
   165  		return nil
   166  	}
   167  
   168  	return c.out.Write(ctx, c.apiUsersToUserInfoSlice(result))
   169  }
   170  
   171  func (c *listCommand) formatTabular(writer io.Writer, value interface{}) error {
   172  	if c.modelName == "" {
   173  		return c.formatControllerUsers(writer, value)
   174  	}
   175  	return c.formatModelUsers(writer, value)
   176  }
   177  
   178  func (c *listCommand) isLoggedInUser(username string) bool {
   179  	tag := names.NewUserTag(username)
   180  	return tag.Id() == c.currentUser
   181  }
   182  
   183  func (c *listCommand) formatModelUsers(writer io.Writer, value interface{}) error {
   184  	users, ok := value.(map[string]common.ModelUserInfo)
   185  	if !ok {
   186  		return errors.Errorf("expected value of type %T, got %T", users, value)
   187  	}
   188  	modelUsers := set.NewStrings()
   189  	for name := range users {
   190  		modelUsers.Add(name)
   191  	}
   192  	tw := output.TabWriter(writer)
   193  	w := output.Wrapper{tw}
   194  	w.Println("Name", "Display name", "Access", "Last connection")
   195  	for _, name := range modelUsers.SortedValues() {
   196  		user := users[name]
   197  
   198  		var highlight *ansiterm.Context
   199  		userName := name
   200  		if c.isLoggedInUser(name) {
   201  			userName += "*"
   202  			highlight = output.CurrentHighlight
   203  		}
   204  		w.PrintColor(highlight, userName)
   205  		w.Println(user.DisplayName, user.Access, user.LastConnection)
   206  	}
   207  	tw.Flush()
   208  	return nil
   209  }
   210  
   211  func (c *listCommand) formatControllerUsers(writer io.Writer, value interface{}) error {
   212  	users, valueConverted := value.([]UserInfo)
   213  	if !valueConverted {
   214  		return errors.Errorf("expected value of type %T, got %T", users, value)
   215  	}
   216  
   217  	tw := output.TabWriter(writer)
   218  	w := output.Wrapper{tw}
   219  	w.Println("Controller: " + c.ControllerName())
   220  	w.Println()
   221  	w.Println("Name", "Display name", "Access", "Date created", "Last connection")
   222  	for _, user := range users {
   223  		conn := user.LastConnection
   224  		if user.Disabled {
   225  			conn += " (disabled)"
   226  		}
   227  		var highlight *ansiterm.Context
   228  		userName := user.Username
   229  		if c.isLoggedInUser(user.Username) {
   230  			userName += "*"
   231  			highlight = output.CurrentHighlight
   232  		}
   233  		w.PrintColor(highlight, userName)
   234  		w.Println(user.DisplayName, user.Access, user.DateCreated, conn)
   235  	}
   236  	tw.Flush()
   237  	return nil
   238  }