Skip to content

Commit 3cfa2a8

Browse files
authored
Merge pull request #4764 from muraee/rosa-machinepool-version
✨ ROSA: Reconcile ROSAMachinePool version
2 parents 2a030a7 + d5c8ce7 commit 3cfa2a8

18 files changed

+552
-32
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ spec:
287287
type: string
288288
version:
289289
description: Openshift version, for example "4.14.5".
290-
pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
291290
type: string
292291
workerRoleARN:
293292
type: string
@@ -362,8 +361,13 @@ spec:
362361
AKS, EKS, GKE, etc.
363362
type: boolean
364363
failureMessage:
365-
description: ErrorMessage indicates that there is a terminal problem
366-
reconciling the state, and will be set to a descriptive error message.
364+
description: "FailureMessage will be set in the event that there is
365+
a terminal problem reconciling the state and will be set to a descriptive
366+
error message. \n This field should not be set for transitive errors
367+
that a controller faces that are expected to be fixed automatically
368+
over time (like service outages), but instead indicate that something
369+
is fundamentally wrong with the spec or the configuration of the
370+
controller, and that manual intervention is required."
367371
type: string
368372
id:
369373
description: ID is the cluster ID given by ROSA.

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ spec:
9494
type: array
9595
subnet:
9696
type: string
97+
version:
98+
description: Version specifies the penshift version of the nodes associated
99+
with this machinepool. ROSAControlPlane version is used if not set.
100+
type: string
97101
required:
98102
- nodePoolName
99103
type: object
@@ -146,6 +150,15 @@ spec:
146150
- type
147151
type: object
148152
type: array
153+
failureMessage:
154+
description: "FailureMessage will be set in the event that there is
155+
a terminal problem reconciling the state and will be set to a descriptive
156+
error message. \n This field should not be set for transitive errors
157+
that a controller faces that are expected to be fixed automatically
158+
over time (like service outages), but instead indicate that something
159+
is fundamentally wrong with the spec or the configuration of the
160+
controller, and that manual intervention is required."
161+
type: string
149162
id:
150163
description: ID is the ID given by ROSA.
151164
type: string

config/rbac/role.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ rules:
401401
- apiGroups:
402402
- infrastructure.cluster.x-k8s.io
403403
resources:
404-
- rosamachinenepools
404+
- rosamachinepools
405405
verbs:
406406
- delete
407407
- get
@@ -412,7 +412,7 @@ rules:
412412
- apiGroups:
413413
- infrastructure.cluster.x-k8s.io
414414
resources:
415-
- rosamachinenepools/status
415+
- rosamachinepools/status
416416
verbs:
417417
- get
418418
- patch

config/webhook/manifests.yaml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,28 @@ webhooks:
201201
resources:
202202
- awsmanagedmachinepools
203203
sideEffects: None
204+
- admissionReviewVersions:
205+
- v1
206+
- v1beta1
207+
clientConfig:
208+
service:
209+
name: webhook-service
210+
namespace: system
211+
path: /mutate-infrastructure-cluster-x-k8s-io-v1beta2-rosamachinepool
212+
failurePolicy: Fail
213+
matchPolicy: Equivalent
214+
name: default.rosamachinepool.infrastructure.cluster.x-k8s.io
215+
rules:
216+
- apiGroups:
217+
- infrastructure.cluster.x-k8s.io
218+
apiVersions:
219+
- v1beta2
220+
operations:
221+
- CREATE
222+
- UPDATE
223+
resources:
224+
- rosamachinepools
225+
sideEffects: None
204226
- admissionReviewVersions:
205227
- v1
206228
- v1beta1
@@ -267,6 +289,28 @@ webhooks:
267289
resources:
268290
- awsmanagedcontrolplanes
269291
sideEffects: None
292+
- admissionReviewVersions:
293+
- v1
294+
- v1beta1
295+
clientConfig:
296+
service:
297+
name: webhook-service
298+
namespace: system
299+
path: /mutate-controlplane-cluster-x-k8s-io-v1beta2-rosacontrolplane
300+
failurePolicy: Fail
301+
matchPolicy: Equivalent
302+
name: default.rosacontrolplanes.controlplane.cluster.x-k8s.io
303+
rules:
304+
- apiGroups:
305+
- controlplane.cluster.x-k8s.io
306+
apiVersions:
307+
- v1beta2
308+
operations:
309+
- CREATE
310+
- UPDATE
311+
resources:
312+
- rosacontrolplanes
313+
sideEffects: None
270314
---
271315
apiVersion: admissionregistration.k8s.io/v1
272316
kind: ValidatingWebhookConfiguration
@@ -493,6 +537,28 @@ webhooks:
493537
resources:
494538
- awsmanagedmachinepools
495539
sideEffects: None
540+
- admissionReviewVersions:
541+
- v1
542+
- v1beta1
543+
clientConfig:
544+
service:
545+
name: webhook-service
546+
namespace: system
547+
path: /validate-infrastructure-cluster-x-k8s-io-v1beta2-rosamachinepool
548+
failurePolicy: Fail
549+
matchPolicy: Equivalent
550+
name: validation.rosamachinepool.infrastructure.cluster.x-k8s.io
551+
rules:
552+
- apiGroups:
553+
- infrastructure.cluster.x-k8s.io
554+
apiVersions:
555+
- v1beta2
556+
operations:
557+
- CREATE
558+
- UPDATE
559+
resources:
560+
- rosamachinepools
561+
sideEffects: None
496562
- admissionReviewVersions:
497563
- v1
498564
- v1beta1
@@ -559,3 +625,25 @@ webhooks:
559625
resources:
560626
- awsmanagedcontrolplanes
561627
sideEffects: None
628+
- admissionReviewVersions:
629+
- v1
630+
- v1beta1
631+
clientConfig:
632+
service:
633+
name: webhook-service
634+
namespace: system
635+
path: /validate-controlplane-cluster-x-k8s-io-v1beta2-rosacontrolplane
636+
failurePolicy: Fail
637+
matchPolicy: Equivalent
638+
name: validation.rosacontrolplanes.controlplane.cluster.x-k8s.io
639+
rules:
640+
- apiGroups:
641+
- controlplane.cluster.x-k8s.io
642+
apiVersions:
643+
- v1beta2
644+
operations:
645+
- CREATE
646+
- UPDATE
647+
resources:
648+
- rosacontrolplanes
649+
sideEffects: None

controlplane/rosa/api/v1beta2/rosacontrolplane_types.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ type RosaControlPlaneSpec struct { //nolint: maligned
5050
Region *string `json:"region"`
5151

5252
// Openshift version, for example "4.14.5".
53-
//
54-
// +kubebuilder:validation:Pattern:=`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`
5553
Version string `json:"version"`
5654

5755
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
@@ -473,8 +471,15 @@ type RosaControlPlaneStatus struct {
473471
// Ready denotes that the ROSAControlPlane API Server is ready to receive requests.
474472
// +kubebuilder:default=false
475473
Ready bool `json:"ready"`
476-
// ErrorMessage indicates that there is a terminal problem reconciling the
477-
// state, and will be set to a descriptive error message.
474+
// FailureMessage will be set in the event that there is a terminal problem
475+
// reconciling the state and will be set to a descriptive error message.
476+
//
477+
// This field should not be set for transitive errors that a controller
478+
// faces that are expected to be fixed automatically over
479+
// time (like service outages), but instead indicate that something is
480+
// fundamentally wrong with the spec or the configuration of
481+
// the controller, and that manual intervention is required.
482+
//
478483
// +optional
479484
FailureMessage *string `json:"failureMessage,omitempty"`
480485
// Conditions specifies the cpnditions for the managed control plane
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package v1beta2
2+
3+
import (
4+
"github.com/blang/semver"
5+
apierrors "k8s.io/apimachinery/pkg/api/errors"
6+
runtime "k8s.io/apimachinery/pkg/runtime"
7+
"k8s.io/apimachinery/pkg/util/validation/field"
8+
ctrl "sigs.k8s.io/controller-runtime"
9+
"sigs.k8s.io/controller-runtime/pkg/webhook"
10+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
11+
)
12+
13+
// SetupWebhookWithManager will setup the webhooks for the ROSAControlPlane.
14+
func (r *ROSAControlPlane) SetupWebhookWithManager(mgr ctrl.Manager) error {
15+
return ctrl.NewWebhookManagedBy(mgr).
16+
For(r).
17+
Complete()
18+
}
19+
20+
// +kubebuilder:webhook:verbs=create;update,path=/validate-controlplane-cluster-x-k8s-io-v1beta2-rosacontrolplane,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=controlplane.cluster.x-k8s.io,resources=rosacontrolplanes,versions=v1beta2,name=validation.rosacontrolplanes.controlplane.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
21+
// +kubebuilder:webhook:verbs=create;update,path=/mutate-controlplane-cluster-x-k8s-io-v1beta2-rosacontrolplane,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=controlplane.cluster.x-k8s.io,resources=rosacontrolplanes,versions=v1beta2,name=default.rosacontrolplanes.controlplane.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
22+
23+
var _ webhook.Defaulter = &ROSAControlPlane{}
24+
var _ webhook.Validator = &ROSAControlPlane{}
25+
26+
// ValidateCreate implements admission.Validator.
27+
func (r *ROSAControlPlane) ValidateCreate() (warnings admission.Warnings, err error) {
28+
var allErrs field.ErrorList
29+
30+
if err := r.validateVersion(); err != nil {
31+
allErrs = append(allErrs, err)
32+
}
33+
34+
if len(allErrs) == 0 {
35+
return nil, nil
36+
}
37+
38+
return nil, apierrors.NewInvalid(
39+
r.GroupVersionKind().GroupKind(),
40+
r.Name,
41+
allErrs,
42+
)
43+
}
44+
45+
// ValidateUpdate implements admission.Validator.
46+
func (r *ROSAControlPlane) ValidateUpdate(old runtime.Object) (warnings admission.Warnings, err error) {
47+
var allErrs field.ErrorList
48+
49+
if err := r.validateVersion(); err != nil {
50+
allErrs = append(allErrs, err)
51+
}
52+
53+
if len(allErrs) == 0 {
54+
return nil, nil
55+
}
56+
57+
return nil, apierrors.NewInvalid(
58+
r.GroupVersionKind().GroupKind(),
59+
r.Name,
60+
allErrs,
61+
)
62+
}
63+
64+
// ValidateDelete implements admission.Validator.
65+
func (r *ROSAControlPlane) ValidateDelete() (warnings admission.Warnings, err error) {
66+
return nil, nil
67+
}
68+
69+
func (r *ROSAControlPlane) validateVersion() *field.Error {
70+
_, err := semver.Parse(r.Spec.Version)
71+
if err != nil {
72+
return field.Invalid(field.NewPath("spec.version"), r.Spec.Version, "version must be a valid semantic version")
73+
}
74+
75+
return nil
76+
}
77+
78+
// Default implements admission.Defaulter.
79+
func (r *ROSAControlPlane) Default() {
80+
SetObjectDefaults_ROSAControlPlane(r)
81+
}

controlplane/rosa/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/rosa/controllers/rosacontrolplane_controller.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,16 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
191191
}
192192
defer rosaClient.Close()
193193

194-
isValid, err := validateControlPlaneSpec(rosaClient, rosaScope)
194+
failureMessage, err := validateControlPlaneSpec(rosaClient, rosaScope)
195195
if err != nil {
196196
return ctrl.Result{}, fmt.Errorf("failed to validate ROSAControlPlane.spec: %w", err)
197197
}
198-
if !isValid {
198+
if failureMessage != nil {
199+
rosaScope.ControlPlane.Status.FailureMessage = failureMessage
199200
// dont' requeue because input is invalid and manual intervention is needed.
200201
return ctrl.Result{}, nil
202+
} else {
203+
rosaScope.ControlPlane.Status.FailureMessage = nil
201204
}
202205

203206
cluster, err := rosaClient.GetCluster()
@@ -270,7 +273,7 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
270273
DisableUserWorkloadMonitoring(true).
271274
Version(
272275
cmv1.NewVersion().
273-
ID(fmt.Sprintf("openshift-v%s", rosaScope.ControlPlane.Spec.Version)).
276+
ID(rosa.VersionID(rosaScope.ControlPlane.Spec.Version)).
274277
ChannelGroup("stable"),
275278
).
276279
ExpirationTimestamp(time.Now().Add(1 * time.Hour)).
@@ -411,7 +414,7 @@ func (r *ROSAControlPlaneReconciler) reconcileDelete(ctx context.Context, rosaSc
411414

412415
func (r *ROSAControlPlaneReconciler) reconcileClusterVersion(rosaScope *scope.ROSAControlPlaneScope, rosaClient *rosa.RosaClient, cluster *cmv1.Cluster) error {
413416
version := rosaScope.ControlPlane.Spec.Version
414-
if version == cluster.Version().RawID() {
417+
if version == rosa.RawVersionID(cluster.Version()) {
415418
conditions.MarkFalse(rosaScope.ControlPlane, rosacontrolplanev1.ROSAControlPlaneUpgradingCondition, "upgraded", clusterv1.ConditionSeverityInfo, "")
416419
return nil
417420
}
@@ -560,24 +563,20 @@ func (r *ROSAControlPlaneReconciler) reconcileClusterAdminPassword(ctx context.C
560563
return password, nil
561564
}
562565

563-
func validateControlPlaneSpec(rosaClient *rosa.RosaClient, rosaScope *scope.ROSAControlPlaneScope) (bool, error) {
564-
// reset previous message.
565-
rosaScope.ControlPlane.Status.FailureMessage = nil
566-
566+
func validateControlPlaneSpec(rosaClient *rosa.RosaClient, rosaScope *scope.ROSAControlPlaneScope) (*string, error) {
567567
version := rosaScope.ControlPlane.Spec.Version
568568
isSupported, err := rosaClient.IsVersionSupported(version)
569569
if err != nil {
570-
return false, err
570+
return nil, fmt.Errorf("failed to verify if version is supported: %w", err)
571571
}
572572

573573
if !isSupported {
574574
message := fmt.Sprintf("version %s is not supported", version)
575-
rosaScope.ControlPlane.Status.FailureMessage = &message
576-
return false, nil
575+
return &message, nil
577576
}
578577

579578
// TODO: add more input validations
580-
return true, nil
579+
return nil, nil
581580
}
582581

583582
func (r *ROSAControlPlaneReconciler) rosaClusterToROSAControlPlane(log *logger.Logger) handler.MapFunc {

docs/book/src/topics/rosa/creating-a-cluster.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ CAPA controller requires an API token in order to be able to provision ROSA clus
1111
--from-literal=ocmToken='eyJhbGciOiJIUzI1NiIsI....' \
1212
--from-literal=ocmApiUrl='https://api.openshift.com'
1313
```
14-
14+
1515
Alternatively, you can edit CAPA controller deployment to provide the credentials:
1616
```shell
1717
kubectl edit deployment -n capa-system capa-controller-manager
@@ -36,7 +36,7 @@ Once Step 3 is done, you will be ready to proceed with creating a ROSA cluster u
3636

3737
1. Prepare the environment:
3838
```bash
39-
export OPENSHIFT_VERSION="openshift-v4.14.5"
39+
export OPENSHIFT_VERSION="4.14.5"
4040
export CLUSTER_NAME="capi-rosa-quickstart"
4141
export AWS_REGION="us-west-2"
4242
export AWS_AVAILABILITY_ZONE="us-west-2a"

exp/api/v1beta2/conditions_consts.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ const (
104104
)
105105

106106
const (
107-
// RosaMachinePoolReadyCondition condition reports on the successful reconciliation of rosa control plane.
107+
// RosaMachinePoolReadyCondition condition reports on the successful reconciliation of rosa machinepool.
108108
RosaMachinePoolReadyCondition clusterv1.ConditionType = "RosaMchinePoolReady"
109+
// RosaMachinePoolUpgradingCondition condition reports whether ROSAMachinePool is upgrading or not.
110+
RosaMachinePoolUpgradingCondition clusterv1.ConditionType = "RosaMchinePoolUpgrading"
109111
// WaitingForRosaControlPlaneReason used when the machine pool is waiting for
110112
// ROSA control plane infrastructure to be ready before proceeding.
111113
WaitingForRosaControlPlaneReason = "WaitingForRosaControlPlane"

0 commit comments

Comments
 (0)