Skip to content

Commit 6a842b0

Browse files
committed
Add AWS SpotMarketOptions support to ROSA HCP MachinePools (ROSAENG-65782)
Adds AWS Spot instance support to ROSA HCP MachinePools via the CAPA layer, mapping a new optional, immutable spec.spotMarketOptions field to the OCM AwsNodePool.spot_market_options API: - spotMarketOptions: {} -> Spot with no maximum price - spotMarketOptions: { maxPrice: "0.05" } -> cap the hourly bid Behavior and guardrails: - Day-1 only / immutable: cannot be added, removed, or changed after the MachinePool is created. Enforced by the validating webhook and ignored in the reconcile diff so it never triggers a spurious Day-2 update. - Requires OpenShift >= 4.22, gated in the controller against the control-plane version (the webhook cannot see the control-plane version). The gate runs even when spec.version is omitted (the common inherit-from-control-plane case). - Incompatible with capacityReservationID; setting both is rejected. Robust version gating: - Uses semver.ParseTolerant so "4.22" and "v4.22.0" are accepted; unparsable or empty versions surface a user-visible Status.FailureMessage instead of an error that requeues forever. - Compares on the {Major, Minor, Patch} triple, so pre-release control-plane versions such as "4.22.0-rc.1" are not wrongly rejected. - Prefers the running control-plane version (Status.Version) over the requested version (Spec.Version), falling back to Spec.Version when Status is unset. - Validation failures set Status.FailureMessage and mark the Ready condition False so they are observable via kubectl. Also corrects the shared SpotMarketOptions MaxPrice kubebuilder marker from lowercase 'pattern' (silently ignored) to 'Pattern', so the numeric validation pattern is now emitted into all CRDs that embed the shared type. Bumps ocm-sdk-go to v0.1.510 / ocm-api-model to v0.0.465 for the new spot builder. Includes webhook, controller, and helper unit tests (immutability, capacity reservation conflict, OCM round-trip, and the full version-gate matrix) and a ROSA MachinePools docs section.
1 parent 67de5c2 commit 6a842b0

20 files changed

Lines changed: 879 additions & 11 deletions

api/v1beta2/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ var (
563563
type SpotMarketOptions struct {
564564
// MaxPrice defines the maximum price the user is willing to pay for Spot VM instances
565565
// +optional
566-
// +kubebuilder:validation:pattern="^[0-9]+(\.[0-9]+)?$"
566+
// +kubebuilder:validation:Pattern=`^[0-9]+(\.[0-9]+)?$`
567567
MaxPrice *string `json:"maxPrice,omitempty"`
568568
}
569569

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,7 @@ spec:
15911591
maxPrice:
15921592
description: MaxPrice defines the maximum price the user is
15931593
willing to pay for Spot VM instances
1594+
pattern: ^[0-9]+(\.[0-9]+)?$
15941595
type: string
15951596
type: object
15961597
sshKeyName:
@@ -4107,6 +4108,7 @@ spec:
41074108
maxPrice:
41084109
description: MaxPrice defines the maximum price the user is
41094110
willing to pay for Spot VM instances
4111+
pattern: ^[0-9]+(\.[0-9]+)?$
41104112
type: string
41114113
type: object
41124114
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2627,6 +2627,7 @@ spec:
26272627
maxPrice:
26282628
description: MaxPrice defines the maximum price the user is
26292629
willing to pay for Spot VM instances
2630+
pattern: ^[0-9]+(\.[0-9]+)?$
26302631
type: string
26312632
type: object
26322633
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ spec:
222222
maxPrice:
223223
description: MaxPrice defines the maximum price the user is
224224
willing to pay for Spot VM instances
225+
pattern: ^[0-9]+(\.[0-9]+)?$
225226
type: string
226227
type: object
227228
sshKeyName:
@@ -898,6 +899,7 @@ spec:
898899
maxPrice:
899900
description: MaxPrice defines the maximum price the user is
900901
willing to pay for Spot VM instances
902+
pattern: ^[0-9]+(\.[0-9]+)?$
901903
type: string
902904
type: object
903905
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,7 @@ spec:
11741174
maxPrice:
11751175
description: MaxPrice defines the maximum price the user is willing
11761176
to pay for Spot VM instances
1177+
pattern: ^[0-9]+(\.[0-9]+)?$
11771178
type: string
11781179
type: object
11791180
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,7 @@ spec:
10981098
maxPrice:
10991099
description: MaxPrice defines the maximum price the user
11001100
is willing to pay for Spot VM instances
1101+
pattern: ^[0-9]+(\.[0-9]+)?$
11011102
type: string
11021103
type: object
11031104
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ spec:
231231
maxPrice:
232232
description: MaxPrice defines the maximum price the user is
233233
willing to pay for Spot VM instances
234+
pattern: ^[0-9]+(\.[0-9]+)?$
234235
type: string
235236
type: object
236237
sshKeyName:
@@ -907,6 +908,7 @@ spec:
907908
maxPrice:
908909
description: MaxPrice defines the maximum price the user is
909910
willing to pay for Spot VM instances
911+
pattern: ^[0-9]+(\.[0-9]+)?$
910912
type: string
911913
type: object
912914
sshKeyName:

config/crd/bases/infrastructure.cluster.x-k8s.io_rosamachinepools.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ spec:
134134
items:
135135
type: string
136136
type: array
137+
spotMarketOptions:
138+
description: |-
139+
SpotMarketOptions configures the node pool to use AWS Spot instances.
140+
Providing an empty struct ({}) requests Spot with no max price.
141+
Providing MaxPrice limits the bid to that amount per hour.
142+
Incompatible with CapacityReservationID.
143+
Requires minimum OCP version 4.22.
144+
properties:
145+
maxPrice:
146+
description: MaxPrice defines the maximum price the user is willing
147+
to pay for Spot VM instances
148+
pattern: ^[0-9]+(\.[0-9]+)?$
149+
type: string
150+
type: object
137151
subnet:
138152
type: string
139153
x-kubernetes-validations:

docs/book/src/topics/rosa/creating-rosa-machinepools.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,42 @@ spec:
4747
```
4848
4949
see [ROSAMachinePool CRD Reference](https://cluster-api-aws.sigs.k8s.io/crd/#infrastructure.cluster.x-k8s.io/v1beta2.ROSAMachinePool) for all possible configurations.
50+
51+
## Spot instances
52+
53+
A ROSA MachinePool can be backed by [AWS Spot instances](../spot-instances.md) by setting the `spotMarketOptions` field. Provide an empty struct (`{}`) to request Spot instances with no maximum price, or set `maxPrice` to cap the hourly bid.
54+
55+
```yaml
56+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
57+
kind: ROSAMachinePool
58+
metadata:
59+
name: "${CLUSTER_NAME}-pool-spot"
60+
spec:
61+
nodePoolName: "nodepool-spot"
62+
instanceType: "m5.xlarge"
63+
subnet: "${PRIVATE_SUBNET_ID}"
64+
version: "${OPENSHIFT_VERSION}"
65+
# Request Spot instances with no maximum price.
66+
spotMarketOptions: {}
67+
```
68+
69+
```yaml
70+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
71+
kind: ROSAMachinePool
72+
metadata:
73+
name: "${CLUSTER_NAME}-pool-spot"
74+
spec:
75+
nodePoolName: "nodepool-spot"
76+
instanceType: "m5.xlarge"
77+
subnet: "${PRIVATE_SUBNET_ID}"
78+
version: "${OPENSHIFT_VERSION}"
79+
spotMarketOptions:
80+
# Maximum hourly price you are willing to pay for a Spot instance.
81+
maxPrice: "0.05"
82+
```
83+
84+
Notes:
85+
86+
- `spotMarketOptions` is a Day-1 only setting and is **immutable**; it cannot be added, removed, or changed after the MachinePool is created.
87+
- It is incompatible with `capacityReservationID`; setting both is rejected by the validating webhook.
88+
- It requires an OpenShift version `>= 4.22`.

exp/api/v1beta2/rosamachinepool_types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ type RosaMachinePoolSpec struct {
132132
//
133133
// +optional
134134
CapacityReservationID string `json:"capacityReservationID,omitempty"`
135+
136+
// SpotMarketOptions configures the node pool to use AWS Spot instances.
137+
// Providing an empty struct ({}) requests Spot with no max price.
138+
// Providing MaxPrice limits the bid to that amount per hour.
139+
// Incompatible with CapacityReservationID.
140+
// Requires minimum OCP version 4.22.
141+
// +immutable
142+
// +optional
143+
SpotMarketOptions *infrav1.SpotMarketOptions `json:"spotMarketOptions,omitempty"`
135144
}
136145

137146
// RosaTaint represents a taint to be applied to a node.

0 commit comments

Comments
 (0)