-
Notifications
You must be signed in to change notification settings - Fork 4
/
group.go
116 lines (102 loc) · 2.41 KB
/
group.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
package etcdpasswd
import (
"context"
"errors"
"strconv"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/clientv3util"
)
// Group represents attributes of a group.
type Group struct {
Name string
GID int
}
// ListGroups lists all groups registered in the database.
// The result is sorted alphabetically.
func (c Client) ListGroups(ctx context.Context) ([]Group, error) {
prefix := KeyGroups
resp, err := c.Get(ctx, prefix, clientv3.WithPrefix(),
clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend))
if err != nil {
return nil, err
}
ret := make([]Group, resp.Count)
for i, kv := range resp.Kvs {
gid, err := strconv.Atoi(string(kv.Value))
if err != nil {
return nil, err
}
ret[i] = Group{string(kv.Key[len(prefix):]), gid}
}
return ret, nil
}
// AddGroup adds a new managed group to the database.
// If a group having the same name already exists, ErrExists will be returned.
func (c Client) AddGroup(ctx context.Context, name string) error {
cfg, _, err := c.GetConfig(ctx)
if err != nil {
return err
}
if cfg.StartGID == 0 {
// not yet configured
return errors.New("start-gid has not been set")
}
if !IsValidGroupName(name) {
return errors.New("invalid group name: " + name)
}
key := KeyGroups + name
delKey := KeyDeletedGroups + name
RETRY:
gid, rev, err := c.getLastID(ctx, KeyLastGID, cfg.StartGID)
if err != nil {
return err
}
gidStr := strconv.Itoa(gid)
nextGID := strconv.Itoa(gid + 1)
resp, err := c.Txn(ctx).
If(
clientv3.Compare(clientv3.ModRevision(KeyLastGID), "=", rev),
).
Then(
clientv3.OpTxn(
[]clientv3.Cmp{clientv3util.KeyMissing(key)},
[]clientv3.Op{
clientv3.OpPut(KeyLastGID, nextGID),
clientv3.OpPut(key, gidStr),
clientv3.OpDelete(delKey),
},
nil,
),
).
Commit()
if err != nil {
return err
}
if !resp.Succeeded {
goto RETRY
}
if !resp.Responses[0].GetResponseTxn().Succeeded {
return ErrExists
}
return nil
}
// RemoveGroup removes an existing managed group.
// If the group does not exist, ErrNotFound will be returned.
func (c Client) RemoveGroup(ctx context.Context, name string) error {
key := KeyGroups + name
delKey := KeyDeletedGroups + name
resp, err := c.Txn(ctx).
If(clientv3util.KeyExists(key)).
Then(
clientv3.OpDelete(key),
clientv3.OpPut(delKey, ""),
).
Commit()
if err != nil {
return err
}
if !resp.Succeeded {
return ErrNotFound
}
return nil
}