diff --git a/go.mod b/go.mod index 0a6e5f72d..10163a25b 100644 --- a/go.mod +++ b/go.mod @@ -369,3 +369,6 @@ require ( sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect ) + +// go get github.com/vr4manta/api@SPLAT-2206 +replace github.com/openshift/api => github.com/vr4manta/api v0.0.0-20250929154722-9355a7602b96 diff --git a/go.sum b/go.sum index e3944b9e7..47d5d537b 100644 --- a/go.sum +++ b/go.sum @@ -457,8 +457,6 @@ github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jD github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/openshift-eng/openshift-tests-extension v0.0.0-20250711173707-dc2a20e5a5f8 h1:D+Qga9nujuIcrAjcAuKPukoUcVBl6ZDEbtgNLgKKlgY= github.com/openshift-eng/openshift-tests-extension v0.0.0-20250711173707-dc2a20e5a5f8/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M= -github.com/openshift/api v0.0.0-20250901120840-a638ff2e96fb h1:L5A3091VKSyOJb0nJto/pQyyHueoaW+4sXLO5fHrTBE= -github.com/openshift/api v0.0.0-20250901120840-a638ff2e96fb/go.mod h1:SPLf21TYPipzCO67BURkCfK6dcIIxx0oNRVWaOyRcXM= github.com/openshift/client-go v0.0.0-20250710075018-396b36f983ee h1:tOtrrxfDEW8hK3eEsHqxsXurq/D6LcINGfprkQC3hqY= github.com/openshift/client-go v0.0.0-20250710075018-396b36f983ee/go.mod h1:zhRiYyNMk89llof2qEuGPWPD+joQPhCRUc2IK0SB510= github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250718085303-e712b1ebf374 h1:ldUi0e64kdYJC2+ucB24GRXIXfMnI3NpSkcnalPqBGo= @@ -625,6 +623,8 @@ github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U= github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= github.com/vmware/govmomi v0.46.3 h1:zBn42Rl0WZBFhGao8Dy0MFRkbE4YNPqOu0OBd+ww6VM= github.com/vmware/govmomi v0.46.3/go.mod h1:uoLVU9zlXC4p4GmLVG+ZJmBC0Gn3Q7mytOJvi39OhxA= +github.com/vr4manta/api v0.0.0-20250929154722-9355a7602b96 h1:B1sDjz+OYr4DLrz2GpiC3o8+l//3V5XbdnXauKhD+6M= +github.com/vr4manta/api v0.0.0-20250929154722-9355a7602b96/go.mod h1:SPLf21TYPipzCO67BURkCfK6dcIIxx0oNRVWaOyRcXM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= diff --git a/pkg/operator/operator_test.go b/pkg/operator/operator_test.go index c6e28b72e..ea6649598 100644 --- a/pkg/operator/operator_test.go +++ b/pkg/operator/operator_test.go @@ -45,13 +45,15 @@ var ( {Name: apifeatures.FeatureGateAzureWorkloadIdentity}, {Name: apifeatures.FeatureGateVSphereMultiDisk}, {Name: apifeatures.FeatureGateVSphereHostVMGroupZonal}, + {Name: apifeatures.FeatureGateAWSDedicatedHosts}, } enabledFeatureMap = map[string]bool{ - "MachineAPIMigration": true, - "AzureWorkloadIdentity": true, - "VSphereMultiDisk": true, - "VSphereHostVMGroupZonal": true, + "MachineAPIMigration": true, + "AzureWorkloadIdentity": true, + "VSphereMultiDisk": true, + "VSphereHostVMGroupZonal": true, + "FeatureGateAWSDedicatedHosts": true, } ) diff --git a/pkg/webhooks/machine_webhook.go b/pkg/webhooks/machine_webhook.go index 4b04ed283..fed940665 100644 --- a/pkg/webhooks/machine_webhook.go +++ b/pkg/webhooks/machine_webhook.go @@ -868,6 +868,13 @@ func validateAWS(m *machinev1beta1.Machine, config *admissionConfig) (bool, []st ) } + // Check if host affinity is set. If so, we expect a Host ID to be set + if providerSpec.HostAffinity != nil { + if providerSpec.HostID == nil || len(*providerSpec.HostID) == 0 { + errs = append(errs, field.Required(field.NewPath("spec.hostID"), "hostID must be set when hostAffinity is configured")) + } + } + if len(errs) > 0 { return false, warnings, errs } diff --git a/pkg/webhooks/machine_webhook_test.go b/pkg/webhooks/machine_webhook_test.go index 4a4b44413..4f836e59c 100644 --- a/pkg/webhooks/machine_webhook_test.go +++ b/pkg/webhooks/machine_webhook_test.go @@ -316,6 +316,67 @@ func TestMachineCreation(t *testing.T) { }, expectedError: "", }, + { + name: "configure host affinity with Host ID", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1beta1.AWSMachineProviderConfig{ + AMI: machinev1beta1.AWSResourceReference{ + ID: ptr.To[string]("ami"), + }, + InstanceType: "test", + HostAffinity: ptr.To(machinev1beta1.HostAffinityAnyAvailable), + HostID: ptr.To("h-09dcf61cb388b0149"), + }, + }, + expectedError: "", + }, + { + name: "configure host affinity with invalid affinity", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1beta1.AWSMachineProviderConfig{ + AMI: machinev1beta1.AWSResourceReference{ + ID: ptr.To[string]("ami"), + }, + InstanceType: "test", + HostAffinity: ptr.To(machinev1beta1.HostAffinity("invalid")), + }, + }, + expectedError: "admission webhook \"validation.machine.machine.openshift.io\" denied the request: spec.hostID: Required value: hostID must be set when hostAffinity is configured", // true + }, + { + name: "configure host affinity without Host ID", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1beta1.AWSMachineProviderConfig{ + AMI: machinev1beta1.AWSResourceReference{ + ID: ptr.To[string]("ami"), + }, + InstanceType: "test", + HostAffinity: ptr.To(machinev1beta1.HostAffinityHost), + }, + }, + expectedError: "admission webhook \"validation.machine.machine.openshift.io\" denied the request: spec.hostID: Required value: hostID must be set when hostAffinity is configured", // true + }, + { + name: "hostID alone is valid", + platformType: osconfigv1.AWSPlatformType, + clusterID: "aws-cluster", + providerSpecValue: &kruntime.RawExtension{ + Object: &machinev1beta1.AWSMachineProviderConfig{ + AMI: machinev1beta1.AWSResourceReference{ + ID: ptr.To[string]("ami"), + }, + InstanceType: "test", + HostID: ptr.To("h-1234567890abcdef0"), + }, + }, + expectedError: "", + }, { name: "with Azure and a nil provider spec value", platformType: osconfigv1.AzurePlatformType, diff --git a/vendor/github.com/openshift/api/features.md b/vendor/github.com/openshift/api/features.md index 35ba08c39..2a52e28ea 100644 --- a/vendor/github.com/openshift/api/features.md +++ b/vendor/github.com/openshift/api/features.md @@ -18,10 +18,12 @@ | AWSClusterHostedDNS| | | Enabled | Enabled | Enabled | Enabled | | AWSClusterHostedDNSInstall| | | Enabled | Enabled | Enabled | Enabled | | AWSDedicatedHosts| | | Enabled | Enabled | Enabled | Enabled | +| AWSDualStackInstall| | | Enabled | Enabled | Enabled | Enabled | | AWSServiceLBNetworkSecurityGroup| | | Enabled | Enabled | Enabled | Enabled | | AutomatedEtcdBackup| | | Enabled | Enabled | Enabled | Enabled | | AzureClusterHostedDNSInstall| | | Enabled | Enabled | Enabled | Enabled | | AzureDedicatedHosts| | | Enabled | Enabled | Enabled | Enabled | +| AzureDualStackInstall| | | Enabled | Enabled | Enabled | Enabled | | AzureMultiDisk| | | Enabled | Enabled | Enabled | Enabled | | BootcNodeManagement| | | Enabled | Enabled | Enabled | Enabled | | ClusterAPIInstallIBMCloud| | | Enabled | Enabled | Enabled | Enabled | @@ -38,6 +40,7 @@ | GCPClusterHostedDNSInstall| | | Enabled | Enabled | Enabled | Enabled | | GCPCustomAPIEndpoints| | | Enabled | Enabled | Enabled | Enabled | | GCPCustomAPIEndpointsInstall| | | Enabled | Enabled | Enabled | Enabled | +| GCPDualStackInstall| | | Enabled | Enabled | Enabled | Enabled | | ImageModeStatusReporting| | | Enabled | Enabled | Enabled | Enabled | | ImageStreamImportMode| | | Enabled | Enabled | Enabled | Enabled | | IngressControllerDynamicConfigurationManager| | | Enabled | Enabled | Enabled | Enabled | diff --git a/vendor/github.com/openshift/api/features/features.go b/vendor/github.com/openshift/api/features/features.go index 711dd25f2..883315a44 100644 --- a/vendor/github.com/openshift/api/features/features.go +++ b/vendor/github.com/openshift/api/features/features.go @@ -92,9 +92,11 @@ var ( enableIn(configv1.Default, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() + // OpenShift and Node Team will keep this turned off until evictions and + // disk provisioning are fixed even though upstream will take this GA. FeatureGateNodeSwap = newFeatureGate("NodeSwap"). reportProblemsToJiraComponent("node"). - contactPerson("ehashman"). + contactPerson("haircommander"). productScope(kubernetes). enhancementPR("https://github.com/kubernetes/enhancements/issues/2400"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). @@ -770,8 +772,8 @@ var ( mustRegister() FeatureGateAWSDedicatedHosts = newFeatureGate("AWSDedicatedHosts"). - reportProblemsToJiraComponent("Installer"). - contactPerson("faermanj"). + reportProblemsToJiraComponent("splat"). + contactPerson("rvanderp3"). productScope(ocpSpecific). enhancementPR("https://github.com/openshift/enhancements/pull/1781"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). @@ -848,4 +850,27 @@ var ( enhancementPR("https://github.com/openshift/enhancements/pull/1785"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). mustRegister() + FeatureGateAWSDualStackInstall = newFeatureGate("AWSDualStackInstall"). + reportProblemsToJiraComponent("Installer"). + contactPerson("sadasu"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1806"). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + mustRegister() + + FeatureGateAzureDualStackInstall = newFeatureGate("AzureDualStackInstall"). + reportProblemsToJiraComponent("Installer"). + contactPerson("jhixson74"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1806"). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + mustRegister() + + FeatureGateGCPDualStackInstall = newFeatureGate("GCPDualStackInstall"). + reportProblemsToJiraComponent("Installer"). + contactPerson("barbacbd"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1806"). + enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + mustRegister() ) diff --git a/vendor/github.com/openshift/api/machine/v1beta1/types_awsprovider.go b/vendor/github.com/openshift/api/machine/v1beta1/types_awsprovider.go index db15df2cc..241a0b588 100644 --- a/vendor/github.com/openshift/api/machine/v1beta1/types_awsprovider.go +++ b/vendor/github.com/openshift/api/machine/v1beta1/types_awsprovider.go @@ -107,6 +107,27 @@ type AWSMachineProviderConfig struct { // If this value is selected, capacityReservationID must be specified to identify the target reservation. // +optional MarketType MarketType `json:"marketType,omitempty"` + + // hostID specifies the Dedicated Host on which the instance must be started. + // This field is mutually exclusive with DynamicHostAllocation. + // When set, the value must be a valid AWS Dedicated Host ID in the form + // "h-" followed by 17 lowercase hexadecimal characters. + // The maximum length is 19 characters, and the field may be omitted. + // +kubebuilder:validation:XValidation:rule="self == null || self.matches('^h-[0-9a-f]{17}$')",message="hostID must match ^h-[0-9a-f]{17}$" + // +kubebuilder:validation:MaxLength=19 + // +openshift:enable:FeatureGate=AWSDedicatedHosts + // +optional + HostID *string `json:"hostID,omitempty"` + + // hostAffinity specifies the dedicated host affinity setting for the instance. + // Valid values are "AnyAvailable", "Host", and omitted. + // When HostAffinity is set to "Host", an instance started onto a specific host always restarts on the same host if stopped. + // When HostAffinity is set to "AnyAvailable", and you stop and restart the instance, it can be restarted on any available host. + // When HostAffinity is omitted and HostID is defined, the instance is started onto the specified host. + // When HostAffinity is defined, HostID is required. + // +openshift:enable:FeatureGate=AWSDedicatedHosts + // +optional + HostAffinity *HostAffinity `json:"hostAffinity,omitempty"` } // BlockDeviceMappingSpec describes a block device mapping @@ -355,3 +376,16 @@ const ( // When set to CapacityBlock the instance utilizes pre-purchased compute capacity (capacity blocks) with AWS Capacity Reservations. MarketTypeCapacityBlock MarketType = "CapacityBlock" ) + +// HostAffinity describes the host affinity of an EC2 Instance +type HostAffinity string + +const ( + // HostAffinityAnyAvailable is a HostAffinity enum value + // When set to AnyAvailable the instance is put on a host using the AWS default logic. + HostAffinityAnyAvailable HostAffinity = "AnyAvailable" + + // HostAffinityHost is a HostAffinity enum value + // When set to host the instance runs on the specified host. + HostAffinityHost HostAffinity = "Host" +) diff --git a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.deepcopy.go index 7763435a9..26152f768 100644 --- a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.deepcopy.go @@ -80,6 +80,16 @@ func (in *AWSMachineProviderConfig) DeepCopyInto(out *AWSMachineProviderConfig) *out = new(int32) **out = **in } + if in.HostID != nil { + in, out := &in.HostID, &out.HostID + *out = new(string) + **out = **in + } + if in.HostAffinity != nil { + in, out := &in.HostAffinity, &out.HostAffinity + *out = new(HostAffinity) + **out = **in + } return } diff --git a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go index e40d744f6..67a5bf8ca 100644 --- a/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/machine/v1beta1/zz_generated.swagger_doc_generated.go @@ -34,6 +34,8 @@ var map_AWSMachineProviderConfig = map[string]string{ "placementGroupPartition": "placementGroupPartition is the partition number within the placement group in which to launch the instance. This must be an integer value between 1 and 7. It is only valid if the placement group, referred in `PlacementGroupName` was created with strategy set to partition.", "capacityReservationId": "capacityReservationId specifies the target Capacity Reservation into which the instance should be launched. The field size should be greater than 0 and the field input must start with cr-***", "marketType": "marketType specifies the type of market for the EC2 instance. Valid values are OnDemand, Spot, CapacityBlock and omitted.\n\nDefaults to OnDemand. When SpotMarketOptions is provided, the marketType defaults to \"Spot\".\n\nWhen set to OnDemand the instance runs as a standard OnDemand instance. When set to Spot the instance runs as a Spot instance. When set to CapacityBlock the instance utilizes pre-purchased compute capacity (capacity blocks) with AWS Capacity Reservations. If this value is selected, capacityReservationID must be specified to identify the target reservation.", + "hostID": "hostID specifies the Dedicated Host on which the instance must be started. This field is mutually exclusive with DynamicHostAllocation. When set, the value must be a valid AWS Dedicated Host ID in the form \"h-\" followed by 17 lowercase hexadecimal characters. The maximum length is 19 characters, and the field may be omitted.", + "hostAffinity": "hostAffinity specifies the dedicated host affinity setting for the instance. Valid values are \"AnyAvailable\", \"Host\", and omitted. When HostAffinity is set to \"Host\", an instance started onto a specific host always restarts on the same host if stopped. When HostAffinity is set to \"AnyAvailable\", and you stop and restart the instance, it can be restarted on any available host. When HostAffinity is omitted and HostID is defined, the instance is started onto the specified host. When HostAffinity is defined, HostID is required.", } func (AWSMachineProviderConfig) SwaggerDoc() map[string]string { diff --git a/vendor/modules.txt b/vendor/modules.txt index 73942bad0..8a57b5fc2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -995,7 +995,7 @@ github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo github.com/openshift-eng/openshift-tests-extension/pkg/junit github.com/openshift-eng/openshift-tests-extension/pkg/util/sets github.com/openshift-eng/openshift-tests-extension/pkg/version -# github.com/openshift/api v0.0.0-20250901120840-a638ff2e96fb +# github.com/openshift/api v0.0.0-20250901120840-a638ff2e96fb => github.com/vr4manta/api v0.0.0-20250929154722-9355a7602b96 ## explicit; go 1.24.0 github.com/openshift/api github.com/openshift/api/annotations @@ -3649,3 +3649,4 @@ sigs.k8s.io/yaml/goyaml.v3 # k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250716113245-b94367cabf3e # k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250716113245-b94367cabf3e # k8s.io/kubernetes => github.com/openshift/kubernetes v1.30.1-0.20250716113245-b94367cabf3e +# github.com/openshift/api => github.com/vr4manta/api v0.0.0-20250929154722-9355a7602b96