command/intention/finder: package for finding based on src/dst
This commit is contained in:
parent
a1a7eaa876
commit
77d0360de1
|
@ -53,17 +53,30 @@ type Intention struct {
|
||||||
|
|
||||||
// String returns human-friendly output describing ths intention.
|
// String returns human-friendly output describing ths intention.
|
||||||
func (i *Intention) String() string {
|
func (i *Intention) String() string {
|
||||||
source := i.SourceName
|
return fmt.Sprintf("%s => %s (%s)",
|
||||||
if i.SourceNS != "" {
|
i.SourceString(),
|
||||||
source = i.SourceNS + "/" + source
|
i.DestinationString(),
|
||||||
|
i.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceString returns the namespace/name format for the source, or
|
||||||
|
// just "name" if the namespace is the default namespace.
|
||||||
|
func (i *Intention) SourceString() string {
|
||||||
|
return i.partString(i.SourceNS, i.SourceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestinationString returns the namespace/name format for the source, or
|
||||||
|
// just "name" if the namespace is the default namespace.
|
||||||
|
func (i *Intention) DestinationString() string {
|
||||||
|
return i.partString(i.DestinationNS, i.DestinationName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Intention) partString(ns, n string) string {
|
||||||
|
if ns != "" {
|
||||||
|
n = ns + "/" + n
|
||||||
}
|
}
|
||||||
|
|
||||||
dest := i.DestinationName
|
return n
|
||||||
if i.DestinationNS != "" {
|
|
||||||
dest = i.DestinationNS + "/" + dest
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s => %s (%s)", source, dest, i.Action)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntentionAction is the action that the intention represents. This
|
// IntentionAction is the action that the intention represents. This
|
||||||
|
|
46
command/intention/finder/finder.go
Normal file
46
command/intention/finder/finder.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package finder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Finder finds intentions by a src/dst exact match. There is currently
|
||||||
|
// no direct API to do this so this struct downloads all intentions and
|
||||||
|
// caches them once, and searches in-memory for this. For now this works since
|
||||||
|
// even with a very large number of intentions, the size of the data gzipped
|
||||||
|
// over HTTP will be relatively small.
|
||||||
|
type Finder struct {
|
||||||
|
// Client is the API client to use for any requests.
|
||||||
|
Client *api.Client
|
||||||
|
|
||||||
|
lock sync.Mutex
|
||||||
|
ixns []*api.Intention // cached list of intentions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find finds the intention that matches the given src and dst. This will
|
||||||
|
// return nil when the result is not found.
|
||||||
|
func (f *Finder) Find(src, dst string) (*api.Intention, error) {
|
||||||
|
f.lock.Lock()
|
||||||
|
defer f.lock.Unlock()
|
||||||
|
|
||||||
|
// If the list of ixns is nil, then we haven't fetched yet, so fetch
|
||||||
|
if f.ixns == nil {
|
||||||
|
ixns, _, err := f.Client.Connect().Intentions(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.ixns = ixns
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through the intentions and find an exact match
|
||||||
|
for _, ixn := range f.ixns {
|
||||||
|
if ixn.SourceString() == src && ixn.DestinationString() == dst {
|
||||||
|
return ixn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
49
command/intention/finder/finder_test.go
Normal file
49
command/intention/finder/finder_test.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package finder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent"
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFinder(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
require := require.New(t)
|
||||||
|
a := agent.NewTestAgent(t.Name(), ``)
|
||||||
|
defer a.Shutdown()
|
||||||
|
client := a.Client()
|
||||||
|
|
||||||
|
// Create a set of intentions
|
||||||
|
var ids []string
|
||||||
|
{
|
||||||
|
insert := [][]string{
|
||||||
|
[]string{"a", "b", "c", "d"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range insert {
|
||||||
|
ixn := &api.Intention{
|
||||||
|
SourceNS: v[0],
|
||||||
|
SourceName: v[1],
|
||||||
|
DestinationNS: v[2],
|
||||||
|
DestinationName: v[3],
|
||||||
|
Action: api.IntentionActionAllow,
|
||||||
|
}
|
||||||
|
|
||||||
|
id, _, err := client.Connect().IntentionCreate(ixn, nil)
|
||||||
|
require.NoError(err)
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finder := &Finder{Client: client}
|
||||||
|
ixn, err := finder.Find("a/b", "c/d")
|
||||||
|
require.NoError(err)
|
||||||
|
require.Equal(ids[0], ixn.ID)
|
||||||
|
|
||||||
|
ixn, err = finder.Find("a/c", "c/d")
|
||||||
|
require.NoError(err)
|
||||||
|
require.Nil(ixn)
|
||||||
|
}
|
Loading…
Reference in a new issue