...

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

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

     1  package nodeagent
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/go-logr/logr"
     8  
     9  	corev1 "k8s.io/api/core/v1"
    10  	"k8s.io/apimachinery/pkg/types"
    11  	kuberecorder "k8s.io/client-go/tools/record"
    12  	ctrl "sigs.k8s.io/controller-runtime"
    13  	"sigs.k8s.io/controller-runtime/pkg/client"
    14  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    15  
    16  	ctrlReconcile "edge-infra.dev/pkg/k8s/runtime/controller/reconcile"
    17  	"edge-infra.dev/pkg/lib/pprof"
    18  	"edge-infra.dev/pkg/sds/ien"
    19  
    20  	"edge-infra.dev/pkg/k8s/meta/status"
    21  	"edge-infra.dev/pkg/k8s/runtime/conditions"
    22  	"edge-infra.dev/pkg/k8s/runtime/controller/metrics"
    23  	controllerReconciler "edge-infra.dev/pkg/k8s/runtime/controller/reconcile"
    24  	"edge-infra.dev/pkg/k8s/runtime/events"
    25  	"edge-infra.dev/pkg/k8s/runtime/patch"
    26  
    27  	"edge-infra.dev/pkg/k8s/runtime/controller"
    28  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    29  
    30  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config"
    31  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/internal"
    32  )
    33  
    34  var (
    35  	sdsNamespace = "sds"
    36  	ienctlName   = "ienctl"
    37  	RequeueTime  = time.Minute * 2
    38  	RootPath     = "/"
    39  )
    40  
    41  // IENodeConditions defines the IENode status conditions owned by the nodeagent
    42  // and how these conditions should be considered when determining overall
    43  // readiness via the Ready condition.
    44  var IENodeConditions = controllerReconciler.Conditions{
    45  	Target: status.ReadyCondition,
    46  	Owned: []string{
    47  		string(v1ien.IENController),
    48  	},
    49  	Summarize: []string{
    50  		string(v1ien.IENController),
    51  	},
    52  	NegativePolarity: []string{},
    53  }
    54  
    55  // Controller represents a nodeagent controller.
    56  type Controller struct {
    57  	client.Client
    58  	kuberecorder.EventRecorder
    59  	Log         logr.Logger
    60  	Name        string
    61  	RequeueTime time.Duration
    62  	Config      config.Config
    63  	Conditions  controllerReconciler.Conditions
    64  	Metrics     metrics.Metrics
    65  	*v1ien.IENode
    66  }
    67  
    68  // Run registers and starts all controllers
    69  func Run(flags config.Flags, opts ...controller.Option) error {
    70  	log := ctrl.Log
    71  
    72  	if flags.Pprof != nil && *flags.Pprof {
    73  		log.Info("serving pprof on /debug/pprof/")
    74  		opts = append(opts, controller.WithPProf("/", pprof.Router()))
    75  	}
    76  
    77  	cmgr, err := createControllerManager(opts...)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	eventRecorder := events.NewRecorder(cmgr, ctrl.Log, "nodeagent")
    83  	mgr, err := registerControllers(flags, cmgr, eventRecorder)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
    89  		log.Error(err, "problem running manager")
    90  		return err
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  // summarizer summarizes the results of the plugin reconciliations and patches
    97  // the status conditions to the IENode resource.
    98  func (c *Controller) Summarizer(ctx context.Context, patcher *patch.SerialPatcher, result ctrlReconcile.Result) (res ctrl.Result, recErr error) {
    99  	s := controllerReconciler.NewSummarizer(patcher)
   100  	return s.SummarizeAndPatch(ctx, c.IENode,
   101  		controllerReconciler.WithConditions(c.Conditions),
   102  		controllerReconciler.WithResult(result),
   103  		controllerReconciler.WithError(recErr),
   104  		controllerReconciler.WithIgnoreNotFound(),
   105  		controllerReconciler.WithProcessors(
   106  			controllerReconciler.RecordReconcileReq,
   107  			controllerReconciler.RecordResult,
   108  		),
   109  		controllerReconciler.WithFieldOwner(c.Name),
   110  		controllerReconciler.WithEventRecorder(c.EventRecorder),
   111  	)
   112  }
   113  
   114  // registerControllers creates the required nodeagent controllers with their
   115  // associated plugins and registers them to the manager.
   116  func registerControllers(flags config.Flags, mgr ctrl.Manager, eventRecorder kuberecorder.EventRecorder) (ctrl.Manager, error) {
   117  	cfg := config.NewConfig(mgr.GetClient(), mgr.GetAPIReader(), eventRecorder, flags)
   118  	metrics := metrics.New(mgr, "nodeagent",
   119  		metrics.WithSuspend(),
   120  		metrics.WithCollectors(
   121  			internal.NodeAgentReadinessMetric,
   122  			internal.NodeAgentDurationMetric,
   123  		),
   124  	)
   125  
   126  	// setup ienode controller
   127  	ienctl := newIENController(mgr, cfg, metrics)
   128  	if err := setupIENControllerWithManager(&ienctl, mgr); err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	// setup fw controller
   133  	fwctl := newGenericController("fwctl", mgr, cfg, metrics, &v1ien.NodeFirewall{})
   134  	if err := setupNodeFirewallControllerWithManager(&fwctl, mgr); err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	// setup secret controller
   139  	secretctl := newGenericController("secretctl", mgr, cfg, metrics, &corev1.Secret{})
   140  	if err := setupWithManager(&secretctl, mgr, cfg.GetFlags()); err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	// setup config map controller
   145  	configctl := newGenericController("configctl", mgr, cfg, metrics, &corev1.ConfigMap{})
   146  	if err := setupWithManager(&configctl, mgr, cfg.GetFlags()); err != nil {
   147  		return nil, err
   148  	}
   149  	return mgr, nil
   150  }
   151  
   152  // createReconcileRequests ignores the input object and returns a reconciliation
   153  // request for the IENode resource for the current node.
   154  func (c *Controller) createReconcileRequests(_ context.Context, _ client.Object) []reconcile.Request {
   155  	hostname, err := ien.GetHostname()
   156  	if err != nil {
   157  		c.Log.Error(err, "error getting hostname for node")
   158  		return []reconcile.Request{}
   159  	}
   160  
   161  	return []reconcile.Request{
   162  		{
   163  			NamespacedName: types.NamespacedName{
   164  				Name: hostname,
   165  			},
   166  		},
   167  	}
   168  }
   169  
   170  // initializeControllerMetrics returns the controller metrics to be used for the
   171  // controller, with core information about the node such as the hostname, class,
   172  // IEN version and lane details injected.
   173  func (c *Controller) initializeControllerMetrics(ctx context.Context) (*internal.ControllerMetrics, error) {
   174  	hostname := c.IENode.ObjectMeta.GetName()
   175  	class := string(c.IENode.Spec.Class)
   176  
   177  	node := corev1.Node{}
   178  	err := c.Client.Get(ctx, client.ObjectKey{Name: hostname}, &node)
   179  	if err != nil {
   180  		c.Log.Error(err, "error getting node info")
   181  		return nil, err
   182  	}
   183  
   184  	ienVersion := node.ObjectMeta.Labels["feature.node.kubernetes.io/ien-version"]
   185  	lane := node.ObjectMeta.Labels["node.ncr.com/lane"]
   186  	return internal.CreateNewControllerMetrics(c.IENode, hostname, class, lane, ienVersion), nil
   187  }
   188  
   189  // isPluginEnabled will check if a plugin is enabled, record the plugin status
   190  func (c *Controller) isPluginEnabled(ctx context.Context, ien *v1ien.IENode, pluginName string) bool {
   191  	pluginEnabled, err := c.Config.IsPluginEnabled(ctx, pluginName)
   192  	if err != nil {
   193  		conditions.MarkUnknown(ien, pluginName, string(v1ien.PluginFailed), "error: %v", err)
   194  	}
   195  	if !pluginEnabled {
   196  		conditions.MarkTrue(ien, pluginName, string(v1ien.PluginDisabled), "%s", string(v1ien.Disabled))
   197  	}
   198  	return pluginEnabled
   199  }
   200  

View as plain text