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 any) 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
}
|