Skip to content

Commit

Permalink
add Progressing condition
Browse files Browse the repository at this point in the history
Signed-off-by: Ankita Thomas <ankithom@redhat.com>
  • Loading branch information
ankitathomas committed Mar 26, 2024
1 parent a020804 commit 03904d9
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 150 deletions.
42 changes: 30 additions & 12 deletions api/v1alpha1/clusterextension_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,32 +75,45 @@ type ClusterExtensionSpec struct {

const (
// TODO(user): add more Types, here and into init()
// TypeInstalled indicates whether the install for the bundle
// referenced in the status was completed.
// It does not indicate whether the App created by the bundle is healthy.
TypeInstalled = "Installed"
TypeResolved = "Resolved"
// TypeProgressing indicates whether operator-controller is
// reconciling, installing, updating or deleting an extension.
TypeProgressing = "Progressing"
TypeResolved = "Resolved"
//TODO: Add a TypeHealthy to status of App health checks
// TypeDeprecated is a rollup condition that is present when
// any of the deprecated conditions are present.
TypeDeprecated = "Deprecated"
TypePackageDeprecated = "PackageDeprecated"
TypeChannelDeprecated = "ChannelDeprecated"
TypeBundleDeprecated = "BundleDeprecated"

ReasonBundleLookupFailed = "BundleLookupFailed"
ReasonInstallationFailed = "InstallationFailed"
ReasonInstallationStatusUnknown = "InstallationStatusUnknown"
ReasonInstallationSucceeded = "InstallationSucceeded"
ReasonInvalidSpec = "InvalidSpec"
ReasonResolutionFailed = "ResolutionFailed"
ReasonResolutionUnknown = "ResolutionUnknown"
ReasonSuccess = "Success"
ReasonDeprecated = "Deprecated"
ReasonDeleteFailed = "DeleteFailed"
ReasonDeleting = "Deleting"
ReasonBundleLookupFailed = "BundleLookupFailed"
ReasonInstallationFailed = "InstallationFailed"
ReasonInstallationStatusUnknown = "InstallationStatusUnknown"
ReasonInstallationSucceeded = "InstallationSucceeded"
ReasonInvalidSpec = "InvalidSpec"
ReasonResolutionFailed = "ResolutionFailed"
ReasonResolutionUnknown = "ResolutionUnknown"
ReasonSuccess = "Success"
ReasonDeprecated = "Deprecated"
ReasonDeleteFailed = "DeleteFailed"
ReasonDeleting = "Deleting"
ReasonUnknown = "Unknown"
ReasonPending = "Pending"
ReasonReconcileFailed = "ReconcileFailed"
ReasonReconciling = "Reconciling"
ReasonUnsupportedOrInvalidBundle = "UnsupportedOrInvalidBundle"
)

func init() {
// TODO(user): add Types from above
conditionsets.ConditionTypes = append(conditionsets.ConditionTypes,
TypeInstalled,
TypeProgressing,
TypeResolved,
TypeDeprecated,
TypePackageDeprecated,
Expand All @@ -120,6 +133,11 @@ func init() {
ReasonDeprecated,
ReasonDeleteFailed,
ReasonDeleting,
ReasonUnknown,
ReasonPending,
ReasonReconcileFailed,
ReasonReconciling,
ReasonUnsupportedOrInvalidBundle,
)
}

Expand Down
114 changes: 90 additions & 24 deletions internal/controllers/common_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,39 @@ func setResolvedStatusConditionSuccess(conditions *[]metav1.Condition, message s
})
}

// setResolvedStatusConditionFailed sets the resolved status condition to failed.
func setResolvedStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeResolved,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonResolutionFailed,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionSuccess sets the installed status condition to success.
func setInstalledStatusConditionSuccess(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Status: metav1.ConditionTrue,
Reason: ocv1alpha1.ReasonSuccess,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionFailed sets the installed status condition to failed.
func setInstalledStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonInstallationFailed,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionUnknown sets the installed status condition to unknown.
func setInstalledStatusConditionUnknown(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Expand All @@ -55,73 +88,106 @@ func setInstalledStatusConditionUnknown(conditions *[]metav1.Condition, message
})
}

// setResolvedStatusConditionFailed sets the resolved status condition to failed.
func setResolvedStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionFalse sets the progressing status condition to false, awaiting next reconcile.
func setProgressingStatusConditionFalse(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeResolved,
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonResolutionFailed,
Reason: ocv1alpha1.ReasonPending,
Message: message,
ObservedGeneration: generation,
})
}

// setResolvedStatusConditionUnknown sets the resolved status condition to unknown.
func setResolvedStatusConditionUnknown(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionUnknown sets the progressing status condition to unknown.
func setProgressingStatusConditionUnknown(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeResolved,
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionUnknown,
Reason: ocv1alpha1.ReasonResolutionUnknown,
Reason: ocv1alpha1.ReasonUnknown,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionSuccess sets the installed status condition to success.
func setInstalledStatusConditionSuccess(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionResolutionFailed sets the progressing status condition to false for failed bundle resolutions.
func setProgressingStatusConditionResolutionFailed(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonResolutionFailed,
Message: message,
ObservedGeneration: generation,
})
}

// setProgressingStatusConditionUnsupportedOrInvalidBundle sets the progressing status condition to false for unsupported/invalid bundles.
func setProgressingStatusConditionUnsupportedOrInvalidBundle(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonUnsupportedOrInvalidBundle,
Message: message,
ObservedGeneration: generation,
})
}

// setProgressingStatusConditionReconciling sets the progressing status condition to true for an app being reconciled.
func setProgressingStatusConditionReconciling(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionTrue,
Reason: ocv1alpha1.ReasonSuccess,
Reason: ocv1alpha1.ReasonReconciling,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionFailed sets the installed status condition to failed.
func setInstalledStatusConditionFailed(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionReconcileFailed sets the progressing status condition to false for an unsuccessfully reconciled app.
func setProgressingStatusConditionReconcileFailed(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonInstallationFailed,
Reason: ocv1alpha1.ReasonReconcileFailed,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionDeleting sets the installed status condition to unknown for deletes in progress.
func setInstalledStatusConditionDeleting(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionReconcileSuccess sets the progressing status condition to false for a successfully reconciled app.
func setProgressingStatusConditionReconcileSuccess(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Status: metav1.ConditionUnknown,
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonSuccess,
Message: message,
ObservedGeneration: generation,
})
}

// setProgressingStatusConditionDeleting sets the progressing status condition to true for a progressing app delete.
func setProgressingStatusConditionDeleting(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeProgressing,
Status: metav1.ConditionTrue,
Reason: ocv1alpha1.ReasonDeleting,
Message: message,
ObservedGeneration: generation,
})
}

// setInstalledStatusConditionDeleteFailed sets the installed status condition to unknown for failed deletes.
func setInstalledStatusConditionDeleteFailed(conditions *[]metav1.Condition, message string, generation int64) {
// setProgressingStatusConditionDeleteFailed sets the progressing status condition to false for failed app delete.
func setProgressingStatusConditionDeleteFailed(conditions *[]metav1.Condition, message string, generation int64) {
apimeta.SetStatusCondition(conditions, metav1.Condition{
Type: ocv1alpha1.TypeInstalled,
Status: metav1.ConditionUnknown,
Status: metav1.ConditionFalse,
Reason: ocv1alpha1.ReasonDeleteFailed,
Message: message,
ObservedGeneration: generation,
})
}

// setDEprecationStatusesUnknown sets the deprecation status conditions to unknown.
// setDeprecationStatusesUnknown sets the deprecation status conditions to unknown.
func setDeprecationStatusesUnknown(conditions *[]metav1.Condition, message string, generation int64) {
conditionTypes := []string{
ocv1alpha1.TypeDeprecated,
Expand Down
59 changes: 33 additions & 26 deletions internal/controllers/extension_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,9 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext
// hasn't been attempted yet, due to the spec being invalid.
ext.Status.InstalledBundleResource = ""
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration())
// Set the TypeResolved condition to Unknown to indicate that the resolution
// hasn't been attempted yet, due to the spec being invalid.

ext.Status.ResolvedBundleResource = ""
setResolvedStatusConditionUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration())
setProgressingStatusConditionUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration())

setDeprecationStatusesUnknown(&ext.Status.Conditions, "extension feature is disabled", ext.GetGeneration())
return ctrl.Result{}, nil
Expand All @@ -148,32 +147,35 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext
if !r.HasKappApis {
ext.Status.InstalledBundleResource = ""
setInstalledStatusConditionFailed(&ext.Status.Conditions, errkappAPIUnavailable.Error(), ext.GetGeneration())

ext.Status.ResolvedBundleResource = ""
setResolvedStatusConditionUnknown(&ext.Status.Conditions, "kapp apis are unavailable", ext.GetGeneration())

setProgressingStatusConditionUnknown(&ext.Status.Conditions, "kapp apis are unavailable", ext.GetGeneration())
setDeprecationStatusesUnknown(&ext.Status.Conditions, "kapp apis are unavailable", ext.GetGeneration())
return ctrl.Result{}, errkappAPIUnavailable
}

// TODO: Improve the resolution logic.
bundle, err := r.resolve(ctx, *ext)
if err != nil {
ext.Status.InstalledBundleResource = ""
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "installation has not been attempted as resolution failed", ext.GetGeneration())
if ext.Status.InstalledBundleResource == "" {
setInstalledStatusConditionUnknown(&ext.Status.Conditions, "installation has not been attempted as resolution failed", ext.GetGeneration())
}
ext.Status.ResolvedBundleResource = ""
setResolvedStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration())
setProgressingStatusConditionResolutionFailed(&ext.Status.Conditions, "resolution failed: "+err.Error(), ext.GetGeneration())
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as resolution failed", ext.GetGeneration())
return ctrl.Result{}, err
}

// Now we can set the Resolved Condition, and the resolvedBundleSource field to the bundle.Image value.
ext.Status.ResolvedBundleResource = bundle.Image
setResolvedStatusConditionSuccess(&ext.Status.Conditions, fmt.Sprintf("resolved to %q", bundle.Image), ext.GetGeneration())

mediaType, err := bundle.MediaType()
if err != nil {
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration())
if ext.Status.InstalledBundleResource == "" {
// Set the TypeInstalled condition to Unknown to indicate that the resolution
// hasn't been attempted yet, due to the spec being invalid.
setInstalledStatusConditionUnknown(&ext.Status.Conditions, err.Error(), ext.GetGeneration())
}
setProgressingStatusConditionUnsupportedOrInvalidBundle(&ext.Status.Conditions, "failed to read bundle mediaType: "+err.Error(), ext.GetGeneration())
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration())
return ctrl.Result{}, err
}
Expand All @@ -183,8 +185,10 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext
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.InstalledBundleResource = ""
setInstalledStatusConditionUnknown(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration())
if ext.Status.InstalledBundleResource == "" {
setInstalledStatusConditionUnknown(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration())
}
setProgressingStatusConditionUnsupportedOrInvalidBundle(&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())
return ctrl.Result{}, nil
}
Expand All @@ -194,6 +198,8 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext
// originally Reason: ocv1alpha1.ReasonInstallationFailed
ext.Status.InstalledBundleResource = ""
setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration())
setProgressingStatusConditionFalse(&ext.Status.Conditions, "app install failed", ext.GetGeneration())
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration())
return ctrl.Result{}, err
}

Expand All @@ -203,11 +209,15 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext
// originally Reason: ocv1alpha1.ReasonInstallationStatusUnknown
ext.Status.InstalledBundleResource = ""
setInstalledStatusConditionUnknown(&ext.Status.Conditions, err.Error(), ext.GetGeneration())
setProgressingStatusConditionFalse(&ext.Status.Conditions, "app install failed", ext.GetGeneration())
setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration())
return ctrl.Result{}, err
}

MapAppStatusToCondition(existingTypedApp, ext, bundle.Image)
ext.Status.InstalledBundleResource = bundle.Image
setInstalledStatusConditionSuccess(&ext.Status.Conditions, "app install succeeded", ext.GetGeneration())

MapAppStatusToCondition(existingTypedApp, ext)
SetDeprecationStatusInExtension(ext, bundle)

return ctrl.Result{}, nil
Expand All @@ -232,12 +242,12 @@ func (r *ExtensionReconciler) SetupWithManager(mgr ctrl.Manager) error {
}

// mapAppStatusToCondition maps the reconciling/deleting App conditions to the installed/deleting conditions on the Extension.
func MapAppStatusToCondition(existingApp *kappctrlv1alpha1.App, ext *ocv1alpha1.Extension, bundleImage string) {
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.
if ext == nil {
return
}
message := "install status unknown"
ext.Status.InstalledBundleResource = ""
message := "app status unknown"

if existingApp == nil {
setInstalledStatusConditionUnknown(&ext.Status.Conditions, message, ext.Generation)
Expand All @@ -256,26 +266,23 @@ func MapAppStatusToCondition(existingApp *kappctrlv1alpha1.App, ext *ocv1alpha1.
kappctrlv1alpha1.Reconciling,
}
appStatusMapFn := map[kappctrlv1alpha1.ConditionType]func(*[]metav1.Condition, string, int64){
kappctrlv1alpha1.DeleteFailed: setInstalledStatusConditionDeleteFailed,
kappctrlv1alpha1.Deleting: setInstalledStatusConditionDeleting,
kappctrlv1alpha1.ReconcileSucceeded: setInstalledStatusConditionSuccess,
kappctrlv1alpha1.ReconcileFailed: setInstalledStatusConditionFailed,
kappctrlv1alpha1.Reconciling: setInstalledStatusConditionUnknown,
kappctrlv1alpha1.DeleteFailed: setProgressingStatusConditionDeleteFailed,
kappctrlv1alpha1.Deleting: setProgressingStatusConditionDeleting,
kappctrlv1alpha1.ReconcileSucceeded: setProgressingStatusConditionReconcileSuccess,
kappctrlv1alpha1.ReconcileFailed: setProgressingStatusConditionReconcileFailed,
kappctrlv1alpha1.Reconciling: setProgressingStatusConditionReconciling,
}
for _, cond := range orderedAppStatuses {
if c := findStatusCondition(existingApp.Status.GenericStatus.Conditions, cond); c != nil && c.Status == corev1.ConditionTrue {
if len(message) == 0 {
message = c.Message
}
if c.Type == kappctrlv1alpha1.ReconcileSucceeded {
ext.Status.InstalledBundleResource = bundleImage
}
appStatusMapFn[cond](&ext.Status.Conditions, message, ext.Generation)
return
}
}
if len(message) == 0 {
message = "install status unknown"
message = "app status unknown"
}
setInstalledStatusConditionUnknown(&ext.Status.Conditions, message, ext.Generation)
}
Expand Down
Loading

0 comments on commit 03904d9

Please sign in to comment.