@@ -31,6 +31,8 @@ import (
3131 "sigs.k8s.io/controller-runtime/pkg/handler"
3232 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3333
34+ "k8s.io/apimachinery/pkg/runtime/schema"
35+
3436 "github.com/go-logr/logr"
3537 condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
3638 "github.com/openstack-k8s-operators/lib-common/modules/common/helper"
@@ -41,6 +43,7 @@ import (
4143 appsv1 "k8s.io/api/apps/v1"
4244 apierrors "k8s.io/apimachinery/pkg/api/errors"
4345 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
46+ uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
4447 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
4548 "sigs.k8s.io/controller-runtime/pkg/log"
4649)
@@ -56,6 +59,18 @@ type OpenStackReconciler struct {
5659 Kclient kubernetes.Interface
5760}
5861
62+ var csvGVR = schema.GroupVersionResource {
63+ Group : "operators.coreos.com" ,
64+ Version : "v1alpha1" ,
65+ Resource : "clusterserviceversions" ,
66+ }
67+
68+ var subscriptionGVR = schema.GroupVersionResource {
69+ Group : "operators.coreos.com" ,
70+ Version : "v1alpha1" ,
71+ Resource : "subscriptions" ,
72+ }
73+
5974// GetLog returns a logger object with a prefix of "controller.name" and aditional controller context fields
6075func (r * OpenStackReconciler ) GetLogger (ctx context.Context ) logr.Logger {
6176 return log .FromContext (ctx ).WithName ("Controllers" ).WithName ("OpenStackControlPlane" )
@@ -110,6 +125,8 @@ func SetupEnv() {
110125// +kubebuilder:rbac:groups=cert-manager.io,resources=issuers,verbs=get;list;watch;create;update;patch;delete;
111126// +kubebuilder:rbac:groups=cert-manager.io,resources=certificates,verbs=get;list;watch;create;update;patch;delete;
112127// +kubebuilder:rbac:groups="monitoring.coreos.com",resources=servicemonitors,verbs=list;get;watch;update;create
128+ // +kubebuilder:rbac:groups=operators.coreos.com,resources=clusterserviceversions,verbs=get;list;delete;
129+ // +kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions,verbs=get;list;delete;
113130
114131// Reconcile is part of the main kubernetes reconciliation loop which aims to
115132// move the current state of the cluster closer to the desired state.
@@ -229,11 +246,9 @@ func (r *OpenStackReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
229246 }
230247
231248 // TODO: cleanup obsolete resources here (remove old CSVs, etc)
232- /*
233- if err := r.cleanupObsoleteResources(ctx); err != nil {
234- return ctrl.Result{}, err
235- }
236- */
249+ if err := r .cleanupObsoleteResources (ctx , instance ); err != nil {
250+ return ctrl.Result {}, err
251+ }
237252
238253 if err := r .applyManifests (ctx , instance ); err != nil {
239254 instance .Status .Conditions .Set (condition .FalseCondition (
@@ -422,6 +437,65 @@ func (r *OpenStackReconciler) renderAndApply(
422437 return nil
423438}
424439
440+ var serviceOperatorNames = []string {"barbican" , "cinder" , "designate" , "glance" , "heat" , "horizon" , "infra" ,
441+ "ironic" , "keystone" , "manila" , "mariadb" , "neutron" , "nova" , "octavia" , "openstack-baremetal" , "ovn" ,
442+ "placement" , "rabbitmq-cluster" , "swift" , "telemetry" }
443+
444+ func isServiceOperatorResource (name string ) bool {
445+ for _ , item := range serviceOperatorNames {
446+ if strings .Index (name , item ) == 0 {
447+ return true
448+ }
449+ }
450+ return false
451+ }
452+
453+ // cleanupObsoleteResources - deletes CSVs for old service operator bundles
454+ func (r * OpenStackReconciler ) cleanupObsoleteResources (ctx context.Context , instance * operatorv1beta1.OpenStack ) error {
455+ Log := r .GetLogger (ctx )
456+
457+ subscriptionList := & uns.UnstructuredList {}
458+ subscriptionList .SetGroupVersionKind (subscriptionGVR .GroupVersion ().WithKind ("Subscription" ))
459+ err := r .Client .List (ctx , subscriptionList , & client.ListOptions {Namespace : instance .Namespace })
460+ if err != nil {
461+ Log .Error (err , "Unable to retrieve Subscriptions instances" )
462+ return err
463+ }
464+ for _ , subscription := range subscriptionList .Items {
465+ Log .Info ("Found Subscription" , "name" , subscription .GetName ())
466+ if isServiceOperatorResource (subscription .GetName ()) {
467+ err = r .Client .Delete (ctx , & subscription )
468+ if err != nil {
469+ Log .Error (err , "Failed to delete existing Subscription" )
470+ return err
471+ }
472+ }
473+ Log .Info ("Subscription deleted successfully" )
474+ }
475+
476+ csvList := & uns.UnstructuredList {}
477+ csvList .SetGroupVersionKind (csvGVR .GroupVersion ().WithKind ("ClusterServiceVersionList" ))
478+
479+ err = r .Client .List (ctx , csvList , & client.ListOptions {Namespace : instance .Namespace })
480+ if err != nil {
481+ Log .Error (err , "Unable to retrieve CSV instances" )
482+ return err
483+ }
484+ for _ , csv := range csvList .Items {
485+ Log .Info ("Found CSV" , "name" , csv .GetName ())
486+ if isServiceOperatorResource (csv .GetName ()) {
487+ err = r .Client .Delete (ctx , & csv )
488+ if err != nil {
489+ Log .Error (err , "Failed to delete existing CSV" )
490+ return err
491+ }
492+ }
493+ Log .Info ("CSV deleted successfully" )
494+ }
495+ return nil
496+
497+ }
498+
425499// SetupWithManager sets up the controller with the Manager.
426500func (r * OpenStackReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
427501
0 commit comments