Skip to content

Commit b600808

Browse files
committed
Add RoleConfig drift reconciliation
1 parent 6640d97 commit b600808

File tree

7 files changed

+274
-109
lines changed

7 files changed

+274
-109
lines changed

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

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,8 @@ spec:
4848
creating your ROSA cluster.
4949
properties:
5050
path:
51-
description: The arn path for the account/operator roles as well
52-
as their policies.
5351
type: string
5452
permissionsBoundaryARN:
55-
description: The ARN of the policy that is used to set the permissions
56-
boundary for the account roles.
5753
type: string
5854
prefix:
5955
description: User-defined prefix for all generated AWS resources
@@ -82,11 +78,8 @@ spec:
8278
- version
8379
type: object
8480
credentialsSecretRef:
85-
description: |-
86-
CredentialsSecretRef references a secret with necessary credentials to connect to the OCM API.
87-
The secret should contain the following data keys:
88-
- ocmToken: eyJhbGciOiJIUzI1NiIsI....
89-
- ocmApiUrl: Optional, defaults to 'https://api.openshift.com'
81+
description: CredentialsSecretRef references a secret with necessary
82+
credentials to connect to the OCM API.
9083
properties:
9184
name:
9285
default: ""
@@ -366,37 +359,6 @@ spec:
366359
x-kubernetes-list-map-keys:
367360
- name
368361
x-kubernetes-list-type: map
369-
identityRef:
370-
description: AWSIdentityReference specifies a identity.
371-
properties:
372-
kind:
373-
description: Kind of the identity.
374-
enum:
375-
- AWSClusterControllerIdentity
376-
- AWSClusterRoleIdentity
377-
- AWSClusterStaticIdentity
378-
type: string
379-
name:
380-
description: Name of the identity.
381-
minLength: 1
382-
type: string
383-
required:
384-
- kind
385-
- name
386-
type: object
387-
managedOIDC:
388-
default: true
389-
description: ManagedOIDC indicates whether it is a Red Hat managed
390-
or unmanaged (Customer hosted) OIDC Configuration. Default is
391-
true.
392-
type: boolean
393-
prefix:
394-
type: string
395-
region:
396-
type: string
397-
required:
398-
- managedOIDC
399-
- prefix
400362
type: object
401363
operatorRoleConfig:
402364
description: OperatorRoleConfig defines cluster-specific operator

controlplane/rosa/api/v1beta2/rosacontrolplane_webhook.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import (
1515
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
1616
)
1717

18+
// log is for logging in this package.
19+
var rosacpLog = ctrl.Log.WithName("rosacontrolplane-resource")
20+
1821
// SetupWebhookWithManager will setup the webhooks for the ROSAControlPlane.
1922
func (r *ROSAControlPlane) SetupWebhookWithManager(mgr ctrl.Manager) error {
2023
w := new(rosaControlPlaneWebhook)
@@ -184,25 +187,54 @@ func (r *ROSAControlPlane) validateExternalAuthProviders() *field.Error {
184187
}
185188

186189
func (r *ROSAControlPlane) validateRosaRoleConfig() *field.Error {
187-
hasRosaRoleConfigRef := r.Spec.RosaRoleConfigRef != nil
188190
hasAnyDirectRoleFields := r.Spec.OIDCID != "" || r.Spec.InstallerRoleARN != "" || r.Spec.SupportRoleARN != "" || r.Spec.WorkerRoleARN != "" ||
189191
r.Spec.RolesRef.IngressARN != "" || r.Spec.RolesRef.ImageRegistryARN != "" || r.Spec.RolesRef.StorageARN != "" ||
190192
r.Spec.RolesRef.NetworkARN != "" || r.Spec.RolesRef.KubeCloudControllerARN != "" || r.Spec.RolesRef.NodePoolManagementARN != "" ||
191193
r.Spec.RolesRef.ControlPlaneOperatorARN != "" || r.Spec.RolesRef.KMSProviderARN != ""
192194

193-
hasAllDirectRoleFields := r.Spec.OIDCID != "" && r.Spec.InstallerRoleARN != "" && r.Spec.SupportRoleARN != "" && r.Spec.WorkerRoleARN != "" &&
194-
r.Spec.RolesRef.IngressARN != "" && r.Spec.RolesRef.ImageRegistryARN != "" && r.Spec.RolesRef.StorageARN != "" &&
195-
r.Spec.RolesRef.NetworkARN != "" && r.Spec.RolesRef.KubeCloudControllerARN != "" && r.Spec.RolesRef.NodePoolManagementARN != "" &&
196-
r.Spec.RolesRef.ControlPlaneOperatorARN != "" && r.Spec.RolesRef.KMSProviderARN != ""
197-
198-
if hasRosaRoleConfigRef && hasAnyDirectRoleFields {
199-
return field.Invalid(field.NewPath("spec.rosaRoleConfigRef"), r.Spec.RosaRoleConfigRef, "rosaRoleConfigRef and direct role fields (oidcID, installerRoleARN, supportRoleARN, workerRoleARN, rolesRef) are mutually exclusive")
195+
if r.Spec.RosaRoleConfigRef != nil {
196+
if hasAnyDirectRoleFields {
197+
rosacpLog.Info("rosaRoleConfigRef and direct role fields (oidcID, installerRoleARN, supportRoleARN, workerRoleARN, rolesRef) are mutually exclusive")
198+
}
199+
return nil
200200
}
201201

202-
if !hasRosaRoleConfigRef && !hasAllDirectRoleFields {
203-
return field.Invalid(field.NewPath("spec"), r.Spec, "either rosaRoleConfigRef or direct role fields (oidcID, installerRoleARN, supportRoleARN, workerRoleARN, rolesRef) must be specified")
202+
if r.Spec.OIDCID == "" {
203+
return field.Invalid(field.NewPath("spec.oidcID"), r.Spec.OIDCID, "must be specified")
204+
}
205+
if r.Spec.InstallerRoleARN == "" {
206+
return field.Invalid(field.NewPath("spec.installerRoleARN"), r.Spec.InstallerRoleARN, "must be specified")
207+
}
208+
if r.Spec.SupportRoleARN == "" {
209+
return field.Invalid(field.NewPath("spec.supportRoleARN"), r.Spec.SupportRoleARN, "must be specified")
210+
}
211+
if r.Spec.WorkerRoleARN == "" {
212+
return field.Invalid(field.NewPath("spec.workerRoleARN"), r.Spec.WorkerRoleARN, "must be specified")
213+
}
214+
if r.Spec.RolesRef.IngressARN == "" {
215+
return field.Invalid(field.NewPath("spec.rolesRef.ingressARN"), r.Spec.RolesRef.IngressARN, "must be specified")
216+
}
217+
if r.Spec.RolesRef.ImageRegistryARN == "" {
218+
return field.Invalid(field.NewPath("spec.rolesRef.imageRegistryARN"), r.Spec.RolesRef.ImageRegistryARN, "must be specified")
219+
}
220+
if r.Spec.RolesRef.StorageARN == "" {
221+
return field.Invalid(field.NewPath("spec.rolesRef.storageARN"), r.Spec.RolesRef.StorageARN, "must be specified")
222+
}
223+
if r.Spec.RolesRef.NetworkARN == "" {
224+
return field.Invalid(field.NewPath("spec.rolesRef.networkARN"), r.Spec.RolesRef.NetworkARN, "must be specified")
225+
}
226+
if r.Spec.RolesRef.KubeCloudControllerARN == "" {
227+
return field.Invalid(field.NewPath("spec.rolesRef.kubeCloudControllerARN"), r.Spec.RolesRef.KubeCloudControllerARN, "must be specified")
228+
}
229+
if r.Spec.RolesRef.NodePoolManagementARN == "" {
230+
return field.Invalid(field.NewPath("spec.rolesRef.nodePoolManagementARN"), r.Spec.RolesRef.NodePoolManagementARN, "must be specified")
231+
}
232+
if r.Spec.RolesRef.ControlPlaneOperatorARN == "" {
233+
return field.Invalid(field.NewPath("spec.rolesRef.controlPlaneOperatorARN"), r.Spec.RolesRef.ControlPlaneOperatorARN, "must be specified")
234+
}
235+
if r.Spec.RolesRef.KMSProviderARN == "" {
236+
return field.Invalid(field.NewPath("spec.rolesRef.kmsProviderARN"), r.Spec.RolesRef.KMSProviderARN, "must be specified")
204237
}
205-
206238
return nil
207239
}
208240

controlplane/rosa/controllers/rosacontrolplane_controller.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ func (r *ROSAControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Req
171171
}
172172

173173
log = log.WithValues("cluster", klog.KObj(cluster))
174-
175174
if isPaused, conditionChanged, err := paused.EnsurePausedCondition(ctx, r.Client, cluster, rosaControlPlane); err != nil || isPaused || conditionChanged {
176175
return ctrl.Result{}, err
177176
}
@@ -202,10 +201,10 @@ func (r *ROSAControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Req
202201
}
203202

204203
// Handle normal reconciliation loop.
205-
return r.reconcileNormal(ctx, rosaScope)
204+
return r.reconcileNormal(ctx, rosaScope, log)
206205
}
207206

208-
func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaScope *scope.ROSAControlPlaneScope) (res ctrl.Result, reterr error) {
207+
func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaScope *scope.ROSAControlPlaneScope, log *logger.Logger) (res ctrl.Result, reterr error) {
209208
rosaScope.Info("Reconciling ROSAControlPlane")
210209

211210
if controllerutil.AddFinalizer(rosaScope.ControlPlane, ROSAControlPlaneFinalizer) {
@@ -245,9 +244,11 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
245244
rosacontrolplanev1.ROSARoleConfigNotFoundReason,
246245
clusterv1.ConditionSeverityError,
247246
"RosaRoleConfig %s/%s not found", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name)
248-
return ctrl.Result{}, fmt.Errorf("RosaRoleConfig %s/%s not found: %w", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name, err)
247+
log.Error(err, fmt.Sprintf("RosaRoleConfig %s/%s not found: %w", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name, err))
248+
return ctrl.Result{RequeueAfter: time.Second * 60}, nil
249249
}
250-
return ctrl.Result{}, fmt.Errorf("failed to get RosaRoleConfig %s/%s: %w", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name, err)
250+
log.Error(err, fmt.Sprintf("failed to get RosaRoleConfig %s/%s: %w", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name, err))
251+
return ctrl.Result{RequeueAfter: time.Second * 60}, nil
251252
}
252253

253254
// Check if RosaRoleConfig is ready
@@ -257,7 +258,9 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
257258
rosacontrolplanev1.ROSARoleConfigNotReadyReason,
258259
clusterv1.ConditionSeverityWarning,
259260
"RosaRoleConfig %s/%s is not ready", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name)
260-
return ctrl.Result{}, fmt.Errorf("RosaRoleConfig %s/%s is not ready", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name)
261+
log.Error(err, fmt.Sprintf("RosaRoleConfig %s/%s is not ready", rosaScope.ControlPlane.Namespace, rosaScope.ControlPlane.Spec.RosaRoleConfigRef.Name))
262+
263+
return ctrl.Result{RequeueAfter: time.Second * 60}, nil
261264
}
262265

263266
conditions.MarkTrue(rosaScope.ControlPlane, rosacontrolplanev1.ROSARoleConfigReadyCondition)

exp/api/v1beta2/rosaroleconfig_types.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ type ROSARoleConfigSpec struct {
3636
IdentityRef *infrav1.AWSIdentityReference `json:"identityRef,omitempty"`
3737
Region string `json:"region,omitempty"`
3838
// CredentialsSecretRef references a secret with necessary credentials to connect to the OCM API.
39-
// The secret should contain the following data keys:
40-
// - ocmToken: eyJhbGciOiJIUzI1NiIsI....
41-
// - ocmApiUrl: Optional, defaults to 'https://api.openshift.com'
4239
// +optional
4340
CredentialsSecretRef *corev1.LocalObjectReference `json:"credentialsSecretRef,omitempty"`
4441
}
@@ -60,7 +57,7 @@ type ROSARoleConfig struct {
6057
// AccountRoleConfig defines account-wide IAM roles before creating your ROSA cluster.
6158
type AccountRoleConfig struct {
6259
// User-defined prefix for all generated AWS resources
63-
// +kubebuilder:validation:MaxLength:=40
60+
// +kubebuilder:validation:MaxLength:=4
6461
// +kubebuilder:validation:Required
6562
// +immutable
6663
Prefix string `json:"prefix"`
@@ -112,10 +109,6 @@ type SharedVPCConfig struct {
112109
// OIDCConfig creates OIDC config in a S3 bucket for the client AWS account and populates it to be compliant with OIDC protocol.
113110
// It also creates a Secret in Secrets Manager containing the private key.
114111
type OIDCConfig struct {
115-
// ManagedOIDC indicates whether it is a Red Hat managed or unmanaged (Customer hosted) OIDC Configuration. Default is true.
116-
// +kubebuilder:default=true
117-
// +immutable
118-
ManagedOIDC bool `json:"managedOIDC"`
119112
// ExternalAuthProviders are external OIDC identity providers that can issue tokens for this cluster.
120113
// Can only be set if "enableExternalAuthProviders" is set to "True".
121114
//
@@ -126,15 +119,6 @@ type OIDCConfig struct {
126119
// +kubebuilder:validation:MaxItems=1
127120
// +immutable
128121
ExternalAuthProviders []rosacontrolplanev1.ExternalAuthProvider `json:"externalAuthProviders,omitempty"`
129-
// IdentityRef is the AWS identity reference for the OIDC config.
130-
// +immutable
131-
IdentityRef *infrav1.AWSIdentityReference `json:"identityRef,omitempty"`
132-
// Region is the AWS region for the OIDC config.
133-
// +immutable
134-
Region string `json:"region,omitempty"`
135-
// Prefix is the prefix for the OIDC config.
136-
// +immutable
137-
Prefix string `json:"prefix"`
138122
}
139123

140124
// ROSARoleConfigStatus defines the observed state of ROSARoleConfig

exp/api/v1beta2/zz_generated.deepcopy.go

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)