Adds a check to make sure query names can't be registered twice.

This commit is contained in:
James Phillips 2015-12-02 09:04:51 -08:00
parent 300cb16b8b
commit 38bdcc9907
2 changed files with 68 additions and 26 deletions

View File

@ -76,6 +76,19 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
query.ModifyIndex = idx
}
// Verify that the query name doesn't already exist, or that we are
// updating the same instance that has this name.
if query.Name != "" {
alias, err := tx.First("prepared-queries", "name", query.Name)
if err != nil {
return fmt.Errorf("failed prepared query lookup: %s", err)
}
if alias != nil && (existing == nil ||
existing.(*structs.PreparedQuery).ID != alias.(*structs.PreparedQuery).ID) {
return fmt.Errorf("name '%s' aliases an existing query name", query.Name)
}
}
// Verify that the name doesn't alias any existing ID. We allow queries
// to be looked up by ID *or* name so we don't want anyone to try to
// register a query with a name equal to some other query's ID in an
@ -86,12 +99,12 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
// index will complain if we look up something that's not formatted
// like one.
if isUUID(query.Name) {
existing, err := tx.First("prepared-queries", "id", query.Name)
alias, err := tx.First("prepared-queries", "id", query.Name)
if err != nil {
return fmt.Errorf("failed prepared query lookup: %s", err)
}
if existing != nil {
return fmt.Errorf("name '%s' aliases an existing query id", query.Name)
if alias != nil {
return fmt.Errorf("name '%s' aliases an existing query ID", query.Name)
}
}

View File

@ -175,27 +175,22 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
t.Fatalf("bad: %v", actual)
}
// Finally, try to abuse the system by trying to register a query whose
// name aliases a real query ID.
// Try to register a query with the same name and make sure it fails.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: query.ID,
Name: query.Name,
Service: structs.ServiceQuery{
Service: "redis",
},
}
err = s.PreparedQuerySet(7, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query") {
err := s.PreparedQuerySet(7, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query name") {
t.Fatalf("bad: %v", err)
}
// Index is not updated if nothing is saved.
if idx := s.maxIndex("prepared-queries"); idx != 6 {
t.Fatalf("bad index: %d", idx)
}
// Sanity check to make sure it's not there.
idx, actual, err = s.PreparedQueryGet(evil.ID)
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -205,6 +200,40 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Try to abuse the system by trying to register a query whose name
// aliases a real query ID.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: query.ID,
Service: structs.ServiceQuery{
Service: "redis",
},
}
err := s.PreparedQuerySet(8, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query ID") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 6 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Index is not updated if nothing is saved.
if idx := s.maxIndex("prepared-queries"); idx != 6 {
t.Fatalf("bad index: %d", idx)
}
}
func TestStateStore_PreparedQueryDelete(t *testing.T) {