mirror of https://github.com/status-im/consul.git
consul/state: basic acl set/get/delete
This commit is contained in:
parent
391d4eed57
commit
16188e7604
|
@ -23,6 +23,10 @@ var (
|
|||
// ErrMissingSessionID is returned when a session registration
|
||||
// is attempted with an empty session ID.
|
||||
ErrMissingSessionID = errors.New("Missing session ID")
|
||||
|
||||
// ErrMissingACLID is returned when a session set is called on
|
||||
// a session with an empty ID.
|
||||
ErrMissingACLID = errors.New("Missing ACL ID")
|
||||
)
|
||||
|
||||
// StateStore is where we store all of Consul's state, including
|
||||
|
@ -897,7 +901,7 @@ func (s *StateStore) KVSDeleteCAS(idx, cidx uint64, key string) (bool, error) {
|
|||
return false, fmt.Errorf("failed kvs lookup: %s", err)
|
||||
}
|
||||
|
||||
// If the existing index does not match the provided CAS
|
||||
// If the existing index does not match the provided CAS
|
||||
// index arg, then we shouldn't update anything and can safely
|
||||
// return early here.
|
||||
e, ok := entry.(*structs.DirEntry)
|
||||
|
@ -1179,3 +1183,66 @@ func (s *StateStore) sessionDestroyTxn(idx uint64, sessionID string, tx *memdb.T
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ACLSet is used to insert an ACL rule into the state store.
|
||||
func (s *StateStore) ACLSet(idx uint64, acl *structs.ACL) error {
|
||||
tx := s.db.Txn(true)
|
||||
defer tx.Abort()
|
||||
|
||||
// Call set on the ACL
|
||||
if err := s.aclSetTxn(idx, acl, tx); 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 *StateStore) aclSetTxn(idx uint64, acl *structs.ACL, tx *memdb.Txn) 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 *StateStore) ACLGet(aclID string) (*structs.ACL, error) {
|
||||
tx := s.db.Txn(false)
|
||||
defer tx.Abort()
|
||||
|
||||
// Query for the existing ACL
|
||||
acl, err := tx.First("acls", "id", aclID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed acl lookup: %s", err)
|
||||
}
|
||||
if acl != nil {
|
||||
return acl.(*structs.ACL), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -1477,3 +1477,91 @@ func TestStateStore_SessionDestroy(t *testing.T) {
|
|||
t.Fatalf("bad index: %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateStore_ACLSet(t *testing.T) {
|
||||
s := testStateStore(t)
|
||||
|
||||
// Querying ACL's with no results returns nil
|
||||
res, err := s.ACLGet("nope")
|
||||
if res != nil || err != nil {
|
||||
t.Fatalf("expected (nil, nil), got: (%#v, %#v)", res, err)
|
||||
}
|
||||
|
||||
// Inserting an ACL with empty ID is disallowed
|
||||
if err := s.ACLSet(1, &structs.ACL{}); err == nil {
|
||||
t.Fatalf("expected %#v, got: %#v", ErrMissingACLID, err)
|
||||
}
|
||||
|
||||
// Index is not updated if nothing is saved
|
||||
if idx := s.maxIndex("acls"); idx != 0 {
|
||||
t.Fatalf("bad index: %d", idx)
|
||||
}
|
||||
|
||||
// Inserting valid ACL works
|
||||
acl := &structs.ACL{
|
||||
ID: "acl1",
|
||||
Name: "First ACL",
|
||||
Type: structs.ACLTypeClient,
|
||||
Rules: "rules1",
|
||||
}
|
||||
if err := s.ACLSet(1, acl); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Check that the index was updated
|
||||
if idx := s.maxIndex("acls"); idx != 1 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Retrieve the ACL again
|
||||
result, err := s.ACLGet("acl1")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Check that the ACL matches the result
|
||||
expect := &structs.ACL{
|
||||
ID: "acl1",
|
||||
Name: "First ACL",
|
||||
Type: structs.ACLTypeClient,
|
||||
Rules: "rules1",
|
||||
RaftIndex: structs.RaftIndex{
|
||||
CreateIndex: 1,
|
||||
ModifyIndex: 1,
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(result, expect) {
|
||||
t.Fatalf("bad: %#v", result)
|
||||
}
|
||||
|
||||
// Update the ACL
|
||||
acl = &structs.ACL{
|
||||
ID: "acl1",
|
||||
Name: "First ACL",
|
||||
Type: structs.ACLTypeClient,
|
||||
Rules: "rules2",
|
||||
}
|
||||
if err := s.ACLSet(2, acl); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Index was updated
|
||||
if idx := s.maxIndex("acls"); idx != 2 {
|
||||
t.Fatalf("bad: %d", idx)
|
||||
}
|
||||
|
||||
// ACL was updated and matches expected value
|
||||
expect = &structs.ACL{
|
||||
ID: "acl1",
|
||||
Name: "First ACL",
|
||||
Type: structs.ACLTypeClient,
|
||||
Rules: "rules2",
|
||||
RaftIndex: structs.RaftIndex{
|
||||
CreateIndex: 1,
|
||||
ModifyIndex: 2,
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(acl, expect) {
|
||||
t.Fatalf("bad: %#v", acl)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -479,12 +479,12 @@ type IndexedSessions struct {
|
|||
|
||||
// ACL is used to represent a token and it's rules
|
||||
type ACL struct {
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
ID string
|
||||
Name string
|
||||
Type string
|
||||
Rules string
|
||||
ID string
|
||||
Name string
|
||||
Type string
|
||||
Rules string
|
||||
|
||||
RaftIndex
|
||||
}
|
||||
type ACLs []*ACL
|
||||
|
||||
|
|
Loading…
Reference in New Issue