agent/consul: set precedence value on struct itself

This commit is contained in:
Mitchell Hashimoto 2018-06-06 21:11:37 -07:00 committed by Jack Pearkes
parent 1f5398e17c
commit 028aa78e83
4 changed files with 62 additions and 33 deletions

View File

@ -127,6 +127,9 @@ func (s *Intention) Apply(
// Validate. We do not validate on delete since it is valid to only
// send an ID in that case.
if args.Op != structs.IntentionOpDelete {
// Set the precedence
args.Intention.UpdatePrecedence()
if err := args.Intention.Validate(); err != nil {
return err
}

View File

@ -67,6 +67,7 @@ func TestIntentionApply_new(t *testing.T) {
actual.CreateIndex, actual.ModifyIndex = 0, 0
actual.CreatedAt = ixn.Intention.CreatedAt
actual.UpdatedAt = ixn.Intention.UpdatedAt
ixn.Intention.UpdatePrecedence()
assert.Equal(ixn.Intention, actual)
}
}
@ -201,7 +202,7 @@ func TestIntentionApply_updateGood(t *testing.T) {
// Update
ixn.Op = structs.IntentionOpUpdate
ixn.Intention.ID = reply
ixn.Intention.SourceName = "bar"
ixn.Intention.SourceName = "*"
assert.Nil(msgpackrpc.CallWithCodec(codec, "Intention.Apply", &ixn, &reply))
// Read
@ -221,6 +222,7 @@ func TestIntentionApply_updateGood(t *testing.T) {
actual.CreateIndex, actual.ModifyIndex = 0, 0
actual.CreatedAt = ixn.Intention.CreatedAt
actual.UpdatedAt = ixn.Intention.UpdatedAt
ixn.Intention.UpdatePrecedence()
assert.Equal(ixn.Intention, actual)
}
}
@ -378,6 +380,7 @@ service "foo" {
actual.CreateIndex, actual.ModifyIndex = 0, 0
actual.CreatedAt = ixn.Intention.CreatedAt
actual.UpdatedAt = ixn.Intention.UpdatedAt
ixn.Intention.UpdatePrecedence()
assert.Equal(ixn.Intention, actual)
}
}

View File

@ -61,6 +61,11 @@ type Intention struct {
// opaque to Consul but is served in API responses.
Meta map[string]string
// Precedence is the order that the intention will be applied, with
// larger numbers being applied first. This is a read-only field, on
// any intention update it is updated.
Precedence int
// CreatedAt and UpdatedAt keep track of when this record was created
// or modified.
CreatedAt, UpdatedAt time.Time `mapstructure:"-"`
@ -160,6 +165,49 @@ func (x *Intention) Validate() error {
return result
}
// UpdatePrecedence sets the Precedence value based on the fields of this
// structure.
func (x *Intention) UpdatePrecedence() {
// Max maintains the maximum value that the precedence can be depending
// on the number of exact values in the destination.
var max int
switch x.countExact(x.DestinationNS, x.DestinationName) {
case 2:
max = 9
case 1:
max = 6
case 0:
max = 3
default:
// This shouldn't be possible, just set it to zero
x.Precedence = 0
return
}
// Given the maximum, the exact value is determined based on the
// number of source exact values.
countSrc := x.countExact(x.SourceNS, x.SourceName)
x.Precedence = max - (2 - countSrc)
}
// countExact counts the number of exact values (not wildcards) in
// the given namespace and name.
func (x *Intention) countExact(ns, n string) int {
// If NS is wildcard, it must be zero since wildcards only follow exact
if ns == IntentionWildcard {
return 0
}
// Same reasoning as above, a wildcard can only follow an exact value
// and an exact value cannot follow a wildcard, so if name is a wildcard
// we must have exactly one.
if n == IntentionWildcard {
return 1
}
return 2
}
// GetACLPrefix returns the prefix to look up the ACL policy for this
// intention, and a boolean noting whether the prefix is valid to check
// or not. You must check the ok value before using the prefix.
@ -354,20 +402,8 @@ func (s IntentionPrecedenceSorter) Swap(i, j int) {
func (s IntentionPrecedenceSorter) Less(i, j int) bool {
a, b := s[i], s[j]
// First test the # of exact values in destination, since precedence
// is destination-oriented.
aExact := s.countExact(a.DestinationNS, a.DestinationName)
bExact := s.countExact(b.DestinationNS, b.DestinationName)
if aExact != bExact {
return aExact > bExact
}
// Next test the # of exact values in source
aExact = s.countExact(a.SourceNS, a.SourceName)
bExact = s.countExact(b.SourceNS, b.SourceName)
if aExact != bExact {
return aExact > bExact
if a.Precedence != b.Precedence {
return a.Precedence > b.Precedence
}
// Tie break on lexicographic order of the 4-tuple in canonical form (SrcNS,
@ -387,21 +423,3 @@ func (s IntentionPrecedenceSorter) Less(i, j int) bool {
}
return a.DestinationName < b.DestinationName
}
// countExact counts the number of exact values (not wildcards) in
// the given namespace and name.
func (s IntentionPrecedenceSorter) countExact(ns, n string) int {
// If NS is wildcard, it must be zero since wildcards only follow exact
if ns == IntentionWildcard {
return 0
}
// Same reasoning as above, a wildcard can only follow an exact value
// and an exact value cannot follow a wildcard, so if name is a wildcard
// we must have exactly one.
if n == IntentionWildcard {
return 1
}
return 2
}

View File

@ -232,6 +232,11 @@ func TestIntentionPrecedenceSorter(t *testing.T) {
})
}
// Set all the precedence values
for _, ixn := range input {
ixn.UpdatePrecedence()
}
// Sort
sort.Sort(IntentionPrecedenceSorter(input))