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