github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/pkg/controllers/blockdevice/blockdevice_controller.go (about)

     1  /*
     2  Copyright 2021.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package blockdevice
    18  
    19  import (
    20  	"context"
    21  	util2 "github.com/openebs/node-disk-manager/pkg/controllers/util"
    22  
    23  	"github.com/go-logr/logr"
    24  	corev1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/errors"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/client-go/tools/record"
    28  	"k8s.io/klog/v2"
    29  	ctrl "sigs.k8s.io/controller-runtime"
    30  	"sigs.k8s.io/controller-runtime/pkg/client"
    31  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    32  
    33  	apis "github.com/openebs/node-disk-manager/api/v1alpha1"
    34  	ndm "github.com/openebs/node-disk-manager/cmd/ndm_daemonset/controller"
    35  	"github.com/openebs/node-disk-manager/pkg/cleaner"
    36  	"github.com/openebs/node-disk-manager/pkg/util"
    37  )
    38  
    39  // BlockDeviceReconciler reconciles a BlockDevice object
    40  type BlockDeviceReconciler struct {
    41  	Client   client.Client
    42  	Log      logr.Logger
    43  	Scheme   *runtime.Scheme
    44  	Recorder record.EventRecorder
    45  }
    46  
    47  //+kubebuilder:rbac:groups=openebs.io,resources=blockdevices,verbs=get;list;watch;create;update;patch;delete
    48  //+kubebuilder:rbac:groups=openebs.io,resources=blockdevices/status,verbs=get;update;patch
    49  //+kubebuilder:rbac:groups=openebs.io,resources=blockdevices/finalizers,verbs=update
    50  
    51  // Reconcile is part of the main kubernetes reconciliation loop which aims to
    52  // move the current state of the cluster closer to the desired state.
    53  // For more details, check Reconcile and its Result here:
    54  // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.2/pkg/reconcile
    55  func (r *BlockDeviceReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
    56  	// Fetch the BlockDevice instance
    57  	instance := &apis.BlockDevice{}
    58  	err := r.Client.Get(context.TODO(), request.NamespacedName, instance)
    59  	if err != nil {
    60  		if errors.IsNotFound(err) {
    61  			// Requested object not found, could have been deleted after reconcile request.
    62  			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
    63  			// Return and don't requeue
    64  			return reconcile.Result{}, nil
    65  		}
    66  		// Error reading the object - requeue the request.
    67  		return reconcile.Result{}, err
    68  	}
    69  
    70  	// check if the this block device need to reconciled
    71  	if IsReconcileDisabled(instance) {
    72  		return reconcile.Result{}, nil
    73  	}
    74  
    75  	switch instance.Status.ClaimState {
    76  	case apis.BlockDeviceReleased:
    77  		klog.V(2).Infof("%s is in Released state", instance.Name)
    78  		jobController := cleaner.NewJobController(r.Client, request.Namespace)
    79  		cleanupTracker := &cleaner.CleanupStatusTracker{JobController: jobController}
    80  		bdCleaner := cleaner.NewCleaner(r.Client, request.Namespace, cleanupTracker)
    81  		ok, err := bdCleaner.Clean(instance)
    82  		if err != nil {
    83  			klog.Errorf("Error while cleaning %s: %v", instance.Name, err)
    84  			r.Recorder.Eventf(instance, corev1.EventTypeWarning, "BlockDeviceCleanUp", "CleanUp unsuccessful, due to error: %v", err)
    85  			break
    86  		}
    87  		if ok {
    88  			r.Recorder.Eventf(instance, corev1.EventTypeNormal, "BlockDeviceReleased", "CleanUp Completed")
    89  			// remove the finalizer string from BlockDevice resource
    90  			instance.Finalizers = util.RemoveString(instance.Finalizers, util2.BlockDeviceFinalizer)
    91  			klog.Infof("Cleanup completed for %s", instance.Name)
    92  			err := r.updateBDStatus(apis.BlockDeviceUnclaimed, instance)
    93  			if err != nil {
    94  				klog.Errorf("Failed to mark %s as Unclaimed: %v", instance.Name, err)
    95  			}
    96  			r.Recorder.Eventf(instance, corev1.EventTypeNormal, "BlockDeviceUnclaimed", "BD now marked as Unclaimed")
    97  		} else {
    98  			r.Recorder.Eventf(instance, corev1.EventTypeNormal, "BlockDeviceCleanUpInProgress", "CleanUp is in progress")
    99  		}
   100  	case apis.BlockDeviceClaimed:
   101  		if !util.Contains(instance.GetFinalizers(), util2.BlockDeviceFinalizer) {
   102  			// finalizer is not present, may be a BlockDevice claimed from previous release
   103  			instance.Finalizers = append(instance.Finalizers, util2.BlockDeviceFinalizer)
   104  			err := r.Client.Update(context.TODO(), instance)
   105  			if err != nil {
   106  				klog.Errorf("Error updating finalizer on %s: %v", instance.Name, err)
   107  			}
   108  			klog.Infof("%s updated with %s finalizer", instance.Name, util2.BlockDeviceFinalizer)
   109  			r.Recorder.Eventf(instance, corev1.EventTypeNormal, "BlockDeviceClaimed", "BD Claimed, and finalizer added")
   110  		}
   111  		// if finalizer is already present. do nothing
   112  	}
   113  
   114  	return reconcile.Result{}, nil
   115  }
   116  
   117  // SetupWithManager sets up the controller with the Manager.
   118  func (r *BlockDeviceReconciler) SetupWithManager(mgr ctrl.Manager) error {
   119  	return ctrl.NewControllerManagedBy(mgr).
   120  		For(&apis.BlockDevice{}).
   121  		Owns(&apis.BlockDevice{}).
   122  		Complete(r)
   123  }
   124  
   125  func (r *BlockDeviceReconciler) updateBDStatus(state apis.DeviceClaimState, instance *apis.BlockDevice) error {
   126  	instance.Status.ClaimState = state
   127  	err := r.Client.Update(context.TODO(), instance)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return nil
   132  }
   133  
   134  // IsReconcileDisabled is used to check if reconciliation is disabled for
   135  // BlockDevice
   136  func IsReconcileDisabled(bd *apis.BlockDevice) bool {
   137  	return bd.Annotations[ndm.OpenEBSReconcile] == "false"
   138  }