github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/api/usermanager/client.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package usermanager 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 "github.com/juju/names" 13 14 "github.com/juju/juju/api/base" 15 "github.com/juju/juju/apiserver/params" 16 ) 17 18 var logger = loggo.GetLogger("juju.api.usermanager") 19 20 // Client provides methods that the Juju client command uses to interact 21 // with users stored in the Juju Server. 22 type Client struct { 23 base.ClientFacade 24 facade base.FacadeCaller 25 } 26 27 // NewClient creates a new `Client` based on an existing authenticated API 28 // connection. 29 func NewClient(st base.APICallCloser) *Client { 30 frontend, backend := base.NewClientFacade(st, "UserManager") 31 return &Client{ClientFacade: frontend, facade: backend} 32 } 33 34 // AddUser creates a new local user in the juju server. 35 func (c *Client) AddUser(username, displayName, password string) (names.UserTag, error) { 36 if !names.IsValidUser(username) { 37 return names.UserTag{}, fmt.Errorf("invalid user name %q", username) 38 } 39 userArgs := params.AddUsers{ 40 Users: []params.AddUser{{Username: username, DisplayName: displayName, Password: password}}, 41 } 42 var results params.AddUserResults 43 err := c.facade.FacadeCall("AddUser", userArgs, &results) 44 if err != nil { 45 return names.UserTag{}, errors.Trace(err) 46 } 47 if count := len(results.Results); count != 1 { 48 logger.Errorf("expected 1 result, got %#v", results) 49 return names.UserTag{}, errors.Errorf("expected 1 result, got %d", count) 50 } 51 result := results.Results[0] 52 if result.Error != nil { 53 return names.UserTag{}, errors.Trace(result.Error) 54 } 55 tag, err := names.ParseUserTag(result.Tag) 56 if err != nil { 57 return names.UserTag{}, errors.Trace(err) 58 } 59 logger.Infof("created user %s", result.Tag) 60 return tag, nil 61 } 62 63 func (c *Client) userCall(username string, methodCall string) error { 64 if !names.IsValidUserName(username) { 65 return errors.Errorf("%q is not a valid username", username) 66 } 67 tag := names.NewLocalUserTag(username) 68 69 var results params.ErrorResults 70 args := params.Entities{ 71 []params.Entity{{tag.String()}}, 72 } 73 err := c.facade.FacadeCall(methodCall, args, &results) 74 if err != nil { 75 return errors.Trace(err) 76 } 77 return results.OneError() 78 } 79 80 // DisableUser disables a user. If the user is already disabled, the action 81 // is consided a success. 82 func (c *Client) DisableUser(username string) error { 83 return c.userCall(username, "DisableUser") 84 } 85 86 // EnableUser enables a users. If the user is already enabled, the action is 87 // consided a success. 88 func (c *Client) EnableUser(username string) error { 89 return c.userCall(username, "EnableUser") 90 } 91 92 // IncludeDisabled is a type alias to avoid bare true/false values 93 // in calls to the client method. 94 type IncludeDisabled bool 95 96 var ( 97 // ActiveUsers indicates to only return active users. 98 ActiveUsers IncludeDisabled = false 99 // AllUsers indicates that both enabled and disabled users should be 100 // returned. 101 AllUsers IncludeDisabled = true 102 ) 103 104 // UserInfo returns information about the specified users. If no users are 105 // specified, the call should return all users. If includeDisabled is set to 106 // ActiveUsers, only enabled users are returned. 107 func (c *Client) UserInfo(usernames []string, all IncludeDisabled) ([]params.UserInfo, error) { 108 var results params.UserInfoResults 109 var entities []params.Entity 110 for _, username := range usernames { 111 if !names.IsValidUserName(username) { 112 return nil, errors.Errorf("%q is not a valid username", username) 113 } 114 tag := names.NewLocalUserTag(username) 115 entities = append(entities, params.Entity{Tag: tag.String()}) 116 } 117 args := params.UserInfoRequest{ 118 Entities: entities, 119 IncludeDisabled: bool(all), 120 } 121 err := c.facade.FacadeCall("UserInfo", args, &results) 122 if err != nil { 123 return nil, errors.Trace(err) 124 } 125 // Only need to look for errors if users were explicitly specified, because 126 // if we didn't ask for any, we should get all, and we shouldn't get any 127 // errors for listing all. We care here because we index into the users 128 // slice. 129 if len(results.Results) == len(usernames) { 130 var errorStrings []string 131 for i, result := range results.Results { 132 if result.Error != nil { 133 annotated := errors.Annotate(result.Error, usernames[i]) 134 errorStrings = append(errorStrings, annotated.Error()) 135 } 136 } 137 if len(errorStrings) > 0 { 138 return nil, errors.New(strings.Join(errorStrings, ", ")) 139 } 140 } 141 info := []params.UserInfo{} 142 for i, result := range results.Results { 143 if result.Result == nil { 144 return nil, errors.Errorf("unexpected nil result at position %d", i) 145 } 146 info = append(info, *result.Result) 147 } 148 return info, nil 149 } 150 151 // SetPassword changes the password for the specified user. 152 func (c *Client) SetPassword(username, password string) error { 153 if !names.IsValidUserName(username) { 154 return errors.Errorf("%q is not a valid username", username) 155 } 156 tag := names.NewLocalUserTag(username) 157 args := params.EntityPasswords{ 158 Changes: []params.EntityPassword{{ 159 Tag: tag.String(), 160 Password: password}}, 161 } 162 var results params.ErrorResults 163 err := c.facade.FacadeCall("SetPassword", args, &results) 164 if err != nil { 165 return err 166 } 167 return results.OneError() 168 }