Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,5 @@ require (
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
)

replace github.com/openshift/api => github.com/barbacbd/api v0.0.0-20260406135515-7f681bb588e9
Comment on lines +130 to +131

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace directive to personal fork must be removed before merge.

This redirects the official github.com/openshift/api to a personal fork. As noted in the PR description, this is temporary for testing. Ensure this replace directive is removed and the changes are upstreamed to the official API repository before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` around lines 130 - 131, Remove the temporary replace directive that
maps "github.com/openshift/api" to the personal fork (the line starting with
replace github.com/openshift/api => github.com/barbacbd/api ...) from go.mod,
ensure the changes that required that fork are submitted/upstreamed to the
official github.com/openshift/api repository, then update the module graph (run
go mod tidy) and verify the project builds and CI passes so no local replace is
required.

4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7C
github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/barbacbd/api v0.0.0-20260406135515-7f681bb588e9 h1:+TKsZlhazwsJw6XU8t4eAQ/2r+3AkZtEZel6WvO7ea8=
github.com/barbacbd/api v0.0.0-20260406135515-7f681bb588e9/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
Expand Down Expand Up @@ -399,8 +401,6 @@ github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/openshift/api v0.0.0-20260318185450-1f2fa3f09f4e h1:n2fW82JRX5B/+eCULWIe06MAhJVaE8fUsvy0A0Gn9n4=
github.com/openshift/api v0.0.0-20260318185450-1f2fa3f09f4e/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 h1:Hr/R38eg5ZJXfbiaHumjJIN1buDZwhsm4ys4npVCXH0=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1/go.mod h1:Za51LlH76ALiQ/aKGBYJXmyJNkA//IDJ+I///30CA2M=
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20260319024802-3bab34a01ab7 h1:sbMonDqOIvgRVRm8yUqkW1dANr1tqhc/MfrAtMAQntc=
Expand Down
108 changes: 105 additions & 3 deletions pkg/cloud/gcp/actuators/machine/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,56 @@ func (r *Reconciler) create() error {
var networkInterfaces = []*compute.NetworkInterface{}

for _, nic := range r.providerSpec.NetworkInterfaces {
// Configure IPv4 access
accessConfigs := []*compute.AccessConfig{}
if nic.PublicIP {
accessConfigs = append(accessConfigs, &compute.AccessConfig{})
}

// Configure IPv6 access for dual stack
ipv6AccessConfigs := []*compute.AccessConfig{}
stackType := string(nic.StackType)
if stackType == "" {
// Default to IPv4 only for backward compatibility
stackType = string(machinev1.IPv4OnlyStackType)
}

// Configure the GCP stack type based on our API
var gcpStackType string
switch machinev1.StackType(stackType) {
case machinev1.IPv4OnlyStackType:
gcpStackType = "IPV4_ONLY"
case machinev1.DualStackStackType:
gcpStackType = "IPV4_IPV6"
default:
gcpStackType = "IPV4_ONLY"
}

// Determine IPv6 access type with default applied
ipv6AccessType := nic.IPv6AccessType
if nic.StackType == machinev1.DualStackStackType && ipv6AccessType == "" {
// Default to External for dual stack as documented in the API
ipv6AccessType = machinev1.ExternalIPv6AccessType
}

// Add IPv6 external access if configured for dual stack
if nic.StackType == machinev1.DualStackStackType &&
ipv6AccessType == machinev1.ExternalIPv6AccessType {
ipv6AccessConfigs = append(ipv6AccessConfigs, &compute.AccessConfig{
Name: "External IPv6",
Type: "DIRECT_IPV6",
})
}

computeNIC := &compute.NetworkInterface{
AccessConfigs: accessConfigs,
AccessConfigs: accessConfigs,
Ipv6AccessConfigs: ipv6AccessConfigs,
StackType: gcpStackType,
}

// Set static IPv6 address if provided
if nic.IPv6Address != "" {
computeNIC.Ipv6Address = nic.IPv6Address
}
projectID := nic.ProjectID
if projectID == "" {
Expand Down Expand Up @@ -486,9 +530,30 @@ func (r *Reconciler) reconcileMachineWithCloudState(failedCondition *metav1.Cond
}
networkInterface := freshInstance.NetworkInterfaces[0]

nodeAddresses := []corev1.NodeAddress{{Type: corev1.NodeInternalIP, Address: networkInterface.NetworkIP}}
nodeAddresses := []corev1.NodeAddress{}

// Add IPv4 internal IP if present
if networkInterface.NetworkIP != "" {
nodeAddresses = append(nodeAddresses, corev1.NodeAddress{Type: corev1.NodeInternalIP, Address: networkInterface.NetworkIP})
}

// Add IPv4 external IPs from access configs
for _, config := range networkInterface.AccessConfigs {
nodeAddresses = append(nodeAddresses, corev1.NodeAddress{Type: corev1.NodeExternalIP, Address: config.NatIP})
if config.NatIP != "" {
nodeAddresses = append(nodeAddresses, corev1.NodeAddress{Type: corev1.NodeExternalIP, Address: config.NatIP})
}
}

// Add IPv6 internal IP if present
if networkInterface.Ipv6Address != "" {
nodeAddresses = append(nodeAddresses, corev1.NodeAddress{Type: corev1.NodeInternalIP, Address: networkInterface.Ipv6Address})
}

// Add IPv6 external IPs from IPv6 access configs
for _, config := range networkInterface.Ipv6AccessConfigs {
if config.ExternalIpv6 != "" {
nodeAddresses = append(nodeAddresses, corev1.NodeAddress{Type: corev1.NodeExternalIP, Address: config.ExternalIpv6})
}
}
// Since we don't know when the project was created, we must account for
// both types of internal-dns:
Expand Down Expand Up @@ -609,6 +674,43 @@ func validateMachine(machine machinev1.Machine, providerSpec machinev1.GCPMachin
return machinecontroller.InvalidMachineConfiguration("preemptible cannot be used together with 'Spot' provisioning model")
}

// Validate dual stack network configuration
for i, nic := range providerSpec.NetworkInterfaces {
if nic == nil {
continue
}

stackType := nic.StackType
// Empty stack type defaults to IPv4Only, which is valid
if stackType == "" {
stackType = machinev1.IPv4OnlyStackType
}

// Validate stack type is a known value
if stackType != machinev1.IPv4OnlyStackType && stackType != machinev1.DualStackStackType {
return machinecontroller.InvalidMachineConfiguration("network interface %d has invalid stackType %q, valid values are: IPv4Only, DualStack", i, stackType)
}

// Validate IPv6AccessType
if nic.IPv6AccessType != "" {
// IPv6AccessType should only be set for dual stack configurations
if stackType != machinev1.DualStackStackType {
return machinecontroller.InvalidMachineConfiguration("network interface %d has ipv6AccessType set but stackType is %q (must be DualStack)", i, stackType)
}

// Validate IPv6AccessType value
if nic.IPv6AccessType != machinev1.ExternalIPv6AccessType && nic.IPv6AccessType != machinev1.InternalIPv6AccessType {
return machinecontroller.InvalidMachineConfiguration("network interface %d has invalid ipv6AccessType %q, valid values are: External, Internal", i, nic.IPv6AccessType)
}
}
// Note: empty IPv6AccessType defaults to External for DualStack, which is valid

// Validate IPv6Address is only set for dual stack configurations
if nic.IPv6Address != "" && stackType != machinev1.DualStackStackType {
return machinecontroller.InvalidMachineConfiguration("network interface %d has ipv6Address set but stackType is %q (must be DualStack)", i, stackType)
}
}

return nil
}

Expand Down
Loading