ip-algo: pod annotation > NodeConfig annotation > random
Build flock Image / build (push) Has been cancelled
Build flock Image / build (push) Has been cancelled
Add flock.fritzlab.net/ip-algo as a node-wide default via NodeConfig metadata.annotations. Pod-level annotation still wins. Empty, missing, or invalid input at either level falls through to the next; invalid values warn-log via the agent's slog. Both unset → fully random IID (unchanged baseline). ParseAnnotations no longer touches ip-algo; ResolveIPAlgo handles the full precedence chain, called from PodHandler.Add with the cached NodeConfig's annotations and the agent logger. Tests: 9 new TestResolveIPAlgo_* cases covering pod-wins, all fall-through paths, both-absent, nil node map, whitespace, and duplicate-as-invalid. Fuzz target rebuilt without ip-algo input space (now exercised by ResolveIPAlgo unit tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,9 +5,10 @@ import (
|
||||
)
|
||||
|
||||
// FuzzParseAnnotations explores the joint space of {ipv6, ipv4, cidr6, cidr4,
|
||||
// ip-algo, anycast} annotations with random byte strings. Every recognised
|
||||
// key is exercised by deriving a deterministic input map from the fuzzed
|
||||
// bytes; this gives the fuzzer reach into all parser branches at once.
|
||||
// anycast} annotations with random byte strings. ip-algo is handled by
|
||||
// ResolveIPAlgo (separate fuzz target below) and is no longer touched by
|
||||
// ParseAnnotations. Every recognised key is exercised by deriving a
|
||||
// deterministic input map from the fuzzed bytes.
|
||||
//
|
||||
// Properties checked:
|
||||
//
|
||||
@@ -15,15 +16,15 @@ import (
|
||||
// 2. On nil-error return, the result satisfies the design-doc invariant
|
||||
// that at least one of WantV6 / WantV4 is true (a pod always has at
|
||||
// least one address).
|
||||
// 3. Anycast IPs and IPAlgo fields are non-nil/empty only when the
|
||||
// 3. Anycast IPs and CIDR slices are non-nil/empty only when the
|
||||
// annotation was supplied; never spontaneously populated.
|
||||
//
|
||||
// Seed corpus covers known edge cases the spec must handle.
|
||||
func FuzzParseAnnotations(f *testing.F) {
|
||||
// Seeds: each entry is six strings — the literal raw values for the
|
||||
// six parsed keys. Empty string for "key absent".
|
||||
// Seeds: each entry is five strings — the literal raw values for the
|
||||
// five parsed keys. Empty string for "key absent".
|
||||
type seed struct {
|
||||
ipv6, ipv4, cidr6, cidr4, ipAlgo, anycast string
|
||||
ipv6, ipv4, cidr6, cidr4, anycast string
|
||||
}
|
||||
seeds := []seed{
|
||||
{},
|
||||
@@ -43,11 +44,6 @@ func FuzzParseAnnotations(f *testing.F) {
|
||||
{cidr4: "172.25.210.0/24"}, // valid
|
||||
{cidr4: "172.25.210.0/24,172.25.211.0/24"}, // multiple
|
||||
{cidr4: "2602:817::/32"}, // family mismatch
|
||||
{ipAlgo: "namespace,pod,image"},
|
||||
{ipAlgo: "namespace, pod , image"}, // whitespace
|
||||
{ipAlgo: "namespace,unknown"}, // invalid
|
||||
{ipAlgo: ""}, // invalid (empty)
|
||||
{ipAlgo: ","}, // invalid
|
||||
{anycast: "2602:817:3000:ac::1"},
|
||||
{anycast: "2602:817:3000:ac::1, 172.25.255.1"},
|
||||
{anycast: "::1"}, // loopback (allowed at parse time)
|
||||
@@ -62,15 +58,14 @@ func FuzzParseAnnotations(f *testing.F) {
|
||||
{anycast: "\x00\x00"},
|
||||
// Unicode
|
||||
{ipv4: "trüe"},
|
||||
{ipAlgo: "námespace"},
|
||||
// Very long
|
||||
{cidr6: longString("2602:817:3000:f001::/64,", 4096)},
|
||||
}
|
||||
for _, s := range seeds {
|
||||
f.Add(s.ipv6, s.ipv4, s.cidr6, s.cidr4, s.ipAlgo, s.anycast)
|
||||
f.Add(s.ipv6, s.ipv4, s.cidr6, s.cidr4, s.anycast)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, ipv6, ipv4, cidr6, cidr4, ipAlgo, anycast string) {
|
||||
f.Fuzz(func(t *testing.T, ipv6, ipv4, cidr6, cidr4, anycast string) {
|
||||
in := map[string]string{}
|
||||
// Treat empty as "key absent" so the seed table matches the run-time
|
||||
// shape; Kubernetes annotations cannot have a nil value but they CAN
|
||||
@@ -88,9 +83,6 @@ func FuzzParseAnnotations(f *testing.F) {
|
||||
if cidr4 != "" {
|
||||
in[annotationPrefix+annCIDR4] = cidr4
|
||||
}
|
||||
if ipAlgo != "" {
|
||||
in[annotationPrefix+annIPAlgo] = ipAlgo
|
||||
}
|
||||
if anycast != "" {
|
||||
in[annotationPrefix+annAnycast] = anycast
|
||||
}
|
||||
@@ -104,9 +96,6 @@ func FuzzParseAnnotations(f *testing.F) {
|
||||
t.Fatalf("parser accepted but produced no family: in=%#v", in)
|
||||
}
|
||||
// Property: optional fields populated only when their key was set.
|
||||
if _, hasAlgo := in[annotationPrefix+annIPAlgo]; !hasAlgo && len(got.IPAlgo) != 0 {
|
||||
t.Fatalf("IPAlgo populated without annotation")
|
||||
}
|
||||
if _, hasAny := in[annotationPrefix+annAnycast]; !hasAny && len(got.Anycast) != 0 {
|
||||
t.Fatalf("Anycast populated without annotation")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user