feat: cleanup unconfigured services and databases
This commit is contained in:
parent
28377a156d
commit
683b8c966f
@ -1883,11 +1883,11 @@ async function stopServiceContainers(request: FastifyRequest<ServiceStartStop>)
|
|||||||
if (destinationDockerId) {
|
if (destinationDockerId) {
|
||||||
await executeDockerCmd({
|
await executeDockerCmd({
|
||||||
dockerId: destinationDockerId,
|
dockerId: destinationDockerId,
|
||||||
command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -n 1 docker stop -t 0`
|
command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0`
|
||||||
})
|
})
|
||||||
await executeDockerCmd({
|
await executeDockerCmd({
|
||||||
dockerId: destinationDockerId,
|
dockerId: destinationDockerId,
|
||||||
command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -n 1 docker rm --force`
|
command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -r -n 1 docker rm --force`
|
||||||
})
|
})
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ export async function getImages(request: FastifyRequest<GetImages>) {
|
|||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function cleanupUnconfigured(request: FastifyRequest<any>) {
|
export async function cleanupUnconfiguredApplications(request: FastifyRequest<any>) {
|
||||||
try {
|
try {
|
||||||
let teamId = request.user.teamId
|
const teamId = request.user.teamId
|
||||||
let applications = await prisma.application.findMany({
|
let applications = await prisma.application.findMany({
|
||||||
where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } },
|
where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } },
|
||||||
include: { settings: true, destinationDocker: true, teams: true },
|
include: { settings: true, destinationDocker: true, teams: true },
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { OnlyId } from '../../../../types';
|
import { OnlyId } from '../../../../types';
|
||||||
import { cancelDeployment, checkDNS, checkDomain, checkRepository, cleanupUnconfigured, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildPack, getBuilds, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getPreviewStatus, getSecrets, getStorages, getUsage, listApplications, loadPreviews, newApplication, restartApplication, restartPreview, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication, updatePreviewSecret, updateSecret } from './handlers';
|
import { cancelDeployment, checkDNS, checkDomain, checkRepository, cleanupUnconfiguredApplications, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getApplicationStatus, getBuildIdLogs, getBuildPack, getBuilds, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getPreviewStatus, getSecrets, getStorages, getUsage, listApplications, loadPreviews, newApplication, restartApplication, restartPreview, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveConnectedDatabase, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication, stopPreviewApplication, updatePreviewSecret, updateSecret } from './handlers';
|
||||||
|
|
||||||
import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuilds, GetImages, RestartPreviewApplication, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types';
|
import type { CancelDeployment, CheckDNS, CheckDomain, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuilds, GetImages, RestartPreviewApplication, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, StopPreviewApplication } from './types';
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.get('/', async (request) => await listApplications(request));
|
fastify.get('/', async (request) => await listApplications(request));
|
||||||
fastify.post<GetImages>('/images', async (request) => await getImages(request));
|
fastify.post<GetImages>('/images', async (request) => await getImages(request));
|
||||||
|
|
||||||
fastify.post<any>('/cleanup/unconfigured', async (request) => await cleanupUnconfigured(request));
|
fastify.post<any>('/cleanup/unconfigured', async (request) => await cleanupUnconfiguredApplications(request));
|
||||||
|
|
||||||
fastify.post('/new', async (request, reply) => await newApplication(request, reply));
|
fastify.post('/new', async (request, reply) => await newApplication(request, reply));
|
||||||
|
|
||||||
|
@ -51,6 +51,30 @@ export async function newDatabase(request: FastifyRequest, reply: FastifyReply)
|
|||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function cleanupUnconfiguredDatabases(request: FastifyRequest) {
|
||||||
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
let databases = await prisma.database.findMany({
|
||||||
|
where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } },
|
||||||
|
include: { settings: true, destinationDocker: true, teams: true },
|
||||||
|
});
|
||||||
|
for (const database of databases) {
|
||||||
|
if (!database?.version) {
|
||||||
|
const { id } = database;
|
||||||
|
if (database.destinationDockerId) {
|
||||||
|
const everStarted = await stopDatabaseContainer(database);
|
||||||
|
if (everStarted) await stopTcpHttpProxy(id, database.destinationDocker, database.publicPort);
|
||||||
|
}
|
||||||
|
await prisma.databaseSettings.deleteMany({ where: { databaseId: id } });
|
||||||
|
await prisma.databaseSecret.deleteMany({ where: { databaseId: id } });
|
||||||
|
await prisma.database.delete({ where: { id } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
export async function getDatabaseStatus(request: FastifyRequest<OnlyId>) {
|
export async function getDatabaseStatus(request: FastifyRequest<OnlyId>) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { deleteDatabase, deleteDatabaseSecret, getDatabase, getDatabaseLogs, getDatabaseSecrets, getDatabaseStatus, getDatabaseTypes, getDatabaseUsage, getVersions, listDatabases, newDatabase, saveDatabase, saveDatabaseDestination, saveDatabaseSecret, saveDatabaseSettings, saveDatabaseType, saveVersion, startDatabase, stopDatabase } from './handlers';
|
import { cleanupUnconfiguredDatabases, deleteDatabase, deleteDatabaseSecret, getDatabase, getDatabaseLogs, getDatabaseSecrets, getDatabaseStatus, getDatabaseTypes, getDatabaseUsage, getVersions, listDatabases, newDatabase, saveDatabase, saveDatabaseDestination, saveDatabaseSecret, saveDatabaseSettings, saveDatabaseType, saveVersion, startDatabase, stopDatabase } from './handlers';
|
||||||
|
|
||||||
import type { OnlyId } from '../../../../types';
|
import type { OnlyId } from '../../../../types';
|
||||||
|
|
||||||
@ -12,6 +12,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.get('/', async (request) => await listDatabases(request));
|
fastify.get('/', async (request) => await listDatabases(request));
|
||||||
fastify.post('/new', async (request, reply) => await newDatabase(request, reply));
|
fastify.post('/new', async (request, reply) => await newDatabase(request, reply));
|
||||||
|
|
||||||
|
fastify.post<any>('/cleanup/unconfigured', async (request) => await cleanupUnconfiguredDatabases(request));
|
||||||
|
|
||||||
fastify.get<OnlyId>('/:id', async (request) => await getDatabase(request));
|
fastify.get<OnlyId>('/:id', async (request) => await getDatabase(request));
|
||||||
fastify.post<SaveDatabase>('/:id', async (request, reply) => await saveDatabase(request, reply));
|
fastify.post<SaveDatabase>('/:id', async (request, reply) => await saveDatabase(request, reply));
|
||||||
fastify.delete<DeleteDatabase>('/:id', async (request) => await deleteDatabase(request));
|
fastify.delete<DeleteDatabase>('/:id', async (request) => await deleteDatabase(request));
|
||||||
|
@ -143,15 +143,29 @@ export async function showDashboard(request: FastifyRequest) {
|
|||||||
include: { teams: true },
|
include: { teams: true },
|
||||||
});
|
});
|
||||||
const settings = await listSettings();
|
const settings = await listSettings();
|
||||||
|
|
||||||
let foundUnconfiguredApplication = false;
|
let foundUnconfiguredApplication = false;
|
||||||
for (const application of applications) {
|
for (const application of applications) {
|
||||||
if (!application.buildPack || !application.destinationDockerId || !application.branch || (!application.settings?.isBot && !application?.fqdn)) {
|
if (!application.buildPack || !application.destinationDockerId || !application.branch || (!application.settings?.isBot && !application?.fqdn)) {
|
||||||
foundUnconfiguredApplication = true
|
foundUnconfiguredApplication = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let foundUnconfiguredService = false;
|
||||||
|
for (const service of services) {
|
||||||
|
if (!service.fqdn) {
|
||||||
|
foundUnconfiguredService = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let foundUnconfiguredDatabase = false;
|
||||||
|
for (const database of databases) {
|
||||||
|
if (!database.version) {
|
||||||
|
foundUnconfiguredDatabase = true
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
foundUnconfiguredApplication,
|
foundUnconfiguredApplication,
|
||||||
|
foundUnconfiguredDatabase,
|
||||||
|
foundUnconfiguredService,
|
||||||
applications,
|
applications,
|
||||||
databases,
|
databases,
|
||||||
services,
|
services,
|
||||||
|
@ -36,6 +36,33 @@ export async function newService(request: FastifyRequest, reply: FastifyReply) {
|
|||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function cleanupUnconfiguredServices(request: FastifyRequest) {
|
||||||
|
try {
|
||||||
|
const teamId = request.user.teamId;
|
||||||
|
let services = await prisma.service.findMany({
|
||||||
|
where: { teams: { some: { id: teamId === "0" ? undefined : teamId } } },
|
||||||
|
include: { destinationDocker: true, teams: true },
|
||||||
|
});
|
||||||
|
for (const service of services) {
|
||||||
|
if (!service.fqdn) {
|
||||||
|
if (service.destinationDockerId) {
|
||||||
|
await executeDockerCmd({
|
||||||
|
dockerId: service.destinationDockerId,
|
||||||
|
command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0`
|
||||||
|
})
|
||||||
|
await executeDockerCmd({
|
||||||
|
dockerId: service.destinationDockerId,
|
||||||
|
command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}|xargs -r -n 1 docker rm --force`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await removeService({ id: service.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
} catch ({ status, message }) {
|
||||||
|
return errorHandler({ status, message })
|
||||||
|
}
|
||||||
|
}
|
||||||
export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
|
export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
|
||||||
try {
|
try {
|
||||||
const teamId = request.user.teamId;
|
const teamId = request.user.teamId;
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
checkService,
|
checkService,
|
||||||
checkServiceDomain,
|
checkServiceDomain,
|
||||||
cleanupPlausibleLogs,
|
cleanupPlausibleLogs,
|
||||||
|
cleanupUnconfiguredServices,
|
||||||
deleteService,
|
deleteService,
|
||||||
deleteServiceSecret,
|
deleteServiceSecret,
|
||||||
deleteServiceStorage,
|
deleteServiceStorage,
|
||||||
@ -39,6 +40,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.get('/', async (request) => await listServices(request));
|
fastify.get('/', async (request) => await listServices(request));
|
||||||
fastify.post('/new', async (request, reply) => await newService(request, reply));
|
fastify.post('/new', async (request, reply) => await newService(request, reply));
|
||||||
|
|
||||||
|
fastify.post<any>('/cleanup/unconfigured', async (request) => await cleanupUnconfiguredServices(request));
|
||||||
|
|
||||||
fastify.get<OnlyId>('/:id', async (request) => await getService(request));
|
fastify.get<OnlyId>('/:id', async (request) => await getService(request));
|
||||||
fastify.post<SaveService>('/:id', async (request, reply) => await saveService(request, reply));
|
fastify.post<SaveService>('/:id', async (request, reply) => await saveService(request, reply));
|
||||||
fastify.delete<OnlyId>('/:id', async (request) => await deleteService(request));
|
fastify.delete<OnlyId>('/:id', async (request) => await deleteService(request));
|
||||||
|
@ -55,7 +55,6 @@
|
|||||||
export let database: any;
|
export let database: any;
|
||||||
import { del, get, post } from '$lib/api';
|
import { del, get, post } from '$lib/api';
|
||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
|
import { errorNotification, handlerNotFoundLoad } from '$lib/common';
|
||||||
import { appSession, status, isDeploymentEnabled } from '$lib/store';
|
import { appSession, status, isDeploymentEnabled } from '$lib/store';
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let applications: any;
|
export let applications: any;
|
||||||
export let foundUnconfiguredApplication: boolean;
|
export let foundUnconfiguredApplication: boolean;
|
||||||
|
export let foundUnconfiguredService: boolean;
|
||||||
|
export let foundUnconfiguredDatabase: boolean;
|
||||||
export let databases: any;
|
export let databases: any;
|
||||||
export let services: any;
|
export let services: any;
|
||||||
export let settings: any;
|
export let settings: any;
|
||||||
@ -328,7 +330,9 @@
|
|||||||
}
|
}
|
||||||
async function cleanupApplications() {
|
async function cleanupApplications() {
|
||||||
try {
|
try {
|
||||||
const sure = confirm('Are you sure? This will delete all UNCONFIGURED applications and their data.');
|
const sure = confirm(
|
||||||
|
'Are you sure? This will delete all UNCONFIGURED applications and their data.'
|
||||||
|
);
|
||||||
if (sure) {
|
if (sure) {
|
||||||
await post(`/applications/cleanup/unconfigured`, {});
|
await post(`/applications/cleanup/unconfigured`, {});
|
||||||
return window.location.reload();
|
return window.location.reload();
|
||||||
@ -337,6 +341,32 @@
|
|||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function cleanupServices() {
|
||||||
|
try {
|
||||||
|
const sure = confirm(
|
||||||
|
'Are you sure? This will delete all UNCONFIGURED services and their data.'
|
||||||
|
);
|
||||||
|
if (sure) {
|
||||||
|
await post(`/services/cleanup/unconfigured`, {});
|
||||||
|
return window.location.reload();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function cleanupDatabases() {
|
||||||
|
try {
|
||||||
|
const sure = confirm(
|
||||||
|
'Are you sure? This will delete all UNCONFIGURED databases and their data.'
|
||||||
|
);
|
||||||
|
if (sure) {
|
||||||
|
await post(`/databases/cleanup/unconfigured`, {});
|
||||||
|
return window.location.reload();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav class="header">
|
<nav class="header">
|
||||||
@ -534,7 +564,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#if (filtered.applications.length > 0 && applications.length > 0) || filtered.otherApplications.length > 0}
|
{#if (filtered.applications.length > 0 && applications.length > 0) || filtered.otherApplications.length > 0}
|
||||||
<div class="flex items-center mt-10 space-x-2">
|
<div class="flex items-center mt-10 space-x-2">
|
||||||
<h1 class="title lg:text-3xl pr-4">Applications</h1>
|
<h1 class="title lg:text-3xl">Applications</h1>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-primary"
|
class="btn btn-sm btn-primary"
|
||||||
class:loading={loading.applications}
|
class:loading={loading.applications}
|
||||||
@ -760,8 +790,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if (filtered.services.length > 0 && services.length > 0) || filtered.otherServices.length > 0}
|
{#if (filtered.services.length > 0 && services.length > 0) || filtered.otherServices.length > 0}
|
||||||
<div class="flex items-center mt-10">
|
<div class="flex items-center mt-10 space-x-2">
|
||||||
<h1 class="title lg:text-3xl pr-4">Services</h1>
|
<h1 class="title lg:text-3xl">Services</h1>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-primary"
|
class="btn btn-sm btn-primary"
|
||||||
class:loading={loading.services}
|
class:loading={loading.services}
|
||||||
@ -769,6 +799,14 @@
|
|||||||
on:click={refreshStatusServices}
|
on:click={refreshStatusServices}
|
||||||
>{noInitialStatus.services ? 'Load Status' : 'Refresh Status'}</button
|
>{noInitialStatus.services ? 'Load Status' : 'Refresh Status'}</button
|
||||||
>
|
>
|
||||||
|
{#if foundUnconfiguredService}
|
||||||
|
<button
|
||||||
|
class="btn btn-sm"
|
||||||
|
class:loading={loading.services}
|
||||||
|
disabled={loading.services}
|
||||||
|
on:click={cleanupServices}>Cleanup Unconfigured Resources</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if filtered.services.length > 0 && services.length > 0}
|
{#if filtered.services.length > 0 && services.length > 0}
|
||||||
@ -914,8 +952,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if (filtered.databases.length > 0 && databases.length > 0) || filtered.otherDatabases.length > 0}
|
{#if (filtered.databases.length > 0 && databases.length > 0) || filtered.otherDatabases.length > 0}
|
||||||
<div class="flex items-center mt-10">
|
<div class="flex items-center mt-10 space-x-2">
|
||||||
<h1 class="title lg:text-3xl pr-4">Databases</h1>
|
<h1 class="title lg:text-3xl">Databases</h1>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-primary"
|
class="btn btn-sm btn-primary"
|
||||||
on:click={refreshStatusDatabases}
|
on:click={refreshStatusDatabases}
|
||||||
@ -923,6 +961,14 @@
|
|||||||
disabled={loading.databases}
|
disabled={loading.databases}
|
||||||
>{noInitialStatus.databases ? 'Load Status' : 'Refresh Status'}</button
|
>{noInitialStatus.databases ? 'Load Status' : 'Refresh Status'}</button
|
||||||
>
|
>
|
||||||
|
{#if foundUnconfiguredDatabase}
|
||||||
|
<button
|
||||||
|
class="btn btn-sm"
|
||||||
|
class:loading={loading.databases}
|
||||||
|
disabled={loading.databases}
|
||||||
|
on:click={cleanupDatabases}>Cleanup Unconfigured Resources</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if filtered.databases.length > 0 && databases.length > 0}
|
{#if filtered.databases.length > 0 && databases.length > 0}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user