Factors rendering down into the resolve function.
This commit is contained in:
parent
ee43212da4
commit
2a9a5f823e
|
@ -86,6 +86,11 @@ func Compile(query *structs.PreparedQuery) (*CompiledTemplate, error) {
|
||||||
// example, if the user looks up foobar.query.consul via DNS then we will call
|
// example, if the user looks up foobar.query.consul via DNS then we will call
|
||||||
// this function with "foobar" on the compiled template.
|
// this function with "foobar" on the compiled template.
|
||||||
func (ct *CompiledTemplate) Render(name string) (*structs.PreparedQuery, error) {
|
func (ct *CompiledTemplate) Render(name string) (*structs.PreparedQuery, error) {
|
||||||
|
// Make it "safe" to render a default structure.
|
||||||
|
if ct == nil {
|
||||||
|
return nil, fmt.Errorf("Cannot render an uncompiled template")
|
||||||
|
}
|
||||||
|
|
||||||
// Start with a fresh, detached copy of the original so we don't disturb
|
// Start with a fresh, detached copy of the original so we don't disturb
|
||||||
// the prototype.
|
// the prototype.
|
||||||
dup, err := copystructure.Copy(ct.query)
|
dup, err := copystructure.Copy(ct.query)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/armon/go-metrics"
|
"github.com/armon/go-metrics"
|
||||||
"github.com/hashicorp/consul/consul/prepared_query"
|
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
)
|
)
|
||||||
|
@ -290,7 +289,7 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest,
|
||||||
|
|
||||||
// Try to locate the query.
|
// Try to locate the query.
|
||||||
state := p.srv.fsm.State()
|
state := p.srv.fsm.State()
|
||||||
_, query, ct, err := state.PreparedQueryLookup(args.QueryIDOrName)
|
_, query, err := state.PreparedQueryResolve(args.QueryIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -298,18 +297,6 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest,
|
||||||
return ErrQueryNotFound
|
return ErrQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a template then render the query first.
|
|
||||||
if prepared_query.IsTemplate(query) {
|
|
||||||
if ct == nil {
|
|
||||||
return fmt.Errorf("Missing compiled template")
|
|
||||||
}
|
|
||||||
render, err := ct.Render(args.QueryIDOrName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
query = render
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the query for the local DC.
|
// Execute the query for the local DC.
|
||||||
if err := p.execute(query, reply); err != nil {
|
if err := p.execute(query, reply); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -261,21 +261,22 @@ func (s *StateStore) PreparedQueryGet(queryID string) (uint64, *structs.Prepared
|
||||||
return idx, toPreparedQuery(wrapped), nil
|
return idx, toPreparedQuery(wrapped), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreparedQueryLookup returns the given prepared query by looking up an ID or
|
// PreparedQueryResolve returns the given prepared query by looking up an ID or
|
||||||
// Name.
|
// Name. If the query was looked up by name and it's a template, then the
|
||||||
func (s *StateStore) PreparedQueryLookup(queryIDOrName string) (uint64, *structs.PreparedQuery, *prepared_query.CompiledTemplate, error) {
|
// template will be rendered before it is returned.
|
||||||
|
func (s *StateStore) PreparedQueryResolve(queryIDOrName string) (uint64, *structs.PreparedQuery, error) {
|
||||||
tx := s.db.Txn(false)
|
tx := s.db.Txn(false)
|
||||||
defer tx.Abort()
|
defer tx.Abort()
|
||||||
|
|
||||||
// Get the table index.
|
// Get the table index.
|
||||||
idx := maxIndexTxn(tx, s.getWatchTables("PreparedQueryLookup")...)
|
idx := maxIndexTxn(tx, s.getWatchTables("PreparedQueryResolve")...)
|
||||||
|
|
||||||
// Explicitly ban an empty query. This will never match an ID and the
|
// Explicitly ban an empty query. This will never match an ID and the
|
||||||
// schema is set up so it will never match a query with an empty name,
|
// schema is set up so it will never match a query with an empty name,
|
||||||
// but we check it here to be explicit about it (we'd never want to
|
// but we check it here to be explicit about it (we'd never want to
|
||||||
// return the results from the first query w/o a name).
|
// return the results from the first query w/o a name).
|
||||||
if queryIDOrName == "" {
|
if queryIDOrName == "" {
|
||||||
return 0, nil, nil, ErrMissingQueryID
|
return 0, nil, ErrMissingQueryID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try first by ID if it looks like they gave us an ID. We check the
|
// Try first by ID if it looks like they gave us an ID. We check the
|
||||||
|
@ -284,11 +285,29 @@ func (s *StateStore) PreparedQueryLookup(queryIDOrName string) (uint64, *structs
|
||||||
if isUUID(queryIDOrName) {
|
if isUUID(queryIDOrName) {
|
||||||
wrapped, err := tx.First("prepared-queries", "id", queryIDOrName)
|
wrapped, err := tx.First("prepared-queries", "id", queryIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
return 0, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
||||||
}
|
}
|
||||||
if wrapped != nil {
|
if wrapped != nil {
|
||||||
wrapper := wrapped.(*queryWrapper)
|
query := toPreparedQuery(wrapped)
|
||||||
return idx, wrapper.PreparedQuery, wrapper.ct, nil
|
if prepared_query.IsTemplate(query) {
|
||||||
|
return idx, nil, fmt.Errorf("prepared query templates can only be resolved up by name, not by ID")
|
||||||
|
}
|
||||||
|
return idx, query, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prep will check to see if the query is a template and render it
|
||||||
|
// first, otherwise it will just return a regular query.
|
||||||
|
prep := func(wrapped interface{}) (uint64, *structs.PreparedQuery, error) {
|
||||||
|
wrapper := wrapped.(*queryWrapper)
|
||||||
|
if prepared_query.IsTemplate(wrapper.PreparedQuery) {
|
||||||
|
render, err := wrapper.ct.Render(queryIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return idx, nil, err
|
||||||
|
}
|
||||||
|
return idx, render, nil
|
||||||
|
} else {
|
||||||
|
return idx, wrapper.PreparedQuery, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,13 +319,12 @@ func (s *StateStore) PreparedQueryLookup(queryIDOrName string) (uint64, *structs
|
||||||
{
|
{
|
||||||
wrapped, err := tx.First("prepared-queries", "name_prefix", queryIDOrName)
|
wrapped, err := tx.First("prepared-queries", "name_prefix", queryIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
return 0, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
||||||
}
|
}
|
||||||
if wrapped != nil {
|
if wrapped != nil {
|
||||||
wrapper := wrapped.(*queryWrapper)
|
query := toPreparedQuery(wrapped)
|
||||||
query, ct := wrapper.PreparedQuery, wrapper.ct
|
|
||||||
if query.Name == queryIDOrName || prepared_query.IsTemplate(query) {
|
if query.Name == queryIDOrName || prepared_query.IsTemplate(query) {
|
||||||
return idx, query, ct, nil
|
return prep(wrapped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,15 +333,14 @@ func (s *StateStore) PreparedQueryLookup(queryIDOrName string) (uint64, *structs
|
||||||
{
|
{
|
||||||
wrapped, err := tx.First("prepared-queries", "wild", true)
|
wrapped, err := tx.First("prepared-queries", "wild", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
return 0, nil, fmt.Errorf("failed prepared query lookup: %s", err)
|
||||||
}
|
}
|
||||||
if wrapped != nil {
|
if wrapped != nil {
|
||||||
wrapper := wrapped.(*queryWrapper)
|
return prep(wrapped)
|
||||||
return idx, wrapper.PreparedQuery, wrapper.ct, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx, nil, nil, nil
|
return idx, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreparedQueryList returns all the prepared queries.
|
// PreparedQueryList returns all the prepared queries.
|
||||||
|
|
|
@ -318,7 +318,7 @@ func TestStateStore_PreparedQueryDelete(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
func TestStateStore_PreparedQueryResolve(t *testing.T) {
|
||||||
s := testStateStore(t)
|
s := testStateStore(t)
|
||||||
|
|
||||||
// Set up our test environment.
|
// Set up our test environment.
|
||||||
|
@ -336,7 +336,7 @@ func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
||||||
|
|
||||||
// Try to lookup a query that's not there using something that looks
|
// Try to lookup a query that's not there using something that looks
|
||||||
// like a real ID.
|
// like a real ID.
|
||||||
idx, actual, _, err := s.PreparedQueryLookup(query.ID)
|
idx, actual, err := s.PreparedQueryResolve(query.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
||||||
|
|
||||||
// Try to lookup a query that's not there using something that looks
|
// Try to lookup a query that's not there using something that looks
|
||||||
// like a name
|
// like a name
|
||||||
idx, actual, _, err = s.PreparedQueryLookup(query.Name)
|
idx, actual, err = s.PreparedQueryResolve(query.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -382,7 +382,7 @@ func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
||||||
ModifyIndex: 3,
|
ModifyIndex: 3,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
idx, actual, _, err = s.PreparedQueryLookup(query.ID)
|
idx, actual, err = s.PreparedQueryResolve(query.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read it back using the name and verify it again.
|
// Read it back using the name and verify it again.
|
||||||
idx, actual, _, err = s.PreparedQueryLookup(query.Name)
|
idx, actual, err = s.PreparedQueryResolve(query.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ func TestStateStore_PreparedQueryLookup(t *testing.T) {
|
||||||
|
|
||||||
// Make sure an empty lookup is well-behaved if there are actual queries
|
// Make sure an empty lookup is well-behaved if there are actual queries
|
||||||
// in the state store.
|
// in the state store.
|
||||||
idx, actual, _, err = s.PreparedQueryLookup("")
|
idx, actual, err = s.PreparedQueryResolve("")
|
||||||
if err != ErrMissingQueryID {
|
if err != ErrMissingQueryID {
|
||||||
t.Fatalf("bad: %v ", err)
|
t.Fatalf("bad: %v ", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,7 +413,7 @@ func (s *StateStore) getWatchTables(method string) []string {
|
||||||
return []string{"acls"}
|
return []string{"acls"}
|
||||||
case "Coordinates":
|
case "Coordinates":
|
||||||
return []string{"coordinates"}
|
return []string{"coordinates"}
|
||||||
case "PreparedQueryGet", "PreparedQueryLookup", "PreparedQueryList":
|
case "PreparedQueryGet", "PreparedQueryResolve", "PreparedQueryList":
|
||||||
return []string{"prepared-queries"}
|
return []string{"prepared-queries"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue