Skip to content

Commit

Permalink
Allow empty pod and service ranges in shoot spec for IPv6 single stac…
Browse files Browse the repository at this point in the history
…k. (gardener#10541)

* Allow empty pod and service ranges in shoot spec.

* Check ipfamily before setting shoot defaults.
  • Loading branch information
axel7born authored Sep 19, 2024
1 parent dd36bc2 commit 9fbc0e3
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 33 deletions.
16 changes: 8 additions & 8 deletions pkg/gardenlet/operation/shoot/shoot.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,20 +557,20 @@ func ToNetworks(shoot *gardencorev1beta1.Shoot, workerless bool) (*Networks, err
return nil, fmt.Errorf("cannot parse shoot's pod cidr %w", err)
}
pods = append(pods, *p)
} else if !workerless {
} else if !workerless && !gardencorev1beta1.IsIPv6SingleStack(shoot.Spec.Networking.IPFamilies) {
return nil, fmt.Errorf("shoot's pods cidr is empty")
}

if shoot.Spec.Networking.Services == nil {
if shoot.Spec.Networking.Services != nil {
_, s, err := net.ParseCIDR(*shoot.Spec.Networking.Services)
if err != nil {
return nil, fmt.Errorf("cannot parse shoot's network cidr %w", err)
}
services = append(services, *s)
} else if !gardencorev1beta1.IsIPv6SingleStack(shoot.Spec.Networking.IPFamilies) {
return nil, fmt.Errorf("shoot's service cidr is empty")
}

_, s, err := net.ParseCIDR(*shoot.Spec.Networking.Services)
if err != nil {
return nil, fmt.Errorf("cannot parse shoot's network cidr %w", err)
}
services = append(services, *s)

if shoot.Spec.Networking.Nodes != nil {
_, n, err := net.ParseCIDR(*shoot.Spec.Networking.Nodes)
if err != nil {
Expand Down
62 changes: 37 additions & 25 deletions plugin/pkg/shoot/validator/admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"net"
"reflect"
"slices"
"strconv"
Expand Down Expand Up @@ -877,6 +878,11 @@ func (c *validationContext) validateReferencedSecret(secretLister kubecorev1list
return nil
}

func cidrMatchesIPFamily(cidr string, ipfamilies []core.IPFamily) bool {
ip, _, _ := net.ParseCIDR(cidr)
return ip != nil && (ip.To4() != nil && slices.Contains(ipfamilies, core.IPFamilyIPv4) || ip.To4() == nil && slices.Contains(ipfamilies, core.IPFamilyIPv6))
}

func (c *validationContext) validateShootNetworks(a admission.Attributes, workerless bool) field.ErrorList {
var (
allErrs field.ErrorList
Expand All @@ -890,53 +896,59 @@ func (c *validationContext) validateShootNetworks(a admission.Attributes, worker
if c.seed != nil {
if c.shoot.Spec.Networking.Pods == nil && !workerless {
if c.seed.Spec.Networks.ShootDefaults != nil {
c.shoot.Spec.Networking.Pods = c.seed.Spec.Networks.ShootDefaults.Pods
} else {
if cidrMatchesIPFamily(*c.seed.Spec.Networks.ShootDefaults.Pods, c.shoot.Spec.Networking.IPFamilies) {
c.shoot.Spec.Networking.Pods = c.seed.Spec.Networks.ShootDefaults.Pods
}
} else if slices.Contains(c.shoot.Spec.Networking.IPFamilies, core.IPFamilyIPv4) {
allErrs = append(allErrs, field.Required(path.Child("pods"), "pods is required"))
}
}

if c.shoot.Spec.Networking.Services == nil {
if c.seed.Spec.Networks.ShootDefaults != nil {
c.shoot.Spec.Networking.Services = c.seed.Spec.Networks.ShootDefaults.Services
} else {
if cidrMatchesIPFamily(*c.seed.Spec.Networks.ShootDefaults.Services, c.shoot.Spec.Networking.IPFamilies) {
c.shoot.Spec.Networking.Services = c.seed.Spec.Networks.ShootDefaults.Services
}
} else if slices.Contains(c.shoot.Spec.Networking.IPFamilies, core.IPFamilyIPv4) {
allErrs = append(allErrs, field.Required(path.Child("services"), "services is required"))
}
}

// validate network disjointedness within shoot network
allErrs = append(allErrs, cidrvalidation.ValidateShootNetworkDisjointedness(
path,
c.shoot.Spec.Networking.Nodes,
c.shoot.Spec.Networking.Pods,
c.shoot.Spec.Networking.Services,
workerless,
)...)

// validate network disjointedness with seed networks if shoot is being (re)scheduled
if !apiequality.Semantic.DeepEqual(c.oldShoot.Spec.SeedName, c.shoot.Spec.SeedName) {
allErrs = append(allErrs, cidrvalidation.ValidateNetworkDisjointedness(
if slices.Contains(c.shoot.Spec.Networking.IPFamilies, core.IPFamilyIPv4) {
// validate network disjointedness within shoot network
allErrs = append(allErrs, cidrvalidation.ValidateShootNetworkDisjointedness(
path,
c.shoot.Spec.Networking.Nodes,
c.shoot.Spec.Networking.Pods,
c.shoot.Spec.Networking.Services,
c.seed.Spec.Networks.Nodes,
c.seed.Spec.Networks.Pods,
c.seed.Spec.Networks.Services,
workerless,
)...)

if c.shoot.Status.Networking != nil {
allErrs = append(allErrs, cidrvalidation.ValidateMultiNetworkDisjointedness(
field.NewPath("status", "networking"),
c.shoot.Status.Networking.Nodes,
c.shoot.Status.Networking.Pods,
c.shoot.Status.Networking.Services,
// validate network disjointedness with seed networks if shoot is being (re)scheduled
if !apiequality.Semantic.DeepEqual(c.oldShoot.Spec.SeedName, c.shoot.Spec.SeedName) {
allErrs = append(allErrs, cidrvalidation.ValidateNetworkDisjointedness(
path,
c.shoot.Spec.Networking.Nodes,
c.shoot.Spec.Networking.Pods,
c.shoot.Spec.Networking.Services,
c.seed.Spec.Networks.Nodes,
c.seed.Spec.Networks.Pods,
c.seed.Spec.Networks.Services,
workerless,
)...)

if c.shoot.Status.Networking != nil {
allErrs = append(allErrs, cidrvalidation.ValidateMultiNetworkDisjointedness(
field.NewPath("status", "networking"),
c.shoot.Status.Networking.Nodes,
c.shoot.Status.Networking.Pods,
c.shoot.Status.Networking.Services,
c.seed.Spec.Networks.Nodes,
c.seed.Spec.Networks.Pods,
c.seed.Spec.Networks.Services,
workerless,
)...)
}
}
}
}
Expand Down

0 comments on commit 9fbc0e3

Please sign in to comment.