// aclSetTxn is the inner method used to insert an ACL rule with the // proper indexes into the state store. func (s *StateStore) 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) } tx.Defer(func() { s.tableWatches["acls"].Notify() }) return nil }
// 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() }