Skip to content

Commit 0c3b720

Browse files
committed
Address review comments for dual-stack IPv4/IPv6 support
- Remove deprecated subnetID field from machine class spec and template; subnetIDs already contains the same information - Use core.IsDualStack() instead of !core.IsIPv4SingleStack() for clarity - Move isDualStack check to flow graph level via shared.DoIf() for all IPv6 tasks; remove redundant early-return guards from task functions - Refactor PatchProviderStatusAndState: extract computeInfrastructureNetworkingStatus() on FlowContext to keep the function signature clean - Clarify docs: Option 2 (explicit IPv6 CIDRs) does not require a subnetPoolID; if both are set, explicit CIDRs take precedence
1 parent 5abc521 commit 0c3b720

9 files changed

Lines changed: 46 additions & 61 deletions

File tree

charts/internal/machineclass/templates/machineclass.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ providerSpec:
5656
imageName: {{ $machineClass.imageName }}
5757
{{- end }}
5858
networkID: {{ $machineClass.networkID }}
59-
subnetID: {{ $machineClass.subnetID }}
6059
subnetIDs:
6160
{{ toYaml $machineClass.subnetIDs | indent 6 }}
6261
podNetworkCIDRs:

docs/usage/usage.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ Unlike IPv4 where you explicitly specify the CIDR in `networks.workers`, IPv6 ad
110110

111111
#### Option 2: Explicit IPv6 CIDR Configuration
112112

113-
Alternatively, you can explicitly specify IPv6 CIDRs for nodes, pods, and services using the `networks.ipv6` field:
113+
Alternatively, you can explicitly specify IPv6 CIDRs for nodes, pods, and services using the `networks.ipv6` field.
114+
In this case, IPv6 subnets are created without a subnet pool (using the provided CIDRs directly), so no `subnetPoolID` is required.
115+
If a `subnetPoolID` is also set, the explicit CIDRs from `networks.ipv6` take precedence and the pool is not used for CIDR allocation.
114116

115117
```yaml
116118
apiVersion: openstack.provider.extensions.gardener.cloud/v1alpha1

pkg/admission/validator/shoot.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,9 @@ func (s *shoot) validateShoot(ctx context.Context, context *validationContext) f
179179
allErrs = append(allErrs, openstackvalidation.ValidateNetworking(context.shoot.Spec.Networking, nwPath)...)
180180
allErrs = append(allErrs, openstackvalidation.ValidateInfrastructureConfig(context.infraConfig, context.shoot.Spec.Networking.Nodes, infraConfigPath)...)
181181

182-
// Validate that either SubnetPoolID or IPv6 config is set for dual-stack shoots
183-
if !core.IsIPv4SingleStack(context.shoot.Spec.Networking.IPFamilies) {
182+
// Validate that either SubnetPoolID or IPv6 config is set for dual-stack shoots.
183+
// It is valid to set both; in that case the explicit networks.ipv6 CIDRs take precedence.
184+
if core.IsDualStack(context.shoot.Spec.Networking.IPFamilies) {
184185
if context.infraConfig.SubnetPoolID == nil && context.infraConfig.Networks.IPv6 == nil {
185186
allErrs = append(allErrs, field.Required(infraConfigPath, "either subnetPoolID or networks.ipv6 must be set for dual-stack shoots"))
186187
}

pkg/controller/infrastructure/actuator_reconcile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,5 @@ func (a *actuator) migrateFromTerraform(ctx context.Context, log logr.Logger, in
102102
// we mark that there are infra resources created.
103103
state.Data[infraflow.CreatedResourcesExistKey] = "true"
104104

105-
return state, infraflow.PatchProviderStatusAndState(ctx, a.client, infra, nil, nil, &runtime.RawExtension{Object: state}, nil, nil, nil)
105+
return state, infraflow.PatchProviderStatusAndState(ctx, a.client, infra, nil, &runtime.RawExtension{Object: state}, nil)
106106
}

pkg/controller/infrastructure/infraflow/context.go

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -156,50 +156,25 @@ func NewFlowContext(opts Opts) (*FlowContext, error) {
156156
}
157157

158158
func (fctx *FlowContext) persistState(ctx context.Context) error {
159-
return PatchProviderStatusAndState(ctx, fctx.client, fctx.infra, fctx.shootNetworking, nil, fctx.computeInfrastructureState(), nil, nil, nil)
159+
return PatchProviderStatusAndState(ctx, fctx.client, fctx.infra, nil, fctx.computeInfrastructureState(), nil)
160160
}
161161

162162
// PatchProviderStatusAndState patches the infrastructure status with the given provider specific status and state.
163163
func PatchProviderStatusAndState(
164164
ctx context.Context,
165165
runtimeClient client.Client,
166166
infra *extensionsv1alpha1.Infrastructure,
167-
networking *gardencorev1beta1.Networking,
168167
status *openstackv1alpha1.InfrastructureStatus,
169168
state *runtime.RawExtension,
170-
nodesSubnetIPv6CIDR *string,
171-
podSubnetIPv6CIDR *string,
172-
servicesSubnetIPv6CIDR *string,
169+
networkingStatus *extensionsv1alpha1.InfrastructureStatusNetworking,
173170
) error {
174171
patch := client.MergeFrom(infra.DeepCopy())
175172
if status != nil {
176173
infra.Status.ProviderStatus = &runtime.RawExtension{Object: status}
177174
infra.Status.EgressCIDRs = ComputeEgressCIDRs(status.Networks.Router.ExternalFixedIPs)
178175
}
179176

180-
infra.Status.Networking = &extensionsv1alpha1.InfrastructureStatusNetworking{}
181-
182-
if networking != nil {
183-
if networking.Nodes != nil {
184-
infra.Status.Networking.Nodes = append(infra.Status.Networking.Nodes, *networking.Nodes)
185-
}
186-
if networking.Pods != nil {
187-
infra.Status.Networking.Pods = append(infra.Status.Networking.Pods, *networking.Pods)
188-
}
189-
if networking.Services != nil {
190-
infra.Status.Networking.Services = append(infra.Status.Networking.Services, *networking.Services)
191-
}
192-
}
193-
194-
if nodesSubnetIPv6CIDR != nil {
195-
infra.Status.Networking.Nodes = append(infra.Status.Networking.Nodes, *nodesSubnetIPv6CIDR)
196-
}
197-
if podSubnetIPv6CIDR != nil {
198-
infra.Status.Networking.Pods = append(infra.Status.Networking.Pods, *podSubnetIPv6CIDR)
199-
}
200-
if servicesSubnetIPv6CIDR != nil {
201-
infra.Status.Networking.Services = append(infra.Status.Networking.Services, *servicesSubnetIPv6CIDR)
202-
}
177+
infra.Status.Networking = networkingStatus
203178

204179
if state != nil {
205180
infra.Status.State = state
@@ -215,6 +190,36 @@ func PatchProviderStatusAndState(
215190
return runtimeClient.Status().Patch(ctx, infra, patch)
216191
}
217192

193+
// computeInfrastructureNetworkingStatus builds the InfrastructureStatusNetworking from the shoot networking
194+
// spec and any IPv6 CIDRs allocated during reconciliation.
195+
func (fctx *FlowContext) computeInfrastructureNetworkingStatus() *extensionsv1alpha1.InfrastructureStatusNetworking {
196+
networking := &extensionsv1alpha1.InfrastructureStatusNetworking{}
197+
198+
if fctx.shootNetworking != nil {
199+
if fctx.shootNetworking.Nodes != nil {
200+
networking.Nodes = append(networking.Nodes, *fctx.shootNetworking.Nodes)
201+
}
202+
if fctx.shootNetworking.Pods != nil {
203+
networking.Pods = append(networking.Pods, *fctx.shootNetworking.Pods)
204+
}
205+
if fctx.shootNetworking.Services != nil {
206+
networking.Services = append(networking.Services, *fctx.shootNetworking.Services)
207+
}
208+
}
209+
210+
if nodeCIDR := fctx.state.Get(IdentifierNodeSubnetIPv6CIDR); nodeCIDR != nil {
211+
networking.Nodes = append(networking.Nodes, *nodeCIDR)
212+
}
213+
if podCIDR := fctx.state.Get(IdentifierPodSubnetIPv6CIDR); podCIDR != nil {
214+
networking.Pods = append(networking.Pods, *podCIDR)
215+
}
216+
if svcCIDR := fctx.state.Get(IdentifierServiceSubnetIPv6CIDR); svcCIDR != nil {
217+
networking.Services = append(networking.Services, *svcCIDR)
218+
}
219+
220+
return networking
221+
}
222+
218223
func (fctx *FlowContext) computeInfrastructureState() *runtime.RawExtension {
219224
return &runtime.RawExtension{
220225
Object: &openstackv1alpha1.InfrastructureState{

pkg/controller/infrastructure/infraflow/reconcile.go

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,8 @@ func (fctx *FlowContext) Reconcile(ctx context.Context) error {
4545

4646
state := fctx.computeInfrastructureState()
4747
status := fctx.computeInfrastructureStatus()
48-
nodeCIDR := fctx.state.Get(IdentifierNodeSubnetIPv6CIDR)
49-
podCIDR := fctx.state.Get(IdentifierPodSubnetIPv6CIDR)
50-
svcCIDR := fctx.state.Get(IdentifierServiceSubnetIPv6CIDR)
51-
return PatchProviderStatusAndState(ctx, fctx.client, fctx.infra, fctx.shootNetworking, status, state, nodeCIDR, podCIDR, svcCIDR)
52-
//return PatchProviderStatusAndState(ctx, fctx.client, fctx.infra, fctx.shootNetworking, status, state, nil, nil, nil)
48+
networkingStatus := fctx.computeInfrastructureNetworkingStatus()
49+
return PatchProviderStatusAndState(ctx, fctx.client, fctx.infra, status, state, networkingStatus)
5350
}
5451

5552
func (fctx *FlowContext) buildReconcileGraph() *flow.Graph {
@@ -79,20 +76,20 @@ func (fctx *FlowContext) buildReconcileGraph() *flow.Graph {
7976

8077
ensureSubnetIPv6 := fctx.AddTask(g, "ensure IPv6 subnet",
8178
fctx.ensureSubnetIPv6,
82-
shared.Timeout(defaultTimeout), shared.Dependencies(ensureNetwork))
79+
shared.Timeout(defaultTimeout), shared.Dependencies(ensureNetwork), shared.DoIf(gardencorev1beta1.IsDualStack(fctx.shootNetworking.IPFamilies)))
8380

8481
_ = fctx.AddTask(g, "ensure router interface",
8582
fctx.ensureRouterInterface,
8683
shared.Timeout(defaultTimeout), shared.Dependencies(ensureRouter, ensureSubnet))
8784

8885
_ = fctx.AddTask(g, "ensure IPv6 router interface",
8986
fctx.ensureRouterInterfaceIPv6,
90-
shared.Timeout(defaultTimeout), shared.Dependencies(ensureRouter, ensureSubnetIPv6))
87+
shared.Timeout(defaultTimeout), shared.Dependencies(ensureRouter, ensureSubnetIPv6), shared.DoIf(gardencorev1beta1.IsDualStack(fctx.shootNetworking.IPFamilies)))
9188

9289
_ = fctx.AddTask(g, "ensure IPv6 CIDR services", fctx.ensureIPv6CIDRs,
9390
shared.Timeout(defaultTimeout),
9491
shared.Dependencies(ensureSubnetIPv6),
95-
shared.DoIf(fctx.isDualStack()),
92+
shared.DoIf(gardencorev1beta1.IsDualStack(fctx.shootNetworking.IPFamilies)),
9693
)
9794

9895
ensureSecGroup := fctx.AddTask(g, "ensure security group",
@@ -337,9 +334,6 @@ func (fctx *FlowContext) ensureSubnet(ctx context.Context) error {
337334
func (fctx *FlowContext) ensureSubnetIPv6(ctx context.Context) error {
338335
log := shared.LogFromContext(ctx)
339336

340-
if !fctx.isDualStack() {
341-
return nil
342-
}
343337
if fctx.state.Get(IdentifierNetwork) == nil {
344338
return fmt.Errorf("missing cluster network ID")
345339
}
@@ -415,10 +409,6 @@ func (fctx *FlowContext) ensureSubnetIPv6(ctx context.Context) error {
415409
func (fctx *FlowContext) ensureIPv6CIDRs(ctx context.Context) error {
416410
log := shared.LogFromContext(ctx)
417411

418-
if !fctx.isDualStack() {
419-
return nil
420-
}
421-
422412
// If explicit IPv6 CIDRs are configured, use them directly
423413
if fctx.hasExplicitIPv6Config() {
424414
nodeCIDR := fctx.config.Networks.IPv6.NodeCIDR
@@ -559,9 +549,6 @@ func (fctx *FlowContext) ensureRouterInterface(ctx context.Context) error {
559549

560550
func (fctx *FlowContext) ensureRouterInterfaceIPv6(ctx context.Context) error {
561551
log := shared.LogFromContext(ctx)
562-
if !fctx.isDualStack() {
563-
return nil
564-
}
565552
routerID := fctx.state.Get(IdentifierRouter)
566553
if routerID == nil {
567554
return fmt.Errorf("internal error: missing routerID")
@@ -660,7 +647,7 @@ func (fctx *FlowContext) ensureSecGroupRules(ctx context.Context) error {
660647
},
661648
}
662649

663-
if fctx.isDualStack() {
650+
if gardencorev1beta1.IsDualStack(fctx.shootNetworking.IPFamilies) {
664651
desiredRules = append(desiredRules, []rules.SecGroupRule{
665652
{
666653
Direction: string(rules.DirIngress),

pkg/controller/infrastructure/infraflow/utils.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"sync"
1414
"time"
1515

16-
gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
1716
"github.com/go-logr/logr"
1817
"github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers"
1918
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers"
@@ -213,12 +212,6 @@ func (fctx *FlowContext) workersCIDR() string {
213212
return fctx.config.WorkersCIDR()
214213
}
215214

216-
// isDualStack returns true if the cluster is configured for dual-stack networking
217-
// or has migrated from dual-stack to single-stack (indicated by having 2 node CIDRs).
218-
func (fctx *FlowContext) isDualStack() bool {
219-
return !gardencorev1beta1.IsIPv4SingleStack(fctx.shootNetworking.IPFamilies)
220-
}
221-
222215
// hasExplicitIPv6Config returns true if the IPv6 configuration with explicit CIDRs is set
223216
func (fctx *FlowContext) hasExplicitIPv6Config() bool {
224217
return fctx.config.Networks.IPv6 != nil

pkg/controller/worker/machines.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ func (w *WorkerDelegate) generateMachineConfig(ctx context.Context) error {
207207
subnetIDs = append(subnetIDs, subnet.ID)
208208
}
209209

210-
machineClassSpec["subnetID"] = subnets[0].ID
211210
machineClassSpec["subnetIDs"] = subnetIDs
212211

213212
if volumeSize > 0 {

pkg/controller/worker/machines_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ var _ = Describe("Machines", func() {
582582
"region": region,
583583
"keyName": keyName,
584584
"networkID": networkID,
585-
"subnetID": subnetID,
586585
"podNetworkCIDRs": []string{podCIDR},
587586
"securityGroups": []string{securityGroupName},
588587
"subnetIDs": []string{subnetID},

0 commit comments

Comments
 (0)