diff --git a/go.mod b/go.mod
index 3d7b94ac6..4b57aa4fc 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,8 @@ module github.com/openshift/client-go
go 1.25.0
+replace github.com/openshift/api => github.com/bhperry/openshift-api v0.0.0-20260430171308-07f1fbedc28f
+
require (
github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee
diff --git a/go.sum b/go.sum
index 8df7fca2a..b2c535d33 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,7 @@
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/bhperry/openshift-api v0.0.0-20260430171308-07f1fbedc28f h1:R930pInp3YsxDUcvx8nXgQyga1z2f/xcnDEbtM44rRo=
+github.com/bhperry/openshift-api v0.0.0-20260430171308-07f1fbedc28f/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -55,8 +57,6 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
-github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9 h1:lZw6pYY7El1giNk1lYvkp6hLungiqwIOqLlH+Hm7w9g=
-github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee h1:+Sp5GGnjHDhT/a/nQ1xdp43UscBMr7G5wxsYotyhzJ4=
github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
diff --git a/operator/applyconfigurations/internal/internal.go b/operator/applyconfigurations/internal/internal.go
index 7603b0595..e5359c1d3 100644
--- a/operator/applyconfigurations/internal/internal.go
+++ b/operator/applyconfigurations/internal/internal.go
@@ -3366,6 +3366,9 @@ var schemaYAML = typed.YAMLObject(`types:
type:
scalar: string
default: ""
+ - name: nodeUID
+ type:
+ scalar: string
- name: targetRevision
type:
scalar: numeric
diff --git a/operator/applyconfigurations/operator/v1/nodestatus.go b/operator/applyconfigurations/operator/v1/nodestatus.go
index f107c370d..9a796d563 100644
--- a/operator/applyconfigurations/operator/v1/nodestatus.go
+++ b/operator/applyconfigurations/operator/v1/nodestatus.go
@@ -4,6 +4,7 @@ package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
)
// NodeStatusApplyConfiguration represents a declarative configuration of the NodeStatus type for use
@@ -13,6 +14,10 @@ import (
type NodeStatusApplyConfiguration struct {
// nodeName is the name of the node
NodeName *string `json:"nodeName,omitempty"`
+ // nodeUID is the UID of the node.
+ // This field is used to detect that a node has been deleted and recreated with the same name.
+ // When the UID changes, it indicates the node is a new instance and the status should be reset.
+ NodeUID *types.UID `json:"nodeUID,omitempty"`
// currentRevision is the generation of the most recently successful deployment.
// Can not be set on creation of a nodeStatus. Updates must only increase the value.
CurrentRevision *int32 `json:"currentRevision,omitempty"`
@@ -47,6 +52,14 @@ func (b *NodeStatusApplyConfiguration) WithNodeName(value string) *NodeStatusApp
return b
}
+// WithNodeUID sets the NodeUID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the NodeUID field is set to the value of the last call.
+func (b *NodeStatusApplyConfiguration) WithNodeUID(value types.UID) *NodeStatusApplyConfiguration {
+ b.NodeUID = &value
+ return b
+}
+
// WithCurrentRevision sets the CurrentRevision field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the CurrentRevision field is set to the value of the last call.
diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go
index c579be3a1..e7680899d 100644
--- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go
+++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go
@@ -295,7 +295,8 @@ type ExternalPlatformSpec struct {
// PlatformSpec holds the desired state specific to the underlying infrastructure provider
// of the current cluster. Since these are used at spec-level for the underlying cluster, it
// is supposed that only one of the spec structs is set.
-// +kubebuilder:validation:XValidation:rule="!has(oldSelf.vsphere) && has(self.vsphere) ? size(self.vsphere.vcenters) < 2 : true",message="vcenters can have at most 1 item when configured post-install"
+// +openshift:validation:FeatureGateAwareXValidation:featureGate="",rule="!has(oldSelf.vsphere) && has(self.vsphere) ? (has(self.vsphere.vcenters) && size(self.vsphere.vcenters) < 2) : true",message="vcenters can have at most 1 item when configured post-install"
+// +openshift:validation:FeatureGateAwareXValidation:featureGate=VSphereMultiVCenterDay2,rule="oldSelf.?vsphere.vcenters.hasValue() ? self.?vsphere.vcenters.hasValue() : true",message="vcenters is required once set and cannot be removed"
type PlatformSpec struct {
// type is the underlying infrastructure provider for the cluster. This
// value controls whether infrastructure automation such as service load
@@ -1641,21 +1642,24 @@ type VSpherePlatformNodeNetworking struct {
// use these fields for configuration.
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.apiServerInternalIPs) || has(self.apiServerInternalIPs)",message="apiServerInternalIPs list is required once set"
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.ingressIPs) || has(self.ingressIPs)",message="ingressIPs list is required once set"
-// +kubebuilder:validation:XValidation:rule="!has(oldSelf.vcenters) && has(self.vcenters) ? size(self.vcenters) < 2 : true",message="vcenters can have at most 1 item when configured post-install"
type VSpherePlatformSpec struct {
// vcenters holds the connection details for services to communicate with vCenter.
- // Currently, only a single vCenter is supported, but in tech preview 3 vCenters are supported.
+ // Up to 3 vCenters are supported.
// Once the cluster has been installed, you are unable to change the current number of defined
- // vCenters except in the case where the cluster has been upgraded from a version of OpenShift
- // where the vsphere platform spec was not present. You may make modifications to the existing
+ // vCenters except when 1.) the cluster has been upgraded from a version of OpenShift
+ // where the vsphere platform spec was not present or 2.) in TechPreview you are able to add and
+ // remove vCenters but may not remove all vCenters. You may make modifications to the existing
// vCenters that are defined in the vcenters list in order to match with any added or modified
// failure domains.
// ---
// + If VCenters is not defined use the existing cloud-config configmap defined
// + in openshift-config.
- // +kubebuilder:validation:MinItems=0
+ // +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=3
- // +kubebuilder:validation:XValidation:rule="size(self) != size(oldSelf) ? size(oldSelf) == 0 && size(self) < 2 : true",message="vcenters cannot be added or removed once set"
+ // +openshift:validation:FeatureGateAwareXValidation:featureGate="",rule="size(self) != size(oldSelf) ? size(oldSelf) == 0 && size(self) < 2 : true",message="vcenters cannot be added or removed once set"
+ // +openshift:validation:FeatureGateAwareXValidation:featureGate=VSphereMultiVCenterDay2,rule="size(self) >= size(oldSelf) ? oldSelf.all(x, self.exists(y, y.server == x.server)) : true",message="Cannot add and remove vCenters at the same time"
+ // +openshift:validation:FeatureGateAwareXValidation:featureGate=VSphereMultiVCenterDay2,rule="size(self) < size(oldSelf) ? self.all(x, oldSelf.exists(y, y.server == x.server)) : true",message="Cannot add and remove vCenters at the same time"
+ // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, y.server == x.server))",message="vcenters must have unique server values"
// +listType=atomic
// +optional
VCenters []VSpherePlatformVCenterSpec `json:"vcenters,omitempty"`
diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml
index 75233bff7..ff232e723 100644
--- a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml
+++ b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml
@@ -376,6 +376,7 @@ infrastructures.config.openshift.io:
- OnPremDNSRecords
- VSphereHostVMGroupZonal
- VSphereMultiNetworks
+ - VSphereMultiVCenterDay2
FilenameOperatorName: config-operator
FilenameOperatorOrdering: "01"
FilenameRunLevel: "0000_10"
diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go
index f386a8112..b35922c58 100644
--- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go
+++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go
@@ -2082,7 +2082,7 @@ func (VSpherePlatformNodeNetworkingSpec) SwaggerDoc() map[string]string {
var map_VSpherePlatformSpec = map[string]string{
"": "VSpherePlatformSpec holds the desired state of the vSphere infrastructure provider. In the future the cloud provider operator, storage operator and machine operator will use these fields for configuration.",
- "vcenters": "vcenters holds the connection details for services to communicate with vCenter. Currently, only a single vCenter is supported, but in tech preview 3 vCenters are supported. Once the cluster has been installed, you are unable to change the current number of defined vCenters except in the case where the cluster has been upgraded from a version of OpenShift where the vsphere platform spec was not present. You may make modifications to the existing vCenters that are defined in the vcenters list in order to match with any added or modified failure domains.",
+ "vcenters": "vcenters holds the connection details for services to communicate with vCenter. Up to 3 vCenters are supported. Once the cluster has been installed, you are unable to change the current number of defined vCenters except when 1.) the cluster has been upgraded from a version of OpenShift where the vsphere platform spec was not present or 2.) in TechPreview you are able to add and remove vCenters but may not remove all vCenters. You may make modifications to the existing vCenters that are defined in the vcenters list in order to match with any added or modified failure domains.",
"failureDomains": "failureDomains contains the definition of region, zone and the vCenter topology. If this is omitted failure domains (regions and zones) will not be used.",
"nodeNetworking": "nodeNetworking contains the definition of internal and external network constraints for assigning the node's networking. If this field is omitted, networking defaults to the legacy address selection behavior which is to only support a single address and return the first one found.",
"apiServerInternalIPs": "apiServerInternalIPs are the IP addresses to contact the Kubernetes API server that can be used by components inside the cluster, like kubelets using the infrastructure rather than Kubernetes networking. These are the IPs for a self-hosted load balancer in front of the API servers. In dual stack clusters this list contains two IP addresses, one from IPv4 family and one from IPv6. In single stack clusters a single IP address is expected. When omitted, values from the status.apiServerInternalIPs will be used. Once set, the list cannot be completely removed (but its second entry can).",
diff --git a/vendor/github.com/openshift/api/console/v1/types_console_plugin.go b/vendor/github.com/openshift/api/console/v1/types_console_plugin.go
index 0160a4a24..c63db50d5 100644
--- a/vendor/github.com/openshift/api/console/v1/types_console_plugin.go
+++ b/vendor/github.com/openshift/api/console/v1/types_console_plugin.go
@@ -90,7 +90,6 @@ type ConsolePluginSpec struct {
// OpenShift web console server CSP response header:
// Content-Security-Policy: default-src 'self'; base-uri 'self'; script-src 'self' https://script1.com/ https://script2.com/ https://script3.com/; font-src 'self' https://font1.com/ https://font2.com/; img-src 'self' https://img1.com/; style-src 'self'; frame-src 'none'; object-src 'none'
//
- // +openshift:enable:FeatureGate=ConsolePluginContentSecurityPolicy
// +kubebuilder:validation:MaxItems=5
// +kubebuilder:validation:XValidation:rule="self.map(x, x.values.map(y, y.size()).sum()).sum() < 8192",message="the total combined size of values of all directives must not exceed 8192 (8kb)"
// +listType=map
diff --git a/vendor/github.com/openshift/api/console/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/console/v1/zz_generated.featuregated-crd-manifests.yaml
index caa676e69..26524d0a1 100644
--- a/vendor/github.com/openshift/api/console/v1/zz_generated.featuregated-crd-manifests.yaml
+++ b/vendor/github.com/openshift/api/console/v1/zz_generated.featuregated-crd-manifests.yaml
@@ -137,8 +137,7 @@ consoleplugins.console.openshift.io:
CRDName: consoleplugins.console.openshift.io
Capability: Console
Category: ""
- FeatureGates:
- - ConsolePluginContentSecurityPolicy
+ FeatureGates: []
FilenameOperatorName: ""
FilenameOperatorOrdering: "90"
FilenameRunLevel: ""
diff --git a/vendor/github.com/openshift/api/features.md b/vendor/github.com/openshift/api/features.md
index 24149f56e..eb3235e2b 100644
--- a/vendor/github.com/openshift/api/features.md
+++ b/vendor/github.com/openshift/api/features.md
@@ -92,7 +92,6 @@
| AzureWorkloadIdentity| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
| BootImageSkewEnforcement| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
| BuildCSIVolumes| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
-| ConsolePluginContentSecurityPolicy| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
| DualReplica| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
| EventTTL| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
| ExternalOIDC| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled |
diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml
index 4e3d95585..c5d566e19 100644
--- a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml
+++ b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml
@@ -40,6 +40,7 @@ controllerconfigs.machineconfiguration.openshift.io:
- OnPremDNSRecords
- VSphereHostVMGroupZonal
- VSphereMultiNetworks
+ - VSphereMultiVCenterDay2
FilenameOperatorName: machine-config
FilenameOperatorOrdering: "01"
FilenameRunLevel: "0000_80"
diff --git a/vendor/github.com/openshift/api/openapi/openapi.json b/vendor/github.com/openshift/api/openapi/openapi.json
index c8511e062..a9dbb2456 100644
--- a/vendor/github.com/openshift/api/openapi/openapi.json
+++ b/vendor/github.com/openshift/api/openapi/openapi.json
@@ -23544,7 +23544,7 @@
"$ref": "#/definitions/com.github.openshift.api.config.v1.VSpherePlatformNodeNetworking"
},
"vcenters": {
- "description": "vcenters holds the connection details for services to communicate with vCenter. Currently, only a single vCenter is supported, but in tech preview 3 vCenters are supported. Once the cluster has been installed, you are unable to change the current number of defined vCenters except in the case where the cluster has been upgraded from a version of OpenShift where the vsphere platform spec was not present. You may make modifications to the existing vCenters that are defined in the vcenters list in order to match with any added or modified failure domains.",
+ "description": "vcenters holds the connection details for services to communicate with vCenter. Up to 3 vCenters are supported. Once the cluster has been installed, you are unable to change the current number of defined vCenters except when 1.) the cluster has been upgraded from a version of OpenShift where the vsphere platform spec was not present or 2.) in TechPreview you are able to add and remove vCenters but may not remove all vCenters. You may make modifications to the existing vCenters that are defined in the vcenters list in order to match with any added or modified failure domains.",
"type": "array",
"items": {
"default": {},
@@ -46737,6 +46737,10 @@
"type": "string",
"default": ""
},
+ "nodeUID": {
+ "description": "nodeUID is the UID of the node. This field is used to detect that a node has been deleted and recreated with the same name. When the UID changes, it indicates the node is a new instance and the status should be reset.",
+ "type": "string"
+ },
"targetRevision": {
"description": "targetRevision is the generation of the deployment we're trying to apply. Can not be set on creation of a nodeStatus.",
"type": "integer",
diff --git a/vendor/github.com/openshift/api/operator/v1/types.go b/vendor/github.com/openshift/api/operator/v1/types.go
index 3a2141abb..5e4e49daf 100644
--- a/vendor/github.com/openshift/api/operator/v1/types.go
+++ b/vendor/github.com/openshift/api/operator/v1/types.go
@@ -3,6 +3,7 @@ package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
)
// MyOperatorResource is an example operator configuration type
@@ -266,6 +267,12 @@ type NodeStatus struct {
// +required
NodeName string `json:"nodeName"`
+ // nodeUID is the UID of the node.
+ // This field is used to detect that a node has been deleted and recreated with the same name.
+ // When the UID changes, it indicates the node is a new instance and the status should be reset.
+ // +optional
+ NodeUID types.UID `json:"nodeUID,omitempty"`
+
// currentRevision is the generation of the most recently successful deployment.
// Can not be set on creation of a nodeStatus. Updates must only increase the value.
// +kubebuilder:validation:XValidation:rule="self >= oldSelf",message="must only increase"
diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go
index c3ed72602..262d2dd88 100644
--- a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go
+++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go
@@ -37,6 +37,7 @@ func (MyOperatorResource) SwaggerDoc() map[string]string {
var map_NodeStatus = map[string]string{
"": "NodeStatus provides information about the current state of a particular node managed by this operator.",
"nodeName": "nodeName is the name of the node",
+ "nodeUID": "nodeUID is the UID of the node. This field is used to detect that a node has been deleted and recreated with the same name. When the UID changes, it indicates the node is a new instance and the status should be reset.",
"currentRevision": "currentRevision is the generation of the most recently successful deployment. Can not be set on creation of a nodeStatus. Updates must only increase the value.",
"targetRevision": "targetRevision is the generation of the deployment we're trying to apply. Can not be set on creation of a nodeStatus.",
"lastFailedRevision": "lastFailedRevision is the generation of the deployment we tried and failed to deploy.",
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3a37835e4..66a3fdfd9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -58,7 +58,7 @@ github.com/modern-go/reflect2
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
## explicit
github.com/munnerz/goautoneg
-# github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9
+# github.com/openshift/api v0.0.0-20260429122012-1180c0f5c3e9 => github.com/bhperry/openshift-api v0.0.0-20260430171308-07f1fbedc28f
## explicit; go 1.25.0
github.com/openshift/api
github.com/openshift/api/apiextensions
@@ -533,3 +533,4 @@ sigs.k8s.io/structured-merge-diff/v6/value
# sigs.k8s.io/yaml v1.6.0
## explicit; go 1.22
sigs.k8s.io/yaml
+# github.com/openshift/api => github.com/bhperry/openshift-api v0.0.0-20260430171308-07f1fbedc28f