| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package jobruntime |
| 4 | |
| 5 | import ( |
| 6 | "maps" |
| 7 | "sort" |
| 8 | |
| 9 | "github.com/netdata/netdata/go/plugins/pkg/netdataapi" |
| 10 | "github.com/netdata/netdata/go/plugins/plugin/framework/chartengine" |
| 11 | "github.com/netdata/netdata/go/plugins/plugin/framework/vnodes" |
| 12 | ) |
| 13 | |
| 14 | type jobV2CleanupSnapshot struct { |
| 15 | scopeKey string |
| 16 | charts map[string]chartengine.ChartMeta |
| 17 | host jobV2HostRef |
| 18 | staleVnodeSuppressed bool |
| 19 | } |
| 20 | |
| 21 | func (s *jobV2HostState) captureCleanupSnapshot(vnode vnodes.VirtualNode, allowStaleVnodeSuppression bool) jobV2CleanupSnapshot { |
| 22 | if s == nil { |
| 23 | return jobV2CleanupSnapshot{} |
| 24 | } |
| 25 | host := s.cleanupOwner |
| 26 | return jobV2CleanupSnapshot{ |
| 27 | charts: maps.Clone(s.cleanupCharts), |
| 28 | host: host, |
| 29 | staleVnodeSuppressed: allowStaleVnodeSuppression && shouldSuppressCleanupForStaleVnode(host, vnode), |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | func (j *JobV2) captureScopeCleanupSnapshots() []jobV2CleanupSnapshot { |
| 34 | if j == nil || len(j.scopeStates) == 0 { |
| 35 | return nil |
| 36 | } |
| 37 | vnode := j.currentVnode() |
| 38 | keys := sortedScopeStateKeys(j.scopeStates) |
| 39 | |
| 40 | snapshots := make([]jobV2CleanupSnapshot, 0, len(keys)) |
| 41 | for _, key := range keys { |
| 42 | state := j.scopeStates[key] |
| 43 | if state == nil { |
| 44 | continue |
| 45 | } |
| 46 | snapshot := state.host.captureCleanupSnapshot(vnode, key == defaultHostScopeKey) |
| 47 | snapshot.scopeKey = key |
| 48 | snapshots = append(snapshots, snapshot) |
| 49 | } |
| 50 | return snapshots |
| 51 | } |
| 52 | |
| 53 | func (j *JobV2) releaseAllScopeRegistryOwners() { |
| 54 | if j == nil { |
| 55 | return |
| 56 | } |
| 57 | for _, state := range j.scopeStates { |
| 58 | if state != nil { |
| 59 | state.host.releaseRegistryOwners(j.vnodeRegistry) |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | func (j *JobV2) clearAllScopeStateAfterCleanup() { |
| 65 | if j == nil { |
| 66 | return |
| 67 | } |
| 68 | for _, state := range j.scopeStates { |
| 69 | if state != nil { |
| 70 | state.host.clearAfterCleanup() |
| 71 | } |
| 72 | } |
| 73 | clear(j.scopeStates) |
| 74 | } |
| 75 | |
| 76 | func (s *jobV2HostState) clearAfterCleanup() { |
| 77 | if s == nil { |
| 78 | return |
| 79 | } |
| 80 | clear(s.cleanupCharts) |
| 81 | s.definedHost = jobV2HostRef{} |
| 82 | s.definedInfo = netdataapi.HostInfo{} |
| 83 | s.engineHost = jobV2HostRef{} |
| 84 | s.cleanupOwner = jobV2HostRef{} |
| 85 | } |
| 86 | |
| 87 | func buildJobV2CleanupPlan(charts map[string]chartengine.ChartMeta) chartengine.Plan { |
| 88 | if len(charts) == 0 { |
| 89 | return chartengine.Plan{} |
| 90 | } |
| 91 | |
| 92 | chartIDs := make([]string, 0, len(charts)) |
| 93 | for chartID := range charts { |
| 94 | chartIDs = append(chartIDs, chartID) |
| 95 | } |
| 96 | sort.Strings(chartIDs) |
| 97 | |
| 98 | actions := make([]chartengine.EngineAction, 0, len(chartIDs)) |
| 99 | for _, chartID := range chartIDs { |
| 100 | actions = append(actions, chartengine.RemoveChartAction{ |
| 101 | ChartID: chartID, |
| 102 | Meta: charts[chartID], |
| 103 | }) |
| 104 | } |
| 105 | return chartengine.Plan{Actions: actions} |
| 106 | } |
| 107 | |
| 108 | func shouldSuppressCleanupForStaleVnode(cleanupHost jobV2HostRef, vnode vnodes.VirtualNode) bool { |
| 109 | return cleanupHost.isVnode() && |
| 110 | vnode.GUID == cleanupHost.guid && |
| 111 | vnode.Labels["_node_stale_after_seconds"] != "" |
| 112 | } |