-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨improve Extension status conditions #683
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,14 +127,14 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext | |
if !features.OperatorControllerFeatureGate.Enabled(features.EnableExtensionAPI) { | ||
l.Info("extension feature is gated", "name", ext.GetName(), "namespace", ext.GetNamespace()) | ||
|
||
// Set the TypeInstalled condition to Unknown to indicate that the resolution | ||
// Set the TypeInstalled condition to Failed to indicate that the resolution | ||
// hasn't been attempted yet, due to the spec being invalid. | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration()) | ||
// Set the TypeResolved condition to Unknown to indicate that the resolution | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration()) | ||
// Set the TypeResolved condition to Failed to indicate that the resolution | ||
// hasn't been attempted yet, due to the spec being invalid. | ||
ext.Status.ResolvedBundle = nil | ||
setResolvedStatusConditionUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration()) | ||
setResolvedStatusConditionFailed(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration()) | ||
|
||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration()) | ||
return ctrl.Result{}, nil | ||
|
@@ -150,8 +150,10 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext | |
// TODO: Improve the resolution logic. | ||
bundle, err := r.resolve(ctx, *ext) | ||
if err != nil { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "installation has not been attempted as resolution failed", ext.GetGeneration()) | ||
if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, "installation has not been attempted as resolution failed", ext.GetGeneration()) | ||
} | ||
ext.Status.ResolvedBundle = nil | ||
setResolvedStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as resolution failed", ext.GetGeneration()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know you didn't touch this part of the code, but we should be able to determine deprecation status:
Can you make a follow-up issue to improve this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #671 should address it |
||
|
@@ -164,33 +166,46 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext | |
|
||
mediaType, err := bundle.MediaType() | ||
if err != nil { | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("failed to read bundle mediaType: %v", err), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
} | ||
setProgressingStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("failed to read bundle mediaType: %v", err), ext.GetGeneration()) | ||
ankitathomas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return ctrl.Result{}, err | ||
} | ||
|
||
// TODO: this needs to include the registryV1 bundle option. As of this PR, this only supports direct | ||
// installation of a set of manifests. | ||
if mediaType != catalogmetadata.MediaTypePlain { | ||
// Set the TypeInstalled condition to Unknown to indicate that the resolution | ||
// hasn't been attempted yet, due to the spec being invalid. | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { | ||
// Set the TypeInstalled condition to Failed to indicate that the resolution | ||
// hasn't been attempted yet, due to the spec being invalid. | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
} | ||
setProgressingStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration()) | ||
ankitathomas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return ctrl.Result{}, nil | ||
} | ||
|
||
app, err := r.GenerateExpectedApp(*ext, bundle) | ||
if err != nil { | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
} | ||
setProgressingStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
if err := r.ensureApp(ctx, app); err != nil { | ||
// originally Reason: ocv1alpha1.ReasonInstallationFailed | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
setProgressingStatusConditionProgressing(&ext.Status.Conditions, "installation failed", ext.GetGeneration()) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
|
@@ -199,14 +214,19 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext | |
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(app.UnstructuredContent(), existingTypedApp); err != nil { | ||
// originally Reason: ocv1alpha1.ReasonInstallationStatusUnknown | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) | ||
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) | ||
setProgressingStatusConditionProgressing(&ext.Status.Conditions, "installation failed", ext.GetGeneration()) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
mapAppStatusToInstalledCondition(existingTypedApp, ext, bundle) | ||
ext.Status.InstalledBundle = bundleMetadataFor(bundle) | ||
setInstalledStatusConditionSuccess(&ext.Status.Conditions, fmt.Sprintf("successfully installed %v", ext.Status.InstalledBundle), ext.GetGeneration()) | ||
SetDeprecationStatusInExtension(ext, bundle) | ||
|
||
// TODO: add conditions to determine extension health | ||
mapAppStatusToCondition(existingTypedApp, ext) | ||
|
||
return ctrl.Result{}, nil | ||
} | ||
|
||
|
@@ -228,28 +248,37 @@ func (r *ExtensionReconciler) SetupWithManager(mgr ctrl.Manager) error { | |
Complete(r) | ||
} | ||
|
||
// TODO: follow up with mapping of all the available App statuses: https://github.com/carvel-dev/kapp-controller/blob/855063edee53315811a13ee8d5df1431ba258ede/pkg/apis/kappctrl/v1alpha1/status.go#L28-L35 | ||
// mapAppStatusToInstalledCondition currently maps only the installed condition. | ||
func mapAppStatusToInstalledCondition(existingApp *kappctrlv1alpha1.App, ext *ocv1alpha1.Extension, bundle *catalogmetadata.Bundle) { | ||
appReady := findStatusCondition(existingApp.Status.GenericStatus.Conditions, kappctrlv1alpha1.ReconcileSucceeded) | ||
if appReady == nil { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "install status unknown", ext.Generation) | ||
// mapAppStatusToCondition maps the reconciling/deleting App conditions to the installed/deleting conditions on the Extension. | ||
func mapAppStatusToCondition(existingApp *kappctrlv1alpha1.App, ext *ocv1alpha1.Extension) { | ||
// Note: App.Status.Inspect errors are never surfaced to App conditions, so are currently ignored when determining App status. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. iirc, also |
||
if ext == nil || existingApp == nil { | ||
return | ||
} | ||
|
||
if appReady.Status != corev1.ConditionTrue { | ||
ext.Status.InstalledBundle = nil | ||
setInstalledStatusConditionFailed( | ||
&ext.Status.Conditions, | ||
appReady.Message, | ||
ext.GetGeneration(), | ||
) | ||
return | ||
message := existingApp.Status.FriendlyDescription | ||
if len(message) == 0 || strings.Contains(message, "Error (see .status.usefulErrorMessage for details)") { | ||
message = existingApp.Status.UsefulErrorMessage | ||
} | ||
|
||
ext.Status.InstalledBundle = bundleMetadataFor(bundle) | ||
setInstalledStatusConditionSuccess(&ext.Status.Conditions, appReady.Message, ext.Generation) | ||
appStatusMapFn := map[kappctrlv1alpha1.ConditionType]func(*[]metav1.Condition, string, int64){ | ||
kappctrlv1alpha1.Deleting: setProgressingStatusConditionProgressing, | ||
kappctrlv1alpha1.Reconciling: setProgressingStatusConditionProgressing, | ||
kappctrlv1alpha1.DeleteFailed: setProgressingStatusConditionFailed, | ||
kappctrlv1alpha1.ReconcileFailed: setProgressingStatusConditionFailed, | ||
kappctrlv1alpha1.ReconcileSucceeded: setProgressingStatusConditionSuccess, | ||
} | ||
for cond := range appStatusMapFn { | ||
if c := findStatusCondition(existingApp.Status.GenericStatus.Conditions, cond); c != nil && c.Status == corev1.ConditionTrue { | ||
if len(message) == 0 { | ||
message = c.Message | ||
} | ||
appStatusMapFn[cond](&ext.Status.Conditions, fmt.Sprintf("App %s: %s", c.Type, message), ext.Generation) | ||
return | ||
} | ||
} | ||
if len(message) == 0 { | ||
message = "waiting for app" | ||
} | ||
setProgressingStatusConditionProgressing(&ext.Status.Conditions, message, ext.Generation) | ||
Comment on lines
+262
to
+281
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a huge fan of looping through all the status conditions 5 times but since we are moving away from building on top of the App CR and this is an optimization that could be made in the future I'm fine with it for now |
||
} | ||
|
||
// setDeprecationStatus will set the appropriate deprecation statuses for a Extension | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We could also pass in the the reason to the method signature, such that these helpers are used to just indicate if the particular
Status
is set to false or true. Its a personal preference, so whatever you think makes it easier to read the code.