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