This repository is currently being migrated. It's locked while the migration is in progress.
forked from hashicorp/consul
-
Notifications
You must be signed in to change notification settings - Fork 0
/
acl.go
172 lines (143 loc) · 4.31 KB
/
acl.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package state
import (
"fmt"
"github.com/hashicorp/consul/agent/consul/structs"
"github.com/hashicorp/go-memdb"
)
// ACLs is used to pull all the ACLs from the snapshot.
func (s *Snapshot) ACLs() (memdb.ResultIterator, error) {
iter, err := s.tx.Get("acls", "id")
if err != nil {
return nil, err
}
return iter, nil
}
// ACL is used when restoring from a snapshot. For general inserts, use ACLSet.
func (s *Restore) ACL(acl *structs.ACL) error {
if err := s.tx.Insert("acls", acl); err != nil {
return fmt.Errorf("failed restoring acl: %s", err)
}
if err := indexUpdateMaxTxn(s.tx, acl.ModifyIndex, "acls"); err != nil {
return fmt.Errorf("failed updating index: %s", err)
}
return nil
}
// ACLSet is used to insert an ACL rule into the state store.
func (s *Store) ACLSet(idx uint64, acl *structs.ACL) error {
tx := s.db.Txn(true)
defer tx.Abort()
// Call set on the ACL
if err := s.aclSetTxn(tx, idx, acl); err != nil {
return err
}
tx.Commit()
return nil
}
// aclSetTxn is the inner method used to insert an ACL rule with the
// proper indexes into the state store.
func (s *Store) aclSetTxn(tx *memdb.Txn, idx uint64, acl *structs.ACL) error {
// Check that the ID is set
if acl.ID == "" {
return ErrMissingACLID
}
// Check for an existing ACL
existing, err := tx.First("acls", "id", acl.ID)
if err != nil {
return fmt.Errorf("failed acl lookup: %s", err)
}
// Set the indexes
if existing != nil {
acl.CreateIndex = existing.(*structs.ACL).CreateIndex
acl.ModifyIndex = idx
} else {
acl.CreateIndex = idx
acl.ModifyIndex = idx
}
// Insert the ACL
if err := tx.Insert("acls", acl); err != nil {
return fmt.Errorf("failed inserting acl: %s", err)
}
if err := tx.Insert("index", &IndexEntry{"acls", idx}); err != nil {
return fmt.Errorf("failed updating index: %s", err)
}
return nil
}
// ACLGet is used to look up an existing ACL by ID.
func (s *Store) ACLGet(ws memdb.WatchSet, aclID string) (uint64, *structs.ACL, error) {
tx := s.db.Txn(false)
defer tx.Abort()
// Get the table index.
idx := maxIndexTxn(tx, "acls")
// Query for the existing ACL
watchCh, acl, err := tx.FirstWatch("acls", "id", aclID)
if err != nil {
return 0, nil, fmt.Errorf("failed acl lookup: %s", err)
}
ws.Add(watchCh)
if acl != nil {
return idx, acl.(*structs.ACL), nil
}
return idx, nil, nil
}
// ACLList is used to list out all of the ACLs in the state store.
func (s *Store) ACLList(ws memdb.WatchSet) (uint64, structs.ACLs, error) {
tx := s.db.Txn(false)
defer tx.Abort()
// Get the table index.
idx := maxIndexTxn(tx, "acls")
// Return the ACLs.
acls, err := s.aclListTxn(tx, ws)
if err != nil {
return 0, nil, fmt.Errorf("failed acl lookup: %s", err)
}
return idx, acls, nil
}
// aclListTxn is used to list out all of the ACLs in the state store. This is a
// function vs. a method so it can be called from the snapshotter.
func (s *Store) aclListTxn(tx *memdb.Txn, ws memdb.WatchSet) (structs.ACLs, error) {
// Query all of the ACLs in the state store
iter, err := tx.Get("acls", "id")
if err != nil {
return nil, fmt.Errorf("failed acl lookup: %s", err)
}
ws.Add(iter.WatchCh())
// Go over all of the ACLs and build the response
var result structs.ACLs
for acl := iter.Next(); acl != nil; acl = iter.Next() {
a := acl.(*structs.ACL)
result = append(result, a)
}
return result, nil
}
// ACLDelete is used to remove an existing ACL from the state store. If
// the ACL does not exist this is a no-op and no error is returned.
func (s *Store) ACLDelete(idx uint64, aclID string) error {
tx := s.db.Txn(true)
defer tx.Abort()
// Call the ACL delete
if err := s.aclDeleteTxn(tx, idx, aclID); err != nil {
return err
}
tx.Commit()
return nil
}
// aclDeleteTxn is used to delete an ACL from the state store within
// an existing transaction.
func (s *Store) aclDeleteTxn(tx *memdb.Txn, idx uint64, aclID string) error {
// Look up the existing ACL
acl, err := tx.First("acls", "id", aclID)
if err != nil {
return fmt.Errorf("failed acl lookup: %s", err)
}
if acl == nil {
return nil
}
// Delete the ACL from the state store and update indexes
if err := tx.Delete("acls", acl); err != nil {
return fmt.Errorf("failed deleting acl: %s", err)
}
if err := tx.Insert("index", &IndexEntry{"acls", idx}); err != nil {
return fmt.Errorf("failed updating index: %s", err)
}
return nil
}