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
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
75 func (c *GenericController) reconcilePlugins(ctx context.Context, ien *v1ien.IENode, object client.Object) (bool, internal.ReconcileTimeSet) {
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
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
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
111
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
127
128
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
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