Moves ACL ID generation down into the endpoint.

We don't want ACL replication to have this behavior so it was a
little dangerous to have in the shared helper function.
This commit is contained in:
James Phillips 2016-08-09 00:11:00 -07:00
parent c499c4e7d3
commit 04fc5c8a45
No known key found for this signature in database
GPG Key ID: 77183E682AC5FC11
1 changed files with 32 additions and 28 deletions

View File

@ -19,9 +19,13 @@ type ACL struct {
// this is a valid operation. It is used when users are updating ACLs, in which
// case we check their token to make sure they have management privileges. It is
// also used for ACL replication. We want to run the replicated ACLs through the
// same checks on the change itself. If an operation needs to generate an ID,
// routine will fill in an ID with the args as part of the request.
// same checks on the change itself.
func aclApplyInternal(srv *Server, args *structs.ACLRequest, reply *string) error {
// All ACLs must have an ID by this point.
if args.ACL.ID == "" {
return fmt.Errorf("Missing ACL ID")
}
switch args.Op {
case structs.ACLSet:
// Verify the ACL type
@ -43,33 +47,8 @@ func aclApplyInternal(srv *Server, args *structs.ACLRequest, reply *string) erro
return fmt.Errorf("ACL rule compilation failed: %v", err)
}
// If no ID is provided, generate a new ID. This must
// be done prior to appending to the raft log, because the ID is not
// deterministic. Once the entry is in the log, the state update MUST
// be deterministic or the followers will not converge.
if args.ACL.ID == "" {
state := srv.fsm.State()
for {
if args.ACL.ID, err = uuid.GenerateUUID(); err != nil {
srv.logger.Printf("[ERR] consul.acl: UUID generation failed: %v", err)
return err
}
_, acl, err := state.ACLGet(args.ACL.ID)
if err != nil {
srv.logger.Printf("[ERR] consul.acl: ACL lookup failed: %v", err)
return err
}
if acl == nil {
break
}
}
}
case structs.ACLDelete:
if args.ACL.ID == "" {
return fmt.Errorf("Missing ACL ID")
} else if args.ACL.ID == anonymousToken {
if args.ACL.ID == anonymousToken {
return fmt.Errorf("%s: Cannot delete anonymous token", permissionDenied)
}
@ -115,6 +94,31 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error {
return permissionDeniedErr
}
// If no ID is provided, generate a new ID. This must be done prior to
// appending to the Raft log, because the ID is not deterministic. Once
// the entry is in the log, the state update MUST be deterministic or
// the followers will not converge.
if args.Op == structs.ACLSet && args.ACL.ID == "" {
state := a.srv.fsm.State()
for {
var err error
args.ACL.ID, err = uuid.GenerateUUID()
if err != nil {
a.srv.logger.Printf("[ERR] consul.acl: UUID generation failed: %v", err)
return err
}
_, acl, err := state.ACLGet(args.ACL.ID)
if err != nil {
a.srv.logger.Printf("[ERR] consul.acl: ACL lookup failed: %v", err)
return err
}
if acl == nil {
break
}
}
}
// Do the apply now that this update is vetted.
if err := aclApplyInternal(a.srv, args, reply); err != nil {
return err