gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/client/users.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package client 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "fmt" 26 ) 27 28 // CreateUserResult holds the result of a user creation. 29 type CreateUserResult struct { 30 Username string `json:"username"` 31 SSHKeys []string `json:"ssh-keys"` 32 } 33 34 // CreateUserOptions holds options for creating a local system user. 35 // 36 // If Known is false, the provided email is used to query the store for 37 // username and SSH key details. 38 // 39 // If Known is true, the user will be created by looking through existing 40 // system-user assertions and looking for a matching email. If Email is 41 // empty then all such assertions are considered and multiple users may 42 // be created. 43 type CreateUserOptions struct { 44 Email string `json:"email,omitempty"` 45 Sudoer bool `json:"sudoer,omitempty"` 46 Known bool `json:"known,omitempty"` 47 ForceManaged bool `json:"force-managed,omitempty"` 48 // Automatic is for internal snapd use, behavior might evolve 49 Automatic bool `json:"automatic,omitempty"` 50 } 51 52 // RemoveUserOptions holds options for removing a local system user. 53 type RemoveUserOptions struct { 54 // Username indicates which user to remove. 55 Username string `json:"username,omitempty"` 56 } 57 58 type userAction struct { 59 Action string `json:"action"` 60 *CreateUserOptions 61 *RemoveUserOptions 62 } 63 64 func (client *Client) doUserAction(act *userAction, result interface{}) error { 65 data, err := json.Marshal(act) 66 if err != nil { 67 return err 68 } 69 70 _, err = client.doSync("POST", "/v2/users", nil, nil, bytes.NewReader(data), result) 71 return err 72 } 73 74 // CreateUser creates a local system user. See CreateUserOptions for details. 75 func (client *Client) CreateUser(options *CreateUserOptions) (*CreateUserResult, error) { 76 if options == nil || options.Email == "" { 77 return nil, fmt.Errorf("cannot create a user without providing an email") 78 } 79 80 var result []*CreateUserResult 81 err := client.doUserAction(&userAction{Action: "create", CreateUserOptions: options}, &result) 82 if err != nil { 83 return nil, fmt.Errorf("while creating user: %v", err) 84 } 85 return result[0], nil 86 } 87 88 // CreateUsers creates multiple local system users. See CreateUserOptions for details. 89 // 90 // Results may be provided even if there are errors. 91 func (client *Client) CreateUsers(options []*CreateUserOptions) ([]*CreateUserResult, error) { 92 for _, opts := range options { 93 if opts == nil || (opts.Email == "" && !(opts.Known || opts.Automatic)) { 94 return nil, fmt.Errorf("cannot create user from store details without an email to query for") 95 } 96 } 97 98 var results []*CreateUserResult 99 var errs []error 100 for _, opts := range options { 101 var result []*CreateUserResult 102 err := client.doUserAction(&userAction{Action: "create", CreateUserOptions: opts}, &result) 103 if err != nil { 104 errs = append(errs, err) 105 } else { 106 results = append(results, result...) 107 } 108 } 109 110 if len(errs) == 1 { 111 return results, errs[0] 112 } 113 if len(errs) > 1 { 114 var buf bytes.Buffer 115 for _, err := range errs { 116 fmt.Fprintf(&buf, "\n- %s", err) 117 } 118 return results, fmt.Errorf("while creating users:%s", buf.Bytes()) 119 } 120 return results, nil 121 } 122 123 // RemoveUser removes a local system user. 124 func (client *Client) RemoveUser(options *RemoveUserOptions) (removed []*User, err error) { 125 if options == nil || options.Username == "" { 126 return nil, fmt.Errorf("cannot remove a user without providing a username") 127 } 128 var result struct { 129 Removed []*User `json:"removed"` 130 } 131 if err := client.doUserAction(&userAction{Action: "remove", RemoveUserOptions: options}, &result); err != nil { 132 return nil, err 133 } 134 return result.Removed, nil 135 } 136 137 // Users returns the local users. 138 func (client *Client) Users() ([]*User, error) { 139 var result []*User 140 141 if _, err := client.doSync("GET", "/v2/users", nil, nil, nil, &result); err != nil { 142 return nil, fmt.Errorf("while getting users: %v", err) 143 } 144 return result, nil 145 }