agent/consul: set precedence value on struct itself
This commit is contained in:
parent
dd042db965
commit
4ebddd6adb
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
Loading…
Reference in New Issue