...

Source file src/edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/generic_controller.go

Documentation: edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent

     1  package nodeagent
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"time"
     7  
     8  	ctrl "sigs.k8s.io/controller-runtime"
     9  	"sigs.k8s.io/controller-runtime/pkg/builder"
    10  	"sigs.k8s.io/controller-runtime/pkg/client"
    11  	"sigs.k8s.io/controller-runtime/pkg/predicate"
    12  
    13  	"maps"
    14  
    15  	"edge-infra.dev/pkg/k8s/runtime/conditions"
    16  	"edge-infra.dev/pkg/k8s/runtime/controller/metrics"
    17  	"edge-infra.dev/pkg/k8s/runtime/controller/reconcile"
    18  	"edge-infra.dev/pkg/k8s/runtime/patch"
    19  
    20  	"edge-infra.dev/pkg/sds/ien"
    21  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    22  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config"
    23  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/internal"
    24  )
    25  
    26  // Generic v1 controller (secrets, configmaps)
    27  type GenericController struct {
    28  	Controller
    29  	client.Object
    30  	Plugins map[string]Plugin
    31  }
    32  
    33  func (c *GenericController) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, recErr error) {
    34  	var (
    35  		result            reconcile.Result = reconcile.ResultEmpty
    36  		requeue           bool
    37  		reconcileDuration internal.ReconcileTimeSet
    38  		reconcileStartAt  = time.Now()
    39  	)
    40  
    41  	if err := c.Client.Get(ctx, req.NamespacedName, c.Object); err != nil {
    42  		return ctrl.Result{}, client.IgnoreNotFound(err)
    43  	}
    44  
    45  	ienode, err := c.Config.GetHostIENode(ctx)
    46  	if err != nil {
    47  		return ctrl.Result{RequeueAfter: c.RequeueTime}, err
    48  	}
    49  	c.IENode = ienode
    50  
    51  	metrics, err := c.initializeControllerMetrics(ctx)
    52  	if err != nil {
    53  		return ctrl.Result{RequeueAfter: c.RequeueTime}, err
    54  	}
    55  
    56  	patcher := patch.NewSerialPatcher(c.IENode, c.Client)
    57  	defer func() {
    58  		res, recErr = c.Summarizer(ctx, patcher, result)
    59  		metrics.RecordMetrics(reconcileDuration, time.Since(reconcileStartAt).Seconds())
    60  	}()
    61  
    62  	conditions.MarkFalse(c.IENode, string(v1ien.IENController), string(v1ien.Progressing), "%s", string(v1ien.Reconciling))
    63  
    64  	if requeue, reconcileDuration = c.reconcilePlugins(ctx, c.IENode, c.Object); requeue {
    65  		conditions.MarkFalse(c.IENode, string(v1ien.IENController), string(v1ien.Failed), "%s", string(v1ien.Requeueing))
    66  		result = reconcile.ResultRequeue
    67  		return
    68  	}
    69  
    70  	conditions.MarkTrue(c.IENode, string(v1ien.IENController), string(v1ien.Successful), "%s", string(v1ien.Succeeded))
    71  	return res, recErr
    72  }
    73  
    74  // reconcilePlugins iterates through all attached plugins and invokes them.
    75  func (c *GenericController) reconcilePlugins(ctx context.Context, ien *v1ien.IENode, object client.Object) (bool, internal.ReconcileTimeSet) { //nolint: dupl
    76  	requireRequeue := false
    77  	pluginReconcileTimes := make(internal.ReconcileTimeSet)
    78  	for name, plugin := range c.Plugins {
    79  		log := ctrl.LoggerFrom(ctx)
    80  		log = log.WithValues("plugin", name)
    81  
    82  		// check if plugin is enabled in config map
    83  		if !c.isPluginEnabled(ctx, ien, name) {
    84  			continue
    85  		}
    86  
    87  		pluginReconcileStart := time.Now()
    88  		err := plugin.Reconcile(ctx, object, c.Config)
    89  		pluginReconcileTimes[name] = time.Since(pluginReconcileStart).Seconds()
    90  		if err != nil {
    91  			log.Error(err, "failed to run plugin")
    92  			conditions.MarkFalse(ien, name, string(v1ien.PluginFailed), "%v", err)
    93  			requireRequeue = true
    94  			continue
    95  		}
    96  		conditions.MarkTrue(ien, name, string(v1ien.PluginSuccessful), "%s", string(v1ien.Succeeded))
    97  		log.V(1).Info("plugin ran successfully")
    98  	}
    99  	return requireRequeue, pluginReconcileTimes
   100  }
   101  
   102  // registers node agent conditions for GenericController
   103  func (c *GenericController) registerConditions() {
   104  	for pluginName := range maps.Keys(c.Plugins) {
   105  		IENodeConditions.Owned = append(IENodeConditions.Owned, pluginName)
   106  		IENodeConditions.Summarize = append(IENodeConditions.Summarize, pluginName)
   107  	}
   108  }
   109  
   110  // setupNodeFirewallControllerWithManager is the SetupWithManager function to
   111  // use when registering the NodeFirewall controller.
   112  func setupNodeFirewallControllerWithManager(c *GenericController, mgr ctrl.Manager) error {
   113  	hostname, err := ien.GetHostname()
   114  	if err != nil {
   115  		return err
   116  	}
   117  	return ctrl.NewControllerManagedBy(mgr).
   118  		For(&v1ien.NodeFirewall{}, builder.WithPredicates(
   119  			predicate.GenerationChangedPredicate{},
   120  			predicate.NewPredicateFuncs(func(obj client.Object) bool {
   121  				return strings.Contains(obj.GetName(), hostname)
   122  			}))).
   123  		Complete(c)
   124  }
   125  
   126  // setupWithManager is the generic SetupWithManager function to use when
   127  // registering a controller that just needs to reconcile on the it's defined
   128  // controller Object in the 'sds' namespace.
   129  func setupWithManager(c *GenericController, mgr ctrl.Manager, flags config.Flags) error {
   130  	if *flags.WatchAllNamespaces {
   131  		return ctrl.NewControllerManagedBy(mgr).
   132  			For(c.Object, builder.WithPredicates(predicate.ResourceVersionChangedPredicate{})).
   133  			Complete(c)
   134  	}
   135  	return ctrl.NewControllerManagedBy(mgr).
   136  		For(c.Object, builder.WithPredicates(predicate.ResourceVersionChangedPredicate{})).
   137  		WithEventFilter(predicate.NewPredicateFuncs(func(obj client.Object) bool {
   138  			return obj.GetNamespace() == sdsNamespace
   139  		})).
   140  		Complete(c)
   141  }
   142  
   143  // Instantiates a new generic controller
   144  func newGenericController(name string, mgr ctrl.Manager, conf config.Config, metrics metrics.Metrics, object client.Object) GenericController {
   145  	ctl := GenericController{
   146  		Plugins: GenericPlugins,
   147  		Object:  object,
   148  		Controller: Controller{
   149  			Client:      mgr.GetClient(),
   150  			Log:         ctrl.Log.WithName(name),
   151  			Name:        name,
   152  			Config:      conf,
   153  			RequeueTime: RequeueTime,
   154  			Conditions:  IENodeConditions,
   155  			Metrics:     metrics,
   156  		},
   157  	}
   158  	ctl.registerConditions()
   159  	return ctl
   160  }
   161  

View as plain text