Merge pull request #112260 from aryan9600/cidr-metrics

Add metric for max no. of CIDRs available
This commit is contained in:
Kubernetes Prow Robot 2022-12-09 15:42:59 -08:00 committed by GitHub
commit 63a01a5465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 266 additions and 22 deletions

View File

@ -79,7 +79,6 @@ func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) (*CidrSet, error) {
clusterMask := clusterCIDR.Mask clusterMask := clusterCIDR.Mask
clusterMaskSize, bits := clusterMask.Size() clusterMaskSize, bits := clusterMask.Size()
var maxCIDRs int
if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) { if (clusterCIDR.IP.To4() == nil) && (subNetMaskSize-clusterMaskSize > clusterSubnetMaxDiff) {
return nil, ErrCIDRSetSubNetTooBig return nil, ErrCIDRSetSubNetTooBig
} }
@ -87,15 +86,18 @@ func NewCIDRSet(clusterCIDR *net.IPNet, subNetMaskSize int) (*CidrSet, error) {
// register CidrSet metrics // register CidrSet metrics
registerCidrsetMetrics() registerCidrsetMetrics()
maxCIDRs = 1 << uint32(subNetMaskSize-clusterMaskSize) maxCIDRs := getMaxCIDRs(subNetMaskSize, clusterMaskSize)
return &CidrSet{ cidrSet := &CidrSet{
clusterCIDR: clusterCIDR, clusterCIDR: clusterCIDR,
nodeMask: net.CIDRMask(subNetMaskSize, bits), nodeMask: net.CIDRMask(subNetMaskSize, bits),
clusterMaskSize: clusterMaskSize, clusterMaskSize: clusterMaskSize,
maxCIDRs: maxCIDRs, maxCIDRs: maxCIDRs,
nodeMaskSize: subNetMaskSize, nodeMaskSize: subNetMaskSize,
label: clusterCIDR.String(), label: clusterCIDR.String(),
}, nil }
cidrSetMaxCidrs.WithLabelValues(cidrSet.label).Set(float64(maxCIDRs))
return cidrSet, nil
} }
func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet { func (s *CidrSet) indexToCIDRBlock(index int) *net.IPNet {
@ -293,3 +295,9 @@ func (s *CidrSet) getIndexForIP(ip net.IP) (int, error) {
return 0, fmt.Errorf("invalid IP: %v", ip) return 0, fmt.Errorf("invalid IP: %v", ip)
} }
// getMaxCIDRs returns the max number of CIDRs that can be obtained by subdividing a mask of size `clusterMaskSize`
// into subnets with mask of size `subNetMaskSize`.
func getMaxCIDRs(subNetMaskSize, clusterMaskSize int) int {
return 1 << uint32(subNetMaskSize-clusterMaskSize)
}

View File

@ -836,12 +836,24 @@ func TestCIDRSetv6(t *testing.T) {
func TestCidrSetMetrics(t *testing.T) { func TestCidrSetMetrics(t *testing.T) {
cidr := "10.0.0.0/16" cidr := "10.0.0.0/16"
_, clusterCIDR, _ := netutils.ParseCIDRSloppy(cidr) _, clusterCIDR, _ := netutils.ParseCIDRSloppy(cidr)
clearMetrics(map[string]string{"clusterCIDR": cidr})
// We have 256 free cidrs // We have 256 free cidrs
a, err := NewCIDRSet(clusterCIDR, 24) a, err := NewCIDRSet(clusterCIDR, 24)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating CidrSet: %v", err) t.Fatalf("unexpected error creating CidrSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidr})
clusterMaskSize, _ := clusterCIDR.Mask.Size()
max := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(max),
}
expectMetrics(t, cidr, em)
// Allocate next all // Allocate next all
for i := 1; i <= 256; i++ { for i := 1; i <= 256; i++ {
@ -854,16 +866,18 @@ func TestCidrSetMetrics(t *testing.T) {
allocs: float64(i), allocs: float64(i),
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
} }
// Release all // Release all
a.Release(clusterCIDR) a.Release(clusterCIDR)
em := testMetrics{ em = testMetrics{
usage: 0, usage: 0,
allocs: 256, allocs: 256,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
@ -874,30 +888,43 @@ func TestCidrSetMetrics(t *testing.T) {
allocs: 512, allocs: 512,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
} }
func TestCidrSetMetricsHistogram(t *testing.T) { func TestCidrSetMetricsHistogram(t *testing.T) {
cidr := "10.0.0.0/16" cidr := "10.0.0.0/16"
_, clusterCIDR, _ := netutils.ParseCIDRSloppy(cidr) _, clusterCIDR, _ := netutils.ParseCIDRSloppy(cidr)
clearMetrics(map[string]string{"clusterCIDR": cidr})
// We have 256 free cidrs // We have 256 free cidrs
a, err := NewCIDRSet(clusterCIDR, 24) a, err := NewCIDRSet(clusterCIDR, 24)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating CidrSet: %v", err) t.Fatalf("unexpected error creating CidrSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidr})
clusterMaskSize, _ := clusterCIDR.Mask.Size()
max := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(max),
}
expectMetrics(t, cidr, em)
// Allocate half of the range // Allocate half of the range
// Occupy does not update the nextCandidate // Occupy does not update the nextCandidate
_, halfClusterCIDR, _ := netutils.ParseCIDRSloppy("10.0.0.0/17") _, halfClusterCIDR, _ := netutils.ParseCIDRSloppy("10.0.0.0/17")
a.Occupy(halfClusterCIDR) a.Occupy(halfClusterCIDR)
em := testMetrics{ em = testMetrics{
usage: 0.5, usage: 0.5,
allocs: 128, allocs: 128,
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
// Allocate next should iterate until the next free cidr // Allocate next should iterate until the next free cidr
@ -911,6 +938,7 @@ func TestCidrSetMetricsHistogram(t *testing.T) {
allocs: 129, allocs: 129,
releases: 0, releases: 0,
allocTries: 128, allocTries: 128,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
} }
@ -919,26 +947,53 @@ func TestCidrSetMetricsDual(t *testing.T) {
// create IPv4 cidrSet // create IPv4 cidrSet
cidrIPv4 := "10.0.0.0/16" cidrIPv4 := "10.0.0.0/16"
_, clusterCIDRv4, _ := netutils.ParseCIDRSloppy(cidrIPv4) _, clusterCIDRv4, _ := netutils.ParseCIDRSloppy(cidrIPv4)
clearMetrics(map[string]string{"clusterCIDR": cidrIPv4})
a, err := NewCIDRSet(clusterCIDRv4, 24) a, err := NewCIDRSet(clusterCIDRv4, 24)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating CidrSet: %v", err) t.Fatalf("unexpected error creating CidrSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidrIPv4})
clusterMaskSize, _ := clusterCIDRv4.Mask.Size()
maxIPv4 := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(maxIPv4),
}
expectMetrics(t, cidrIPv4, em)
// create IPv6 cidrSet // create IPv6 cidrSet
cidrIPv6 := "2001:db8::/48" cidrIPv6 := "2001:db8::/48"
_, clusterCIDRv6, _ := netutils.ParseCIDRSloppy(cidrIPv6) _, clusterCIDRv6, _ := netutils.ParseCIDRSloppy(cidrIPv6)
clearMetrics(map[string]string{"clusterCIDR": cidrIPv6})
b, err := NewCIDRSet(clusterCIDRv6, 64) b, err := NewCIDRSet(clusterCIDRv6, 64)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating CidrSet: %v", err) t.Fatalf("unexpected error creating CidrSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidrIPv6})
clusterMaskSize, _ = clusterCIDRv6.Mask.Size()
maxIPv6 := getMaxCIDRs(64, clusterMaskSize)
em = testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(maxIPv6),
}
expectMetrics(t, cidrIPv6, em)
// Allocate all // Allocate all
a.Occupy(clusterCIDRv4) a.Occupy(clusterCIDRv4)
em := testMetrics{ em = testMetrics{
usage: 1, usage: 1,
allocs: 256, allocs: 256,
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(maxIPv4),
} }
expectMetrics(t, cidrIPv4, em) expectMetrics(t, cidrIPv4, em)
@ -948,6 +1003,7 @@ func TestCidrSetMetricsDual(t *testing.T) {
allocs: 65536, allocs: 65536,
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(maxIPv6),
} }
expectMetrics(t, cidrIPv6, em) expectMetrics(t, cidrIPv6, em)
@ -958,6 +1014,7 @@ func TestCidrSetMetricsDual(t *testing.T) {
allocs: 256, allocs: 256,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(maxIPv4),
} }
expectMetrics(t, cidrIPv4, em) expectMetrics(t, cidrIPv4, em)
b.Release(clusterCIDRv6) b.Release(clusterCIDRv6)
@ -966,9 +1023,47 @@ func TestCidrSetMetricsDual(t *testing.T) {
allocs: 65536, allocs: 65536,
releases: 65536, releases: 65536,
allocTries: 0, allocTries: 0,
max: float64(maxIPv6),
} }
expectMetrics(t, cidrIPv6, em) expectMetrics(t, cidrIPv6, em)
}
func Test_getMaxCIDRs(t *testing.T) {
cidrIPv4 := "10.0.0.0/16"
_, clusterCIDRv4, _ := netutils.ParseCIDRSloppy(cidrIPv4)
cidrIPv6 := "2001:db8::/48"
_, clusterCIDRv6, _ := netutils.ParseCIDRSloppy(cidrIPv6)
tests := []struct {
name string
subNetMaskSize int
clusterCIDR *net.IPNet
expectedMaxCIDRs int
}{
{
name: "IPv4",
subNetMaskSize: 24,
clusterCIDR: clusterCIDRv4,
expectedMaxCIDRs: 256,
},
{
name: "IPv6",
subNetMaskSize: 64,
clusterCIDR: clusterCIDRv6,
expectedMaxCIDRs: 65536,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
clusterMaskSize, _ := test.clusterCIDR.Mask.Size()
maxCIDRs := getMaxCIDRs(test.subNetMaskSize, clusterMaskSize)
if test.expectedMaxCIDRs != maxCIDRs {
t.Errorf("incorrect maxCIDRs, expected: %d, got: %d", test.expectedMaxCIDRs, maxCIDRs)
}
})
}
} }
// Metrics helpers // Metrics helpers
@ -977,6 +1072,7 @@ func clearMetrics(labels map[string]string) {
cidrSetReleases.Delete(labels) cidrSetReleases.Delete(labels)
cidrSetUsage.Delete(labels) cidrSetUsage.Delete(labels)
cidrSetAllocationTriesPerRequest.Delete(labels) cidrSetAllocationTriesPerRequest.Delete(labels)
cidrSetMaxCidrs.Delete(labels)
} }
type testMetrics struct { type testMetrics struct {
@ -984,6 +1080,7 @@ type testMetrics struct {
allocs float64 allocs float64
releases float64 releases float64
allocTries float64 allocTries float64
max float64
} }
func expectMetrics(t *testing.T, label string, em testMetrics) { func expectMetrics(t *testing.T, label string, em testMetrics) {
@ -1005,6 +1102,10 @@ func expectMetrics(t *testing.T, label string, em testMetrics) {
if err != nil { if err != nil {
t.Errorf("failed to get %s value, err: %v", cidrSetAllocationTriesPerRequest.Name, err) t.Errorf("failed to get %s value, err: %v", cidrSetAllocationTriesPerRequest.Name, err)
} }
m.max, err = testutil.GetGaugeMetricValue(cidrSetMaxCidrs.WithLabelValues(label))
if err != nil {
t.Errorf("failed to get %s value, err: %v", cidrSetMaxCidrs.Name, err)
}
if m != em { if m != em {
t.Fatalf("metrics error: expected %v, received %v", em, m) t.Fatalf("metrics error: expected %v, received %v", em, m)

View File

@ -44,6 +44,16 @@ var (
}, },
[]string{"clusterCIDR"}, []string{"clusterCIDR"},
) )
// This is a gauge, as in theory, a limit can increase or decrease.
cidrSetMaxCidrs = metrics.NewGaugeVec(
&metrics.GaugeOpts{
Subsystem: nodeIpamSubsystem,
Name: "cirdset_max_cidrs",
Help: "Maximum number of CIDRs that can be allocated.",
StabilityLevel: metrics.ALPHA,
},
[]string{"clusterCIDR"},
)
cidrSetUsage = metrics.NewGaugeVec( cidrSetUsage = metrics.NewGaugeVec(
&metrics.GaugeOpts{ &metrics.GaugeOpts{
Subsystem: nodeIpamSubsystem, Subsystem: nodeIpamSubsystem,
@ -72,6 +82,7 @@ func registerCidrsetMetrics() {
registerMetrics.Do(func() { registerMetrics.Do(func() {
legacyregistry.MustRegister(cidrSetAllocations) legacyregistry.MustRegister(cidrSetAllocations)
legacyregistry.MustRegister(cidrSetReleases) legacyregistry.MustRegister(cidrSetReleases)
legacyregistry.MustRegister(cidrSetMaxCidrs)
legacyregistry.MustRegister(cidrSetUsage) legacyregistry.MustRegister(cidrSetUsage)
legacyregistry.MustRegister(cidrSetAllocationTriesPerRequest) legacyregistry.MustRegister(cidrSetAllocationTriesPerRequest)
}) })

View File

@ -44,6 +44,16 @@ var (
}, },
[]string{"clusterCIDR"}, []string{"clusterCIDR"},
) )
// This is a gauge, as in theory, a limit can increase or decrease.
cidrSetMaxCidrs = metrics.NewGaugeVec(
&metrics.GaugeOpts{
Subsystem: nodeIpamSubsystem,
Name: "multicirdset_max_cidrs",
Help: "Maximum number of CIDRs that can be allocated.",
StabilityLevel: metrics.ALPHA,
},
[]string{"clusterCIDR"},
)
cidrSetUsage = metrics.NewGaugeVec( cidrSetUsage = metrics.NewGaugeVec(
&metrics.GaugeOpts{ &metrics.GaugeOpts{
Subsystem: nodeIpamSubsystem, Subsystem: nodeIpamSubsystem,
@ -72,6 +82,7 @@ func registerCidrsetMetrics() {
registerMetrics.Do(func() { registerMetrics.Do(func() {
legacyregistry.MustRegister(cidrSetAllocations) legacyregistry.MustRegister(cidrSetAllocations)
legacyregistry.MustRegister(cidrSetReleases) legacyregistry.MustRegister(cidrSetReleases)
legacyregistry.MustRegister(cidrSetMaxCidrs)
legacyregistry.MustRegister(cidrSetUsage) legacyregistry.MustRegister(cidrSetUsage)
legacyregistry.MustRegister(cidrSetAllocationTriesPerRequest) legacyregistry.MustRegister(cidrSetAllocationTriesPerRequest)
}) })

View File

@ -135,15 +135,19 @@ func NewMultiCIDRSet(cidrConfig *net.IPNet, perNodeHostBits int) (*MultiCIDRSet,
// Register MultiCIDRSet metrics. // Register MultiCIDRSet metrics.
registerCidrsetMetrics() registerCidrsetMetrics()
return &MultiCIDRSet{ maxCIDRs := getMaxCIDRs(subNetMaskSize, clusterMaskSize)
multiCIDRSet := &MultiCIDRSet{
ClusterCIDR: cidrConfig, ClusterCIDR: cidrConfig,
nodeMask: net.CIDRMask(subNetMaskSize, bits), nodeMask: net.CIDRMask(subNetMaskSize, bits),
clusterMaskSize: clusterMaskSize, clusterMaskSize: clusterMaskSize,
MaxCIDRs: 1 << uint32(subNetMaskSize-clusterMaskSize), MaxCIDRs: maxCIDRs,
NodeMaskSize: subNetMaskSize, NodeMaskSize: subNetMaskSize,
Label: cidrConfig.String(), Label: cidrConfig.String(),
AllocatedCIDRMap: make(map[string]bool, 0), AllocatedCIDRMap: make(map[string]bool, 0),
}, nil }
cidrSetMaxCidrs.WithLabelValues(multiCIDRSet.Label).Set(float64(maxCIDRs))
return multiCIDRSet, nil
} }
func (s *MultiCIDRSet) indexToCIDRBlock(index int) (*net.IPNet, error) { func (s *MultiCIDRSet) indexToCIDRBlock(index int) (*net.IPNet, error) {
@ -359,3 +363,9 @@ func (s *MultiCIDRSet) getIndexForIP(ip net.IP) (int, error) {
func (s *MultiCIDRSet) UpdateEvaluatedCount(evaluated int) { func (s *MultiCIDRSet) UpdateEvaluatedCount(evaluated int) {
cidrSetAllocationTriesPerRequest.WithLabelValues(s.Label).Observe(float64(evaluated)) cidrSetAllocationTriesPerRequest.WithLabelValues(s.Label).Observe(float64(evaluated))
} }
// getMaxCIDRs returns the max number of CIDRs that can be obtained by subdividing a mask of size `clusterMaskSize`
// into subnets with mask of size `subNetMaskSize`.
func getMaxCIDRs(subNetMaskSize, clusterMaskSize int) int {
return 1 << uint32(subNetMaskSize-clusterMaskSize)
}

View File

@ -673,12 +673,24 @@ func TestCIDRSetv6(t *testing.T) {
func TestMultiCIDRSetMetrics(t *testing.T) { func TestMultiCIDRSetMetrics(t *testing.T) {
cidr := "10.0.0.0/16" cidr := "10.0.0.0/16"
_, clusterCIDR, _ := utilnet.ParseCIDRSloppy(cidr) _, clusterCIDR, _ := utilnet.ParseCIDRSloppy(cidr)
clearMetrics(map[string]string{"clusterCIDR": cidr})
// We have 256 free cidrs // We have 256 free cidrs
a, err := NewMultiCIDRSet(clusterCIDR, 8) a, err := NewMultiCIDRSet(clusterCIDR, 8)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating MultiCIDRSet: %v", err) t.Fatalf("unexpected error creating MultiCIDRSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidr})
clusterMaskSize, _ := clusterCIDR.Mask.Size()
max := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(max),
}
expectMetrics(t, cidr, em)
// Allocate next all. // Allocate next all.
for i := 1; i <= 256; i++ { for i := 1; i <= 256; i++ {
@ -691,16 +703,18 @@ func TestMultiCIDRSetMetrics(t *testing.T) {
allocs: float64(i), allocs: float64(i),
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
} }
// Release all CIDRs. // Release all CIDRs.
a.Release(clusterCIDR) a.Release(clusterCIDR)
em := testMetrics{ em = testMetrics{
usage: 0, usage: 0,
allocs: 256, allocs: 256,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
@ -711,6 +725,7 @@ func TestMultiCIDRSetMetrics(t *testing.T) {
allocs: 512, allocs: 512,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
@ -719,21 +734,34 @@ func TestMultiCIDRSetMetrics(t *testing.T) {
func TestMultiCIDRSetMetricsHistogram(t *testing.T) { func TestMultiCIDRSetMetricsHistogram(t *testing.T) {
cidr := "10.0.0.0/16" cidr := "10.0.0.0/16"
_, clusterCIDR, _ := utilnet.ParseCIDRSloppy(cidr) _, clusterCIDR, _ := utilnet.ParseCIDRSloppy(cidr)
clearMetrics(map[string]string{"clusterCIDR": cidr})
// We have 256 free cidrs. // We have 256 free cidrs.
a, err := NewMultiCIDRSet(clusterCIDR, 8) a, err := NewMultiCIDRSet(clusterCIDR, 8)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating MultiCIDRSet: %v", err) t.Fatalf("unexpected error creating MultiCIDRSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidr})
clusterMaskSize, _ := clusterCIDR.Mask.Size()
max := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(max),
}
expectMetrics(t, cidr, em)
// Allocate half of the range. // Allocate half of the range.
// Occupy does not update the nextCandidate. // Occupy does not update the nextCandidate.
_, halfClusterCIDR, _ := utilnet.ParseCIDRSloppy("10.0.0.0/17") _, halfClusterCIDR, _ := utilnet.ParseCIDRSloppy("10.0.0.0/17")
a.Occupy(halfClusterCIDR) a.Occupy(halfClusterCIDR)
em := testMetrics{ em = testMetrics{
usage: 0.5, usage: 0.5,
allocs: 128, allocs: 128,
releases: 0, releases: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
// Allocate next should iterate until the next free cidr // Allocate next should iterate until the next free cidr
@ -746,6 +774,7 @@ func TestMultiCIDRSetMetricsHistogram(t *testing.T) {
usage: float64(129) / float64(256), usage: float64(129) / float64(256),
allocs: 129, allocs: 129,
releases: 0, releases: 0,
max: float64(max),
} }
expectMetrics(t, cidr, em) expectMetrics(t, cidr, em)
} }
@ -754,26 +783,53 @@ func TestMultiCIDRSetMetricsDual(t *testing.T) {
// create IPv4 cidrSet. // create IPv4 cidrSet.
cidrIPv4 := "10.0.0.0/16" cidrIPv4 := "10.0.0.0/16"
_, clusterCIDRv4, _ := utilnet.ParseCIDRSloppy(cidrIPv4) _, clusterCIDRv4, _ := utilnet.ParseCIDRSloppy(cidrIPv4)
clearMetrics(map[string]string{"clusterCIDR": cidrIPv4})
a, err := NewMultiCIDRSet(clusterCIDRv4, 8) a, err := NewMultiCIDRSet(clusterCIDRv4, 8)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating MultiCIDRSet: %v", err) t.Fatalf("unexpected error creating MultiCIDRSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidrIPv4})
clusterMaskSize, _ := clusterCIDRv4.Mask.Size()
maxIPv4 := getMaxCIDRs(24, clusterMaskSize)
em := testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(maxIPv4),
}
expectMetrics(t, cidrIPv4, em)
// create IPv6 cidrSet. // create IPv6 cidrSet.
cidrIPv6 := "2001:db8::/48" cidrIPv6 := "2001:db8::/48"
_, clusterCIDRv6, _ := utilnet.ParseCIDRSloppy(cidrIPv6) _, clusterCIDRv6, _ := utilnet.ParseCIDRSloppy(cidrIPv6)
clearMetrics(map[string]string{"clusterCIDR": cidrIPv6})
b, err := NewMultiCIDRSet(clusterCIDRv6, 64) b, err := NewMultiCIDRSet(clusterCIDRv6, 64)
if err != nil { if err != nil {
t.Fatalf("unexpected error creating MultiCIDRSet: %v", err) t.Fatalf("unexpected error creating MultiCIDRSet: %v", err)
} }
clearMetrics(map[string]string{"clusterCIDR": cidrIPv6})
clusterMaskSize, _ = clusterCIDRv6.Mask.Size()
maxIPv6 := getMaxCIDRs(64, clusterMaskSize)
em = testMetrics{
usage: 0,
allocs: 0,
releases: 0,
allocTries: 0,
max: float64(maxIPv6),
}
expectMetrics(t, cidrIPv6, em)
// Allocate all. // Allocate all.
a.Occupy(clusterCIDRv4) a.Occupy(clusterCIDRv4)
em := testMetrics{ em = testMetrics{
usage: 1, usage: 1,
allocs: 256, allocs: 256,
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(maxIPv4),
} }
expectMetrics(t, cidrIPv4, em) expectMetrics(t, cidrIPv4, em)
@ -783,6 +839,7 @@ func TestMultiCIDRSetMetricsDual(t *testing.T) {
allocs: 65536, allocs: 65536,
releases: 0, releases: 0,
allocTries: 0, allocTries: 0,
max: float64(maxIPv6),
} }
expectMetrics(t, cidrIPv6, em) expectMetrics(t, cidrIPv6, em)
@ -793,6 +850,7 @@ func TestMultiCIDRSetMetricsDual(t *testing.T) {
allocs: 256, allocs: 256,
releases: 256, releases: 256,
allocTries: 0, allocTries: 0,
max: float64(maxIPv4),
} }
expectMetrics(t, cidrIPv4, em) expectMetrics(t, cidrIPv4, em)
b.Release(clusterCIDRv6) b.Release(clusterCIDRv6)
@ -801,17 +859,57 @@ func TestMultiCIDRSetMetricsDual(t *testing.T) {
allocs: 65536, allocs: 65536,
releases: 65536, releases: 65536,
allocTries: 0, allocTries: 0,
max: float64(maxIPv6),
} }
expectMetrics(t, cidrIPv6, em) expectMetrics(t, cidrIPv6, em)
} }
func Test_getMaxCIDRs(t *testing.T) {
cidrIPv4 := "10.0.0.0/16"
_, clusterCIDRv4, _ := utilnet.ParseCIDRSloppy(cidrIPv4)
cidrIPv6 := "2001:db8::/48"
_, clusterCIDRv6, _ := utilnet.ParseCIDRSloppy(cidrIPv6)
tests := []struct {
name string
subNetMaskSize int
clusterCIDR *net.IPNet
expectedMaxCIDRs int
}{
{
name: "IPv4",
subNetMaskSize: 24,
clusterCIDR: clusterCIDRv4,
expectedMaxCIDRs: 256,
},
{
name: "IPv6",
subNetMaskSize: 64,
clusterCIDR: clusterCIDRv6,
expectedMaxCIDRs: 65536,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
clusterMaskSize, _ := test.clusterCIDR.Mask.Size()
maxCIDRs := getMaxCIDRs(test.subNetMaskSize, clusterMaskSize)
if test.expectedMaxCIDRs != maxCIDRs {
t.Errorf("incorrect maxCIDRs, expected: %d, got: %d", test.expectedMaxCIDRs, maxCIDRs)
}
})
}
}
// Metrics helpers. // Metrics helpers.
func clearMetrics(labels map[string]string) { func clearMetrics(labels map[string]string) {
cidrSetAllocations.Delete(labels) cidrSetAllocations.Delete(labels)
cidrSetReleases.Delete(labels) cidrSetReleases.Delete(labels)
cidrSetUsage.Delete(labels) cidrSetUsage.Delete(labels)
cidrSetAllocationTriesPerRequest.Delete(labels) cidrSetAllocationTriesPerRequest.Delete(labels)
cidrSetMaxCidrs.Delete(labels)
} }
type testMetrics struct { type testMetrics struct {
@ -819,6 +917,7 @@ type testMetrics struct {
allocs float64 allocs float64
releases float64 releases float64
allocTries float64 allocTries float64
max float64
} }
func expectMetrics(t *testing.T, label string, em testMetrics) { func expectMetrics(t *testing.T, label string, em testMetrics) {
@ -840,6 +939,10 @@ func expectMetrics(t *testing.T, label string, em testMetrics) {
if err != nil { if err != nil {
t.Errorf("failed to get %s value, err: %v", cidrSetAllocationTriesPerRequest.Name, err) t.Errorf("failed to get %s value, err: %v", cidrSetAllocationTriesPerRequest.Name, err)
} }
m.max, err = testutil.GetGaugeMetricValue(cidrSetMaxCidrs.WithLabelValues(label))
if err != nil {
t.Errorf("failed to get %s value, err: %v", cidrSetMaxCidrs.Name, err)
}
if m != em { if m != em {
t.Fatalf("metrics error: expected %v, received %v", em, m) t.Fatalf("metrics error: expected %v, received %v", em, m)