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