diff --git a/api/core/v1alpha1/clustercatalog_types.go b/api/core/v1alpha1/clustercatalog_types.go index ecc88403..c33f3d50 100644 --- a/api/core/v1alpha1/clustercatalog_types.go +++ b/api/core/v1alpha1/clustercatalog_types.go @@ -33,6 +33,7 @@ const ( // Serving reasons ReasonAvailable = "Available" ReasonUnavailable = "Unavailable" + ReasonDisabled = "Disabled" // Progressing reasons ReasonSucceeded = "Succeeded" @@ -40,6 +41,9 @@ const ( ReasonBlocked = "Blocked" MetadataNameLabel = "olm.operatorframework.io/metadata.name" + + AvailabilityEnabled = "Enabled" + AvailabilityDisabled = "Disabled" ) //+kubebuilder:object:root=true @@ -92,6 +96,20 @@ type ClusterCatalogSpec struct { // +kubebuilder:default:=0 // +optional Priority int32 `json:"priority"` + + // Availability is an optional field that allows users to define whether the ClusterCatalog is utilized by the operator-controller. + // + // Allowed values are : ["Enabled", "Disabled"]. + // If set to "Enabled", the catalog will be used for updates, serving contents, and package installations. + // + // If set to "Disabled", catalogd will stop serving the catalog and the cached data will be removed. + // + // If unspecified, the default value is "Enabled" + // + // +kubebuilder:validation:Enum="Disabled";"Enabled" + // +kubebuilder:default="Enabled" + // +optional + Availability string `json:"availability,omitempty"` } // ClusterCatalogStatus defines the observed state of ClusterCatalog diff --git a/cmd/manager/main.go b/cmd/manager/main.go index a2d0175a..b6dae394 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -260,6 +260,7 @@ func main() { localStorage = storage.LocalDir{RootDir: storeDir, BaseURL: baseStorageURL} + // Config for the the catalogd web server catalogServerConfig := serverutil.CatalogServerConfig{ ExternalAddr: externalAddr, CatalogAddr: catalogServerAddr, @@ -268,6 +269,7 @@ func main() { LocalStorage: localStorage, } + // Start the catalogd web server err = serverutil.AddCatalogServerToManager(mgr, catalogServerConfig, cw) if err != nil { setupLog.Error(err, "unable to configure catalog server") diff --git a/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml b/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml index 67a0d774..678cf072 100644 --- a/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml +++ b/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml @@ -51,6 +51,16 @@ spec: spec: description: ClusterCatalogSpec defines the desired state of ClusterCatalog properties: + availability: + default: Enabled + description: |- + Availability is an optional field that allows users to define whether the ClusterCatalog is utilized by the operator-controller. + If set to "Enabled", the catalog will be used for updates, serving contents, and package installations. + If set to "Disabled", the catalog will be ignored by the operator-controller, meaning it will not be used for any operations. + enum: + - Disabled + - Enabled + type: string priority: default: 0 description: |- diff --git a/internal/controllers/core/clustercatalog_controller.go b/internal/controllers/core/clustercatalog_controller.go index a8ad497c..c3275280 100644 --- a/internal/controllers/core/clustercatalog_controller.go +++ b/internal/controllers/core/clustercatalog_controller.go @@ -88,6 +88,7 @@ func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Reque if err := r.Client.Get(ctx, req.NamespacedName, &existingCatsrc); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } + reconciledCatsrc := existingCatsrc.DeepCopy() res, reconcileErr := r.reconcile(ctx, reconciledCatsrc) @@ -157,6 +158,32 @@ func (r *ClusterCatalogReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ClusterCatalogReconciler) reconcile(ctx context.Context, catalog *v1alpha1.ClusterCatalog) (ctrl.Result, error) { l := log.FromContext(ctx) + // Check if the catalog availability is set to disabled, if true then + // unset content URL, delete it from the cache and set appropriate status + if catalog.Spec.Availability == v1alpha1.AvailabilityDisabled { + + // Delete the catalog from local + if err := r.Storage.Delete(catalog.Name); err != nil { + updateStatusProgressing(&catalog.Status, catalog.GetGeneration(), err) + return ctrl.Result{}, err + } + + // Set status.conditions[type=Serving] to False, unset status.contentURL and + // update status.lastUnpacked + updateStatusNotServing(&catalog.Status, catalog.GetGeneration()) + if err := r.Unpacker.Cleanup(ctx, catalog); err != nil { + updateStatusProgressing(&catalog.Status, catalog.GetGeneration(), err) + return ctrl.Result{}, err + } + r.deleteStoredCatalog(catalog.Name) + + // Set status.conditions[type=Progressing] to False as we are done with + // all that needs to be done with the catalog + updateStatusCatalogDisabled(&catalog.Status, catalog.GetGeneration()) + + return ctrl.Result{}, nil + } + finalizeResult, err := r.finalizers.Finalize(ctx, catalog) if err != nil { return ctrl.Result{}, err @@ -315,6 +342,17 @@ func updateStatusServing(status *v1alpha1.ClusterCatalogStatus, result source.Re }) } +func updateStatusCatalogDisabled(status *v1alpha1.ClusterCatalogStatus, generation int64) { + progressingCond := metav1.Condition{ + Type: v1alpha1.TypeProgressing, + Status: metav1.ConditionFalse, + Reason: v1alpha1.ReasonDisabled, + Message: "Catalog availability is set to Disabled", + ObservedGeneration: generation, + } + meta.SetStatusCondition(&status.Conditions, progressingCond) +} + func updateStatusNotServing(status *v1alpha1.ClusterCatalogStatus, generation int64) { status.ResolvedSource = nil status.ContentURL = ""