Skip to content

Commit 7ba756a

Browse files
authored
Merge pull request #288 from kubernetes-sigs/prefix-0
Allow IPPool to have Prefix /0
2 parents a48a815 + f99333d commit 7ba756a

File tree

6 files changed

+81
-3
lines changed

6 files changed

+81
-3
lines changed

api/v1alpha2/inclusterippool_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type InClusterIPPoolSpec struct {
2828

2929
// Prefix is the network prefix to use.
3030
// +kubebuilder:validation:Maximum=128
31+
// +kubebuilder:validation:Minimum=0
3132
Prefix int `json:"prefix"`
3233

3334
// Gateway

config/crd/bases/ipam.cluster.x-k8s.io_globalinclusterippools.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ spec:
217217
prefix:
218218
description: Prefix is the network prefix to use.
219219
maximum: 128
220+
minimum: 0
220221
type: integer
221222
required:
222223
- addresses

config/crd/bases/ipam.cluster.x-k8s.io_inclusterippools.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ spec:
215215
prefix:
216216
description: Prefix is the network prefix to use.
217217
maximum: 128
218+
minimum: 0
218219
type: integer
219220
required:
220221
- addresses

internal/poolutil/pool_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ import (
2828
)
2929

3030
var _ = Describe("PoolSpecToIPSet", func() {
31+
It("should allow a pool spec with prefix /0", func() {
32+
spec := &v1alpha2.InClusterIPPoolSpec{
33+
Gateway: "192.168.0.1",
34+
Prefix: 0,
35+
Addresses: []string{
36+
"192.168.0.3-192.168.0.10",
37+
},
38+
}
39+
ipSet, err := PoolSpecToIPSet(spec)
40+
Expect(err).ToNot(HaveOccurred())
41+
Expect(ipSet.Contains(mustParse("192.168.0.3"))).To(BeTrue())
42+
Expect(ipSet.Contains(mustParse("192.168.0.3"))).To(BeTrue())
43+
Expect(ipSet.Contains(mustParse("192.168.0.5"))).To(BeTrue())
44+
Expect(ipSet.Contains(mustParse("192.168.0.6"))).To(BeTrue())
45+
Expect(ipSet.Contains(mustParse("192.168.0.7"))).To(BeTrue())
46+
Expect(IPSetCount(ipSet)).To(Equal(8))
47+
})
3148
It("converts a pool spec to a set", func() {
3249
spec := &v1alpha2.InClusterIPPoolSpec{
3350
Gateway: "192.168.0.1",

internal/webhooks/inclusterippool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ func (webhook *InClusterIPPool) validate(_, newPool types.GenericInClusterPool)
185185
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "addresses"), newPool.PoolSpec().Addresses, "addresses is required"))
186186
}
187187

188-
if newPool.PoolSpec().Prefix == 0 {
189-
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "prefix"), newPool.PoolSpec().Prefix, "a valid prefix is required"))
188+
if newPool.PoolSpec().Prefix < 0 {
189+
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "prefix"), newPool.PoolSpec().Addresses, "a valid prefix is required"))
190190
}
191191

192192
var hasIPv4Addr, hasIPv6Addr bool

internal/webhooks/inclusterippool_test.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,13 @@ func TestInvalidScenarios(t *testing.T) {
419419
expectedError: "provided address is not a valid IP, range, nor CIDR",
420420
},
421421
{
422-
testcase: "omitting a prefix should not be allowed",
422+
testcase: "negative prefix not allowed",
423423
spec: v1alpha2.InClusterIPPoolSpec{
424424
Addresses: []string{
425425
"10.0.0.25",
426426
"10.0.0.26",
427427
},
428+
Prefix: -1,
428429
Gateway: "10.0.0.1",
429430
},
430431
expectedError: "a valid prefix is required",
@@ -648,6 +649,63 @@ func TestInvalidScenarios(t *testing.T) {
648649
}
649650
}
650651

652+
func TestIPPool_Prefix(t *testing.T) {
653+
g := NewWithT(t)
654+
655+
scheme := runtime.NewScheme()
656+
g.Expect(ipamv1.AddToScheme(scheme)).To(Succeed())
657+
658+
namespacedPool := &v1alpha2.InClusterIPPool{
659+
ObjectMeta: metav1.ObjectMeta{
660+
Name: "my-pool",
661+
},
662+
Spec: v1alpha2.InClusterIPPoolSpec{
663+
Addresses: []string{"10.0.0.10-10.0.0.20"},
664+
Prefix: 0,
665+
Gateway: "10.0.0.1",
666+
},
667+
}
668+
669+
globalPool := &v1alpha2.GlobalInClusterIPPool{
670+
ObjectMeta: metav1.ObjectMeta{
671+
Name: "my-pool",
672+
},
673+
Spec: v1alpha2.InClusterIPPoolSpec{
674+
Addresses: []string{"10.0.0.10-10.0.0.20"},
675+
Prefix: 0,
676+
Gateway: "10.0.0.1",
677+
},
678+
}
679+
emptyPrefixPool := &v1alpha2.InClusterIPPool{
680+
ObjectMeta: metav1.ObjectMeta{
681+
Name: "my-pool",
682+
},
683+
Spec: v1alpha2.InClusterIPPoolSpec{
684+
Addresses: []string{"10.0.0.10-10.0.0.20"},
685+
Gateway: "10.0.0.1",
686+
},
687+
}
688+
689+
ips := []client.Object{
690+
createIP("my-ip", "10.0.0.10", namespacedPool),
691+
createIP("my-ip-2", "10.0.0.10", globalPool),
692+
}
693+
694+
fakeClient := fake.NewClientBuilder().
695+
WithScheme(scheme).
696+
WithObjects(ips...).
697+
WithIndex(&ipamv1.IPAddress{}, index.IPAddressPoolRefCombinedField, index.IPAddressByCombinedPoolRef).
698+
Build()
699+
700+
webhook := InClusterIPPool{
701+
Client: fakeClient,
702+
}
703+
704+
g.Expect(webhook.validate(&v1alpha2.InClusterIPPool{}, namespacedPool)).Error().To(BeNil(), "should allow /0 prefix InClusterIPPool")
705+
g.Expect(webhook.validate(&v1alpha2.GlobalInClusterIPPool{}, globalPool)).Error().To(BeNil(), "should allow /0 prefix GlobalInClusterIPPool")
706+
g.Expect(webhook.validate(&v1alpha2.InClusterIPPool{}, emptyPrefixPool)).Error().To(BeNil(), "should allow empty prefix InClusterIPPool")
707+
}
708+
651709
func runInvalidScenarioTests(t *testing.T, tt invalidScenarioTest, pool types.GenericInClusterPool, webhook InClusterIPPool) {
652710
t.Helper()
653711
t.Run(tt.testcase, func(t *testing.T) {

0 commit comments

Comments
 (0)