@@ -26,6 +26,7 @@ import (
26
26
"github.com/jatalocks/kube-reqsizer/pkg/cache/localcache"
27
27
"github.com/jatalocks/kube-reqsizer/pkg/cache/rediscache"
28
28
"github.com/jatalocks/kube-reqsizer/types"
29
+ "github.com/prometheus/client_golang/prometheus"
29
30
corev1 "k8s.io/api/core/v1"
30
31
v1 "k8s.io/api/core/v1"
31
32
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -36,6 +37,7 @@ import (
36
37
37
38
ctrl "sigs.k8s.io/controller-runtime"
38
39
"sigs.k8s.io/controller-runtime/pkg/client"
40
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
39
41
)
40
42
41
43
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;update;patch
@@ -66,64 +68,90 @@ const (
66
68
operatorModeAnnotation = "reqsizer.jatalocks.github.io/mode"
67
69
)
68
70
71
+ var (
72
+ cpuOffset = prometheus .NewGauge (
73
+ prometheus.GaugeOpts {
74
+ Name : "cpu_offset" ,
75
+ Help : "Number of milli-cores that have been increased/removed since startup" ,
76
+ },
77
+ )
78
+ memoryOffset = prometheus .NewGauge (
79
+ prometheus.GaugeOpts {
80
+ Name : "memory_offset" ,
81
+ Help : "Number of megabits that have been increased/removed since startup" ,
82
+ },
83
+ )
84
+ cacheSize = prometheus .NewGauge (
85
+ prometheus.GaugeOpts {
86
+ Name : "cache_size" ,
87
+ Help : "Number of pod controllers currently in cache" ,
88
+ },
89
+ )
90
+ )
91
+
92
+ func init () {
93
+ // Register custom metrics with the global prometheus registry
94
+ metrics .Registry .MustRegister (cpuOffset , memoryOffset , cacheSize )
95
+ }
96
+
69
97
func cacheKeyFunc (obj interface {}) (string , error ) {
70
- return obj .(types.PodRequests ).Name + "-" + obj .(types. PodRequests ). Namespace , nil
98
+ return obj .(types.PodRequests ).Name , nil
71
99
}
72
100
73
101
var cacheStore = cache .NewStore (cacheKeyFunc )
74
102
75
103
// Reconcile handles a reconciliation request for a Pod.
76
104
func (r * PodReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
77
105
log := r .Log .WithValues ("pod" , req .NamespacedName )
78
-
106
+ if r .EnablePersistence {
107
+ cacheSize .Set (float64 (r .RedisClient .CacheSize ()))
108
+ } else {
109
+ cacheSize .Set (float64 (len (cacheStore .List ())))
110
+ }
79
111
/*
80
112
Step 0: Fetch the Pod from the Kubernetes API.
81
113
*/
82
-
83
114
var pod corev1.Pod
115
+
84
116
if err := r .Get (ctx , req .NamespacedName , & pod ); err != nil {
85
117
if apierrors .IsNotFound (err ) {
86
- // we'll ignore not-found errors, since they can't be fixed by an immediate
87
- // requeue (we'll need to wait for a new notification), and we can get them
88
- // on deleted requests.
89
118
return ctrl.Result {}, nil
90
119
}
91
120
log .Error (nil , "unable to fetch Pod" )
92
121
return ctrl.Result {}, err
93
122
}
94
-
95
- annotation , err := r .NamespaceOrPodHaveAnnotation (pod , ctx )
123
+ podReferenceName := r . GetPodCacheName ( & pod ) + "-" + pod . Namespace
124
+ annotation , err := r .NamespaceOrPodHaveAnnotation (& pod , ctx )
96
125
if err != nil {
97
126
log .Error (nil , "failed to get annotations" )
98
127
return ctrl.Result {}, err
99
128
}
100
- ignoreAnnotation , err := r .NamespaceOrPodHaveIgnoreAnnotation (pod , ctx )
129
+ ignoreAnnotation , err := r .NamespaceOrPodHaveIgnoreAnnotation (& pod , ctx )
101
130
if err != nil {
102
131
log .Error (nil , "failed to get annotations" )
103
132
return ctrl.Result {}, err
104
133
}
105
134
106
135
if ((! r .EnableAnnotation ) || (r .EnableAnnotation && annotation )) && ! ignoreAnnotation {
136
+ log .Info ("Cache Reference Name: " + podReferenceName )
137
+
107
138
data , err := r .ClientSet .RESTClient ().Get ().AbsPath (fmt .Sprintf ("apis/metrics.k8s.io/v1beta1/namespaces/%v/pods/%v" , pod .Namespace , pod .Name )).DoRaw (ctx )
108
139
109
140
if err != nil {
110
141
log .Error (nil , "failed to get stats from pod" )
111
142
return ctrl.Result {}, err
112
143
}
113
144
PodUsageData := GeneratePodRequestsObjectFromRestData (data )
114
- err , _ , _ , deploymentName := r .GetPodParentKind (pod , ctx )
115
- if err != nil {
116
- deploymentName = pod .Name
117
- }
118
- SumPodRequest := types.PodRequests {Name : deploymentName , Namespace : pod .Namespace , ContainerRequests : []types.ContainerRequests {}}
145
+ SumPodRequest := types.PodRequests {Name : podReferenceName , Namespace : pod .Namespace , ContainerRequests : []types.ContainerRequests {}}
119
146
120
147
SumPodRequest .ContainerRequests = PodUsageData .ContainerRequests
121
148
var LatestPodRequest types.PodRequests
122
149
if r .EnablePersistence {
123
- LatestPodRequest , err = r .RedisClient .FetchFromCache (deploymentName + "-" + pod . Namespace )
150
+ LatestPodRequest , err = r .RedisClient .FetchFromCache (podReferenceName )
124
151
} else {
125
- LatestPodRequest , err = localcache .FetchFromCache (cacheStore , deploymentName + "-" + pod . Namespace )
152
+ LatestPodRequest , err = localcache .FetchFromCache (cacheStore , podReferenceName )
126
153
}
154
+
127
155
if err != nil {
128
156
SumPodRequest .Sample = 0
129
157
log .Info (fmt .Sprint ("Adding cache sample " , SumPodRequest .Sample ))
@@ -184,7 +212,6 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
184
212
}
185
213
}
186
214
}
187
- log .Info (fmt .Sprint (SumPodRequest ))
188
215
if (SumPodRequest .Sample >= r .SampleSize ) && r .MinimumUptimeOfPodInParent (pod , ctx ) {
189
216
log .Info ("Sample Size and Minimum Time have been reached" )
190
217
PodChange := false
@@ -216,28 +243,34 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
216
243
case "average" :
217
244
if r .ValidateCPU (currentC .CPU , AverageUsageCPU ) {
218
245
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceCPU ] = resource .MustParse (fmt .Sprintf ("%dm" , int (float64 (AverageUsageCPU )* r .CPUFactor )))
246
+ cpuOffset .Add (float64 (int (float64 (AverageUsageCPU )* r .CPUFactor ) - int (currentC .CPU )))
219
247
PodChange = true
220
248
}
221
249
if r .ValidateMemory (currentC .Memory , AverageUsageMemory ) {
222
250
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceMemory ] = resource .MustParse (fmt .Sprintf ("%dMi" , int (float64 (AverageUsageMemory )* r .MemoryFactor )))
251
+ memoryOffset .Add (float64 (int (float64 (AverageUsageMemory )* r .MemoryFactor ) - int (currentC .Memory )))
223
252
PodChange = true
224
253
}
225
254
case "min" :
226
255
if r .ValidateCPU (currentC .CPU , c .MinCPU ) {
227
256
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceCPU ] = resource .MustParse (fmt .Sprintf ("%dm" , int (float64 (c .MinCPU )* r .CPUFactor )))
257
+ cpuOffset .Add (float64 (int (float64 (c .MinCPU )* r .CPUFactor ) - int (currentC .CPU )))
228
258
PodChange = true
229
259
}
230
260
if r .ValidateMemory (currentC .Memory , c .MinMemory ) {
231
261
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceMemory ] = resource .MustParse (fmt .Sprintf ("%dMi" , int (float64 (c .MinMemory )* r .MemoryFactor )))
262
+ memoryOffset .Add (float64 (int (float64 (c .MinMemory )* r .MemoryFactor ) - int (currentC .Memory )))
232
263
PodChange = true
233
264
}
234
265
case "max" :
235
266
if r .ValidateCPU (currentC .CPU , c .MaxCPU ) {
236
267
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceCPU ] = resource .MustParse (fmt .Sprintf ("%dm" , int (float64 (c .MaxCPU )* r .CPUFactor )))
268
+ cpuOffset .Add (float64 (int (float64 (c .MaxCPU )* r .CPUFactor ) - int (currentC .CPU )))
237
269
PodChange = true
238
270
}
239
271
if r .ValidateMemory (currentC .Memory , c .MaxMemory ) {
240
272
pod .Spec .Containers [i ].Resources .Requests [v1 .ResourceMemory ] = resource .MustParse (fmt .Sprintf ("%dMi" , int (float64 (c .MaxMemory )* r .MemoryFactor )))
273
+ memoryOffset .Add (float64 (int (float64 (c .MaxMemory )* r .MemoryFactor ) - int (currentC .Memory )))
241
274
PodChange = true
242
275
}
243
276
}
@@ -249,6 +282,15 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
249
282
}
250
283
}
251
284
}
285
+ if r .EnablePersistence {
286
+ if err := r .RedisClient .DeleteFromCache (SumPodRequest ); err != nil {
287
+ log .Error (err , err .Error ())
288
+ }
289
+ } else {
290
+ if err := localcache .DeleteFromCache (cacheStore , LatestPodRequest ); err != nil {
291
+ log .Error (err , err .Error ())
292
+ }
293
+ }
252
294
if PodChange {
253
295
pod .Annotations ["reqsizer.jatalocks.github.io/changed" ] = "true"
254
296
@@ -267,20 +309,9 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
267
309
UpdatePodController (podSpec , Requests , ctx )
268
310
269
311
return r .UpdateKubeObject (deployment .(client.Object ), ctx )
270
-
271
- }
272
-
273
- if r .EnablePersistence {
274
- if err := r .RedisClient .DeleteFromCache (SumPodRequest ); err != nil {
275
- log .Error (err , err .Error ())
276
- }
277
- } else {
278
- if err := localcache .DeleteFromCache (cacheStore , LatestPodRequest ); err != nil {
279
- log .Error (err , err .Error ())
280
- }
281
312
}
282
313
}
283
314
}
284
315
285
- return ctrl.Result {RequeueAfter : 10 * time .Second }, nil
316
+ return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
286
317
}
0 commit comments