diff --git a/internal/apis/networking/validation/network.go b/internal/apis/networking/validation/network.go index a0c35449e..9631d40b7 100644 --- a/internal/apis/networking/validation/network.go +++ b/internal/apis/networking/validation/network.go @@ -54,6 +54,29 @@ func validateNetworkSpec(namespace, name string, spec *networking.NetworkSpec, f allErrs = append(allErrs, validateNetworkPeering(peering, fldPath)...) } + seenPeeringClaimRefKeys := sets.New[client.ObjectKey]() + + for i, peeringClaimRef := range spec.PeeringClaimRefs { + fldPath := fldPath.Child("incomingPeerings").Index(i) + + peeringClaimRefNamespace := peeringClaimRef.Namespace + if peeringClaimRefNamespace == "" { + peeringClaimRefNamespace = namespace + } + + peeringClaimRefkKey := client.ObjectKey{Namespace: peeringClaimRefNamespace, Name: peeringClaimRef.Name} + + if name != "" && (client.ObjectKey{Namespace: namespace, Name: name}) == peeringClaimRefkKey { + allErrs = append(allErrs, field.Forbidden(fldPath, "cannot claim itself")) + } else if seenPeeringClaimRefKeys.Has(peeringClaimRefkKey) { + allErrs = append(allErrs, field.Duplicate(fldPath, peeringClaimRef)) + } else { + seenPeeringClaimRefKeys.Insert(peeringClaimRefkKey) + } + + allErrs = append(allErrs, validatePeeringClaimRef(peeringClaimRef, fldPath)...) + } + return allErrs } @@ -77,6 +100,26 @@ func validateNetworkPeering(peering networking.NetworkPeering, fldPath *field.Pa return allErrs } +func validatePeeringClaimRef(peeringClaimRef networking.NetworkPeeringClaimRef, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + + if len(peeringClaimRef.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name is required")) + } else { + for _, msg := range apivalidation.NameIsDNSLabel(peeringClaimRef.Name, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), peeringClaimRef.Name, msg)) + } + } + + if peeringClaimRef.Namespace != "" { + for _, msg := range apivalidation.NameIsDNSLabel(peeringClaimRef.Namespace, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), peeringClaimRef.Namespace, msg)) + } + } + + return allErrs +} + // ValidateNetworkUpdate validates a Network object before an update. func ValidateNetworkUpdate(newNetwork, oldNetwork *networking.Network) field.ErrorList { var allErrs field.ErrorList diff --git a/internal/apis/networking/validation/network_test.go b/internal/apis/networking/validation/network_test.go index ce293118f..e9166bcb7 100644 --- a/internal/apis/networking/validation/network_test.go +++ b/internal/apis/networking/validation/network_test.go @@ -68,6 +68,52 @@ var _ = Describe("Network", func() { }, ContainElement(DuplicateField("spec.peerings[1].networkRef")), ), + Entry("peering claim references itself", + &networking.Network{ + ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "foo"}, + Spec: networking.NetworkSpec{ + PeeringClaimRefs: []networking.NetworkPeeringClaimRef{ + { + Name: "foo", + Namespace: "ns", + }, + }, + }, + }, + ContainElement(ForbiddenField("spec.incomingPeerings[0]")), + ), + Entry("duplicate peering claim ref", + &networking.Network{ + Spec: networking.NetworkSpec{ + PeeringClaimRefs: []networking.NetworkPeeringClaimRef{ + {Name: "bar"}, + {Name: "bar"}, + }, + }, + }, + ContainElement(DuplicateField("spec.incomingPeerings[1]")), + ), + Entry("invalid peering claim ref name", + &networking.Network{ + Spec: networking.NetworkSpec{ + PeeringClaimRefs: []networking.NetworkPeeringClaimRef{ + {Name: "bar*"}, + }, + }, + }, + ContainElement(InvalidField("spec.incomingPeerings[0].name")), + ), + Entry("invalid peering claim ref namespace", + &networking.Network{ + Spec: networking.NetworkSpec{ + PeeringClaimRefs: []networking.NetworkPeeringClaimRef{ + {Namespace: "ns*"}, + }, + }, + }, + ContainElements(InvalidField("spec.incomingPeerings[0].namespace"), + RequiredField("spec.incomingPeerings[0].name")), + ), ) DescribeTable("ValidateNetworkUpdate",