// ACLSet is used to create or update an ACL entry // allowCreate is used for initialization of the anonymous and master tokens, // since it permits them to be created with a specified ID that does not exist. func (s *StateStore) ACLSet(index uint64, acl *structs.ACL, allowCreate bool) error { // Start a new txn tx, err := s.tables.StartTxn(false) if err != nil { return err } defer tx.Abort() // Generate a new session ID if acl.ID == "" { for { acl.ID = generateUUID() res, err := s.aclTable.GetTxn(tx, "id", acl.ID) if err != nil { return err } // Quit if this ID is unique if len(res) == 0 { break } } acl.CreateIndex = index acl.ModifyIndex = index } else { // Look for the existing node res, err := s.aclTable.GetTxn(tx, "id", acl.ID) if err != nil { return err } switch len(res) { case 0: if !allowCreate { return fmt.Errorf("Invalid ACL") } acl.CreateIndex = index acl.ModifyIndex = index case 1: exist := res[0].(*structs.ACL) acl.CreateIndex = exist.CreateIndex acl.ModifyIndex = index default: panic(fmt.Errorf("Duplicate ACL definition. Internal error")) } } // Insert the ACL if err := s.aclTable.InsertTxn(tx, acl); err != nil { return err } // Trigger the update notifications if err := s.aclTable.SetLastIndexTxn(tx, index); err != nil { return err } tx.Defer(func() { s.watch[s.aclTable].Notify() }) return tx.Commit() }