diff --git a/src/app/settings/maintenance/qs-maintenance-settings.tsx b/src/app/settings/maintenance/qs-maintenance-settings.tsx index 40147b6..2a2169a 100644 --- a/src/app/settings/maintenance/qs-maintenance-settings.tsx +++ b/src/app/settings/maintenance/qs-maintenance-settings.tsx @@ -1,7 +1,7 @@ 'use client'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { cleanupOldBuildJobs, cleanupOldTmpFiles, purgeRegistryImages, updateRegistry, updateTraefikMeCertificates } from "../server/actions"; +import { cleanupOldBuildJobs, cleanupOldTmpFiles, deleteAllFailedAndSuccededPods, purgeRegistryImages, updateRegistry, updateTraefikMeCertificates } from "../server/actions"; import { Button } from "@/components/ui/button"; import { Toast } from "@/frontend/utils/toast.utils"; import { useConfirmDialog } from "@/frontend/states/zustand.states"; @@ -87,6 +87,16 @@ export default function QuickStackMaintenanceSettings({ } }}>Update Traefik.me SSL Certificates + + ; diff --git a/src/app/settings/server/actions.ts b/src/app/settings/server/actions.ts index 9427c37..0f433b6 100644 --- a/src/app/settings/server/actions.ts +++ b/src/app/settings/server/actions.ts @@ -16,6 +16,7 @@ import buildService from "@/server/services/build.service"; import { PathUtils } from "@/server/utils/path.utils"; import { FsUtils } from "@/server/utils/fs.utils"; import traefikMeDomainStandaloneService from "@/server/services/standalone-services/traefik-me-domain-standalone.service"; +import standalonePodService from "@/server/services/standalone-services/standalone-pod.service"; export const updateIngressSettings = async (prevState: any, inputData: QsIngressSettingsModel) => saveFormAction(inputData, qsIngressSettingsZodModel, async (validatedData) => { @@ -119,6 +120,13 @@ export const updateTraefikMeCertificates = async () => return new SuccessActionResult(undefined, 'Certificates will be updated, this might take a few seconds.'); }); +export const deleteAllFailedAndSuccededPods = async () => + simpleAction(async () => { + await getAuthUserSession(); + await standalonePodService.deleteAllFailedAndSuccededPods(); + return new SuccessActionResult(undefined, 'Successfully deleted all failed and succeeded pods.'); + }); + export const purgeRegistryImages = async () => simpleAction(async () => { await getAuthUserSession(); diff --git a/src/server/services/standalone-services/standalone-pod.service.ts b/src/server/services/standalone-services/standalone-pod.service.ts index f4cd037..0ae0f2b 100644 --- a/src/server/services/standalone-services/standalone-pod.service.ts +++ b/src/server/services/standalone-services/standalone-pod.service.ts @@ -2,6 +2,7 @@ import k3s from "../../adapter/kubernetes-api.adapter"; import fs from 'fs'; import stream from 'stream'; import * as k8s from '@kubernetes/client-node'; +import dataAccess from "../../../server/adapter/db.client"; class SetupPodService { @@ -226,7 +227,18 @@ class SetupPodService { }, 5000); }); }); + } + async deleteAllFailedAndSuccededPods() { + const projects = await dataAccess.client.project.findMany(); + + for (const project of projects) { + const podsOfNamespace = await k3s.core.listNamespacedPod(project.id); + const failedPods = podsOfNamespace.body.items.filter((pod) => ['Failed', 'Succeeded'].includes(pod.status?.phase!)); + for (const pod of failedPods) { + await k3s.core.deleteNamespacedPod(pod.metadata?.name!, project.id); + } + } } }