@cryptotaxi247 / netdata-1 / commits / aed408ec4

improvement(go.d/k8state): add CronJob suspend status (#19829)

* improvement(go.d/k8state): add CronJob suspend status * fix tests

Ilya Mashchenko committed Mar 12, 2025 at 14:03 UTC aed408ec41f996d437f2493713da9d47ae78d181
6 files changed +54 -2
src/go/plugin/go.d/collector/k8s_state/charts.go
+15
@@ -68,6 +68,7 @@ const (
68 prioCronJobLastCompletionDuration
69 prioCronJobLastCompletedTimeAgo
70 prioCronJobLastScheduleTimeAgo
71 + prioCronJobSuspendStatus
72 prioCronJobAge
73 )
74
@@ -153,6 +154,7 @@ var cronJobChartsTmpl = module.Charts{
154 cronJobLastCompletionDurationChartTmpl.Copy(),
155 cronJobLastCompletedTimeAgoChartTmpl.Copy(),
156 cronJobLastScheduleTimeAgoChartTmpl.Copy(),
157 + cronJobSuspendStatusChartTmpl.Copy(),
158 cronJobAgeChartTmpl.Copy(),
159 }
160
@@ -929,6 +931,19 @@ var (
931 {ID: "cronjob_%s_last_schedule_seconds_ago", Name: "last_schedule_ago"},
932 },
933 }
934 + cronJobSuspendStatusChartTmpl = module.Chart{
935 + IDSep: true,
936 + ID: "cronjob_%s.suspend_status",
937 + Title: "CronJob Suspend Status",
938 + Units: "status",
939 + Fam: "cronjob status",
940 + Ctx: "k8s_state.cronjob_suspend_status",
941 + Priority: prioCronJobSuspendStatus,
942 + Dims: module.Dims{
943 + {ID: "cronjob_%s_suspend_status_enabled", Name: "enabled"},
944 + {ID: "cronjob_%s_suspend_status_suspended", Name: "suspended"},
945 + },
946 + }
947 cronJobAgeChartTmpl = module.Chart{
948 IDSep: true,
949 ID: "cronjob_%s.age",
src/go/plugin/go.d/collector/k8s_state/collect.go
+3
@@ -388,6 +388,9 @@ func (c *Collector) collectCronJobState(mx map[string]int64) {
388 mx[px+"complete_jobs"] = 0
389 mx[px+"suspended_jobs"] = 0
390
391 + mx[px+"suspend_status_enabled"] = metrix.Bool(!st.suspend)
392 + mx[px+"suspend_status_suspended"] = metrix.Bool(st.suspend)
393 +
394 mx[px+"failed_jobs_reason_pod_failure_policy"] = 0
395 mx[px+"failed_jobs_reason_backoff_limit_exceeded"] = 0
396 mx[px+"failed_jobs_reason_deadline_exceeded"] = 0
src/go/plugin/go.d/collector/k8s_state/collector_test.go
+23 -2
@@ -515,6 +515,8 @@ func TestCollector_Collect(t *testing.T) {
515 "CronJobs": {
516 create: func(t *testing.T) testCase {
517 cj := prepareCronJob("cronjob01")
518 + cjSuspended := prepareCronJob("cronjob02")
519 + cjSuspended.Spec.Suspend = ptr(true)
520 jobNotStarted := prepareCronJobNotStartedJob("job-not-started", cj)
521 jobComplete := prepareCronJobCompleteJob("job-complete", cj)
522 jobFailed := prepareCronJobFailedJob("job-failed", cj)
@@ -522,6 +524,7 @@ func TestCollector_Collect(t *testing.T) {
524 jobSuspended := prepareCronJobSuspendedJob("job-suspended", cj)
525
526 client := fake.NewClientset(
527 + cjSuspended,
528 cj,
529 jobNotStarted,
530 jobComplete,
@@ -545,7 +548,23 @@ func TestCollector_Collect(t *testing.T) {
548 "cronjob_default_cronjob01_last_schedule_seconds_ago": 130,
549 "cronjob_default_cronjob01_last_successful_seconds_ago": 70,
550 "cronjob_default_cronjob01_running_jobs": 1,
551 + "cronjob_default_cronjob01_suspend_status_enabled": 1,
552 + "cronjob_default_cronjob01_suspend_status_suspended": 0,
553 "cronjob_default_cronjob01_suspended_jobs": 1,
554 + "cronjob_default_cronjob02_age": 10,
555 + "cronjob_default_cronjob02_complete_jobs": 0,
556 + "cronjob_default_cronjob02_failed_jobs": 0,
557 + "cronjob_default_cronjob02_failed_jobs_reason_backoff_limit_exceeded": 0,
558 + "cronjob_default_cronjob02_failed_jobs_reason_deadline_exceeded": 0,
559 + "cronjob_default_cronjob02_failed_jobs_reason_pod_failure_policy": 0,
560 + "cronjob_default_cronjob02_last_execution_status_failed": 0,
561 + "cronjob_default_cronjob02_last_execution_status_succeeded": 0,
562 + "cronjob_default_cronjob02_last_schedule_seconds_ago": 130,
563 + "cronjob_default_cronjob02_last_successful_seconds_ago": 70,
564 + "cronjob_default_cronjob02_running_jobs": 0,
565 + "cronjob_default_cronjob02_suspend_status_enabled": 0,
566 + "cronjob_default_cronjob02_suspend_status_suspended": 1,
567 + "cronjob_default_cronjob02_suspended_jobs": 0,
568 "discovery_node_discoverer_state": 1,
569 "discovery_pod_discoverer_state": 1,
570 }
@@ -554,11 +573,13 @@ func TestCollector_Collect(t *testing.T) {
573
574 assert.Equal(t, expected, mx)
575 assert.Equal(t,
557 - len(cronJobChartsTmpl)+
576 + len(cronJobChartsTmpl)*2+
577 len(baseCharts),
578 len(*collr.Charts()),
579 )
561 - module.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
580 + module.TestMetricsHasAllChartsDimsSkip(t, collr.Charts(), mx, func(chart *module.Chart, dim *module.Dim) bool {
581 + return strings.Contains(chart.ID, cjSuspended.Name) && strings.HasSuffix(chart.ID, "last_completion_duration")
582 + })
583 }
584
585 return testCase{
src/go/plugin/go.d/collector/k8s_state/metadata.yaml
+7
@@ -309,6 +309,13 @@ modules:
309 chart_type: line
310 dimensions:
311 - name: last_schedule_ago
312 + - name: k8s_state.cronjob_suspend_status
313 + description: CronJob Suspend Status
314 + unit: 'status'
315 + chart_type: line
316 + dimensions:
317 + - name: enabled
318 + - name: suspended
319 - name: k8s_state.cronjob_age
320 description: CronJob Age
321 unit: 'seconds'
src/go/plugin/go.d/collector/k8s_state/state.go
+1
@@ -203,6 +203,7 @@ type cronJobState struct {
203 namespace string
204 creationTime time.Time
205
206 + suspend bool
207 lastScheduleTime *time.Time
208 lastSuccessfulTime *time.Time
209 }
src/go/plugin/go.d/collector/k8s_state/update_cronjob_state.go
+5
@@ -27,6 +27,11 @@ func (c *Collector) updateCronJobState(r resource) {
27 st.creationTime = cj.CreationTimestamp.Time
28 }
29
30 + st.suspend = false
31 + if cj.Spec.Suspend != nil {
32 + st.suspend = *cj.Spec.Suspend
33 + }
34 +
35 st.lastScheduleTime = nil
36 st.lastSuccessfulTime = nil
37