Skip to content

Commit

Permalink
Eviction controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Arvindthiru committed Oct 31, 2024
1 parent cb9a7a0 commit 4fd013b
Showing 1 changed file with 133 additions and 0 deletions.
133 changes: 133 additions & 0 deletions pkg/controllers/clusterresourceplacementeviction/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package clusterresourceplacementeviction

import (
"context"
"time"

placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
"go.goms.io/fleet/pkg/utils/controller"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
runtime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
ctrl "sigs.k8s.io/controller-runtime/pkg/controller"

placementv1alpha1 "go.goms.io/fleet/apis/placement/v1alpha1"
)

const (
reasonClusterResourcePlacementEvictionValid = "ClusterResourcePlacementEvictionValid"
reasonClusterResourcePlacementEvictionInvalid = "ClusterResourcePlacementEvictionInvalid"
)

// Reconciler reconciles a MemberCluster object
type Reconciler struct {
client.Client
}

func (r *Reconciler) Reconcile(ctx context.Context, req runtime.Request) (runtime.Result, error) {
startTime := time.Now()
klog.V(2).InfoS("ClusterResourcePlacementEviction reconciliation starts", "clusterResourcePlacementEviction", req.NamespacedName)
defer func() {
latency := time.Since(startTime).Milliseconds()
klog.V(2).InfoS("ClusterResourcePlacementEviction reconciliation ends", "clusterResourcePlacementEviction", req.NamespacedName, "latency", latency)
}()

var eviction placementv1alpha1.ClusterResourcePlacementEviction
if err := r.Client.Get(ctx, req.NamespacedName, &eviction); err != nil {
klog.ErrorS(err, "Failed to get cluster resource placement eviction", "clusterResourcePlacementEviction", req.NamespacedName)
return runtime.Result{}, client.IgnoreNotFound(err)
}

isCRPPresent := true
var crp placementv1beta1.ClusterResourcePlacement
if err := r.Client.Get(ctx, types.NamespacedName{Name: eviction.Spec.PlacementName}, &crp); err != nil {
if errors.IsNotFound(err) {
isCRPPresent = false

Check failure on line 49 in pkg/controllers/clusterresourceplacementeviction/controller.go

View workflow job for this annotation

GitHub Actions / Lint

ineffectual assignment to isCRPPresent (ineffassign)
}
return runtime.Result{}, err
}

if !isCRPPresent {
klog.V(2).InfoS("Failed to find cluster resource placement targeted by eviction", "clusterResourcePlacementEviction", req.NamespacedName, "clusterResourcePlacement", eviction.Spec.PlacementName)
// mark eviction as invalid.
markEvictionInvalid(&eviction)
if err := r.updateEvictionStatus(ctx, &eviction); err != nil {
klog.ErrorS(err, "Failed to update eviction status as invalid", "clusterResourcePlacementEviction", req.NamespacedName)
return runtime.Result{}, err
}
}

var crbList placementv1beta1.ClusterResourceBindingList
if err := r.Client.List(ctx, &crbList, client.MatchingLabels{placementv1beta1.CRPTrackingLabel: crp.Name}); err != nil {
return runtime.Result{}, err
}

var evictionTargetBinding *placementv1beta1.ClusterResourceBinding
for i := range crbList.Items {
if crbList.Items[i].Spec.TargetCluster == eviction.Spec.ClusterName {
evictionTargetBinding = &crbList.Items[i]
}
}

if evictionTargetBinding == nil {
klog.V(2).InfoS("Failed to find cluster resource binding for cluster targeted by eviction", "clusterResourcePlacementEviction", req.NamespacedName, "clusterName", eviction.Spec.ClusterName)
// mark eviction as invalid.
markEvictionInvalid(&eviction)
if err := r.updateEvictionStatus(ctx, &eviction); err != nil {
klog.ErrorS(err, "Failed to update eviction status as invalid", "clusterResourcePlacementEviction", req.NamespacedName)
return runtime.Result{}, err
}
}

// mark eviction as valid.
markEvictionValid(&eviction)
if err := r.updateEvictionStatus(ctx, &eviction); err != nil {
klog.ErrorS(err, "Failed to update eviction status as valid", "clusterResourcePlacementEviction", req.NamespacedName)
return runtime.Result{}, err
}

// TODO: Get PDB and check if eviction is allowed.

return runtime.Result{}, nil
}

func (r *Reconciler) updateEvictionStatus(ctx context.Context, eviction *placementv1alpha1.ClusterResourcePlacementEviction) error {
if err := r.Client.Status().Update(ctx, eviction); err != nil {
klog.ErrorS(err, "Failed to update eviction status", "clusterResourcePlacementEviction", klog.KObj(eviction))
return controller.NewUpdateIgnoreConflictError(err)
}
klog.V(2).InfoS("Updated the status of a eviction", "clusterResourcePlacementEviction", klog.KObj(eviction))
return nil
}

func markEvictionValid(eviction *placementv1alpha1.ClusterResourcePlacementEviction) {
cond := metav1.Condition{
Type: string(placementv1alpha1.PlacementEvictionConditionTypeValid),
Status: metav1.ConditionTrue,
ObservedGeneration: eviction.Generation,
Reason: reasonClusterResourcePlacementEvictionValid,
}
meta.SetStatusCondition(&eviction.Status.Conditions, cond)
}

func markEvictionInvalid(eviction *placementv1alpha1.ClusterResourcePlacementEviction) {
cond := metav1.Condition{
Type: string(placementv1alpha1.PlacementEvictionConditionTypeValid),
Status: metav1.ConditionFalse,
ObservedGeneration: eviction.Generation,
Reason: reasonClusterResourcePlacementEvictionInvalid,
}
meta.SetStatusCondition(&eviction.Status.Conditions, cond)
}

// SetupWithManager sets up the controller with the Manager.
func (r *Reconciler) SetupWithManager(mgr runtime.Manager) error {
return runtime.NewControllerManagedBy(mgr).
WithOptions(ctrl.Options{MaxConcurrentReconciles: 1}). // set the max number of concurrent reconciles
For(&placementv1alpha1.ClusterResourcePlacementEviction{}).
Complete(r)
}

0 comments on commit 4fd013b

Please sign in to comment.