From 7d2df8a6b68b60c450fba0cce11ff934d504f1a5 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Tue, 10 Mar 2026 20:29:35 +0300 Subject: [PATCH 1/3] wip Signed-off-by: Daniil Loktev --- .../cmd/virtualization-controller/main.go | 4 + .../pkg/config/load_gc_settings.go | 9 ++ .../pkg/controller/vm/pod_gc.go | 104 ++++++++++++++++++ .../virtualization-controller/_helpers.tpl | 4 + 4 files changed, 121 insertions(+) create mode 100644 images/virtualization-artifact/pkg/controller/vm/pod_gc.go diff --git a/images/virtualization-artifact/cmd/virtualization-controller/main.go b/images/virtualization-artifact/cmd/virtualization-controller/main.go index f1a685a130..45bbc5efcc 100644 --- a/images/virtualization-artifact/cmd/virtualization-controller/main.go +++ b/images/virtualization-artifact/cmd/virtualization-controller/main.go @@ -355,6 +355,10 @@ func main() { log.Error(err.Error()) os.Exit(1) } + if err = vm.SetupPodGC(mgr, vmLogger, gcSettings.VMPod); err != nil { + log.Error(err.Error()) + os.Exit(1) + } vmbdaLogger := logger.NewControllerLogger(vmbda.ControllerName, logLevel, logOutput, logDebugVerbosity, logDebugControllerList) if _, err = vmbda.NewController(ctx, mgr, virtClient, vmbdaLogger, controllerNamespace); err != nil { diff --git a/images/virtualization-artifact/pkg/config/load_gc_settings.go b/images/virtualization-artifact/pkg/config/load_gc_settings.go index 7cac99823f..c4eaf7b323 100644 --- a/images/virtualization-artifact/pkg/config/load_gc_settings.go +++ b/images/virtualization-artifact/pkg/config/load_gc_settings.go @@ -29,11 +29,14 @@ const ( GcVmopScheduleVar = "GC_VMOP_SCHEDULE" GcVMIMigrationTTLVar = "GC_VMI_MIGRATION_TTL" GcVMIMigrationScheduleVar = "GC_VMI_MIGRATION_SCHEDULE" + GcVMPodTTLVar = "GC_VM_POD_TTL" + GcVMPodScheduleVar = "GC_VM_POD_SCHEDULE" ) type GCSettings struct { VMOP BaseGcSettings VMIMigration BaseGcSettings + VMPod BaseGcSettings } type BaseGcSettings struct { @@ -55,6 +58,12 @@ func LoadGcSettings() (GCSettings, error) { } gcSettings.VMIMigration = base + base, err = GetBaseGCSettingsFromEnv(GcVMPodScheduleVar, GcVMPodTTLVar) + if err != nil { + return gcSettings, err + } + gcSettings.VMPod = base + return gcSettings, nil } diff --git a/images/virtualization-artifact/pkg/controller/vm/pod_gc.go b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go new file mode 100644 index 0000000000..df2173a6fa --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go @@ -0,0 +1,104 @@ +/* +Copyright 2025 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vm + +import ( + "context" + "time" + + corev1 "k8s.io/api/core/v1" + virtv1 "kubevirt.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/deckhouse/deckhouse/pkg/log" + "github.com/deckhouse/virtualization-controller/pkg/config" + "github.com/deckhouse/virtualization-controller/pkg/controller/gc" +) + +const gcPodControllerName = "vm-pod-gc-controller" + +func SetupPodGC(mgr manager.Manager, log *log.Logger, gcSettings config.BaseGcSettings) error { + podGCMgr := newPodGCManager(mgr.GetClient(), gcSettings.TTL.Duration, 10) + + return gc.SetupGcController(gcPodControllerName, + mgr, + log.With("resource", "vm-pod"), + gcSettings.Schedule, + podGCMgr, + ) +} + +func newPodGCManager(client client.Client, ttl time.Duration, max int) *podGCManager { + if ttl == 0 { + ttl = 24 * time.Hour + } + if max == 0 { + max = 10 + } + return &podGCManager{ + client: client, + ttl: ttl, + max: max, + } +} + +var _ gc.ReconcileGCManager = &podGCManager{} + +type podGCManager struct { + client client.Client + ttl time.Duration + max int +} + +func (m *podGCManager) New() client.Object { + return &corev1.Pod{} +} + +func (m *podGCManager) ShouldBeDeleted(obj client.Object) bool { + pod, ok := obj.(*corev1.Pod) + if !ok { + return false + } + if _, hasLabel := pod.Labels[virtv1.VirtualMachineNameLabel]; !hasLabel { + return false + } + return pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed +} + +func (m *podGCManager) ListForDelete(ctx context.Context, now time.Time) ([]client.Object, error) { + podList := &corev1.PodList{} + err := m.client.List(ctx, podList, client.HasLabels{virtv1.VirtualMachineNameLabel}) + if err != nil { + return nil, err + } + + objs := make([]client.Object, 0, len(podList.Items)) + for _, pod := range podList.Items { + objs = append(objs, &pod) + } + + return gc.DefaultFilter(objs, m.ShouldBeDeleted, m.ttl, m.getIndex, m.max, now), nil +} + +func (m *podGCManager) getIndex(obj client.Object) string { + pod, ok := obj.(*corev1.Pod) + if !ok { + return "" + } + return pod.Labels[virtv1.VirtualMachineNameLabel] +} diff --git a/templates/virtualization-controller/_helpers.tpl b/templates/virtualization-controller/_helpers.tpl index f88f153591..0f6ac0011f 100644 --- a/templates/virtualization-controller/_helpers.tpl +++ b/templates/virtualization-controller/_helpers.tpl @@ -84,6 +84,10 @@ true value: "24h" - name: GC_VMI_MIGRATION_SCHEDULE value: "0 0 * * *" +- name: GC_VM_POD_TTL + value: "24h" +- name: GC_VM_POD_SCHEDULE + value: "0 0 * * *" {{- if (hasKey .Values.virtualization.internal.moduleConfig "liveMigration") }} - name: LIVE_MIGRATION_BANDWIDTH_PER_NODE value: {{ .Values.virtualization.internal.moduleConfig.liveMigration.bandwidthPerNode | quote }} From 014ce0594f2a19bf4d9327d72a6bf1851ee66795 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 11 Mar 2026 12:08:09 +0300 Subject: [PATCH 2/3] fix comment Signed-off-by: Daniil Loktev --- images/virtualization-artifact/pkg/controller/vm/pod_gc.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/pod_gc.go b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go index df2173a6fa..0cbc0c7e73 100644 --- a/images/virtualization-artifact/pkg/controller/vm/pod_gc.go +++ b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go @@ -33,7 +33,7 @@ import ( const gcPodControllerName = "vm-pod-gc-controller" func SetupPodGC(mgr manager.Manager, log *log.Logger, gcSettings config.BaseGcSettings) error { - podGCMgr := newPodGCManager(mgr.GetClient(), gcSettings.TTL.Duration, 10) + podGCMgr := newPodGCManager(mgr.GetClient(), gcSettings.TTL.Duration, 2) return gc.SetupGcController(gcPodControllerName, mgr, @@ -48,7 +48,7 @@ func newPodGCManager(client client.Client, ttl time.Duration, max int) *podGCMan ttl = 24 * time.Hour } if max == 0 { - max = 10 + max = 2 } return &podGCManager{ client: client, @@ -100,5 +100,5 @@ func (m *podGCManager) getIndex(obj client.Object) string { if !ok { return "" } - return pod.Labels[virtv1.VirtualMachineNameLabel] + return pod.Namespace + "/" + pod.Labels[virtv1.VirtualMachineNameLabel] } From aa3b1e29d5eaf45f9d15d4bbd07b7646c303d070 Mon Sep 17 00:00:00 2001 From: Daniil Loktev Date: Wed, 11 Mar 2026 12:15:11 +0300 Subject: [PATCH 3/3] fix comment Signed-off-by: Daniil Loktev --- .../pkg/controller/vm/pod_gc.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vm/pod_gc.go b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go index 0cbc0c7e73..9e86e2fc05 100644 --- a/images/virtualization-artifact/pkg/controller/vm/pod_gc.go +++ b/images/virtualization-artifact/pkg/controller/vm/pod_gc.go @@ -1,5 +1,5 @@ /* -Copyright 2025 Flant JSC +Copyright 2026 Flant JSC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,10 +30,14 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/gc" ) -const gcPodControllerName = "vm-pod-gc-controller" +const ( + gcPodControllerName = "vm-pod-gc-controller" + defaultPodGCTTL = 24 * time.Hour + defaultPodGCMaxCount = 2 +) func SetupPodGC(mgr manager.Manager, log *log.Logger, gcSettings config.BaseGcSettings) error { - podGCMgr := newPodGCManager(mgr.GetClient(), gcSettings.TTL.Duration, 2) + podGCMgr := newPodGCManager(mgr.GetClient(), gcSettings.TTL.Duration, defaultPodGCMaxCount) return gc.SetupGcController(gcPodControllerName, mgr, @@ -45,10 +49,10 @@ func SetupPodGC(mgr manager.Manager, log *log.Logger, gcSettings config.BaseGcSe func newPodGCManager(client client.Client, ttl time.Duration, max int) *podGCManager { if ttl == 0 { - ttl = 24 * time.Hour + ttl = defaultPodGCTTL } if max == 0 { - max = 2 + max = defaultPodGCMaxCount } return &podGCManager{ client: client,