agent/cache-types: support intention match queries
This commit is contained in:
parent
109bb946e9
commit
56774f24d0
|
@ -0,0 +1,41 @@
|
|||
package cachetype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/consul/agent/cache"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
)
|
||||
|
||||
// Recommended name for registration.
|
||||
const IntentionMatchName = "intention-match"
|
||||
|
||||
// IntentionMatch supports fetching the intentions via match queries.
|
||||
type IntentionMatch struct {
|
||||
RPC RPC
|
||||
}
|
||||
|
||||
func (c *IntentionMatch) Fetch(opts cache.FetchOptions, req cache.Request) (cache.FetchResult, error) {
|
||||
var result cache.FetchResult
|
||||
|
||||
// The request should be an IntentionQueryRequest.
|
||||
reqReal, ok := req.(*structs.IntentionQueryRequest)
|
||||
if !ok {
|
||||
return result, fmt.Errorf(
|
||||
"Internal cache failure: request wrong type: %T", req)
|
||||
}
|
||||
|
||||
// Set the minimum query index to our current index so we block
|
||||
reqReal.MinQueryIndex = opts.MinIndex
|
||||
reqReal.MaxQueryTime = opts.Timeout
|
||||
|
||||
// Fetch
|
||||
var reply structs.IndexedIntentionMatches
|
||||
if err := c.RPC.RPC("Intention.Match", reqReal, &reply); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
result.Value = &reply
|
||||
result.Index = reply.Index
|
||||
return result, nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package cachetype
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/cache"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIntentionMatch(t *testing.T) {
|
||||
require := require.New(t)
|
||||
rpc := TestRPC(t)
|
||||
defer rpc.AssertExpectations(t)
|
||||
typ := &IntentionMatch{RPC: rpc}
|
||||
|
||||
// Expect the proper RPC call. This also sets the expected value
|
||||
// since that is return-by-pointer in the arguments.
|
||||
var resp *structs.IndexedIntentionMatches
|
||||
rpc.On("RPC", "Intention.Match", mock.Anything, mock.Anything).Return(nil).
|
||||
Run(func(args mock.Arguments) {
|
||||
req := args.Get(1).(*structs.IntentionQueryRequest)
|
||||
require.Equal(uint64(24), req.MinQueryIndex)
|
||||
require.Equal(1*time.Second, req.MaxQueryTime)
|
||||
|
||||
reply := args.Get(2).(*structs.IndexedIntentionMatches)
|
||||
reply.Index = 48
|
||||
resp = reply
|
||||
})
|
||||
|
||||
// Fetch
|
||||
result, err := typ.Fetch(cache.FetchOptions{
|
||||
MinIndex: 24,
|
||||
Timeout: 1 * time.Second,
|
||||
}, &structs.IntentionQueryRequest{Datacenter: "dc1"})
|
||||
require.Nil(err)
|
||||
require.Equal(cache.FetchResult{
|
||||
Value: resp,
|
||||
Index: 48,
|
||||
}, result)
|
||||
}
|
||||
|
||||
func TestIntentionMatch_badReqType(t *testing.T) {
|
||||
require := require.New(t)
|
||||
rpc := TestRPC(t)
|
||||
defer rpc.AssertExpectations(t)
|
||||
typ := &IntentionMatch{RPC: rpc}
|
||||
|
||||
// Fetch
|
||||
_, err := typ.Fetch(cache.FetchOptions{}, cache.TestRequest(
|
||||
t, cache.RequestInfo{Key: "foo", MinIndex: 64}))
|
||||
require.NotNil(err)
|
||||
require.Contains(err.Error(), "wrong type")
|
||||
|
||||
}
|
|
@ -2,10 +2,13 @@ package structs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/cache"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/mitchellh/hashstructure"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -267,6 +270,36 @@ func (q *IntentionQueryRequest) RequestDatacenter() string {
|
|||
return q.Datacenter
|
||||
}
|
||||
|
||||
// cache.Request impl.
|
||||
func (q *IntentionQueryRequest) CacheInfo() cache.RequestInfo {
|
||||
// We only support caching Match queries, so if Match isn't set,
|
||||
// then return an empty info object which will cause a pass-through
|
||||
// (and likely fail).
|
||||
if q.Match == nil {
|
||||
return cache.RequestInfo{}
|
||||
}
|
||||
|
||||
info := cache.RequestInfo{
|
||||
Token: q.Token,
|
||||
Datacenter: q.Datacenter,
|
||||
MinIndex: q.MinQueryIndex,
|
||||
Timeout: q.MaxQueryTime,
|
||||
}
|
||||
|
||||
// Calculate the cache key via just hashing the Match struct. This
|
||||
// has been configured so things like ordering of entries has no
|
||||
// effect (via struct tags).
|
||||
v, err := hashstructure.Hash(q.Match, nil)
|
||||
if err == nil {
|
||||
// If there is an error, we don't set the key. A blank key forces
|
||||
// no cache for this request so the request is forwarded directly
|
||||
// to the server.
|
||||
info.Key = strconv.FormatUint(v, 10)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// IntentionQueryMatch are the parameters for performing a match request
|
||||
// against the state store.
|
||||
type IntentionQueryMatch struct {
|
||||
|
|
Loading…
Reference in New Issue