diff --git a/src/app.d.ts b/src/app.d.ts
index d69042fe8..2ebfc021b 100644
--- a/src/app.d.ts
+++ b/src/app.d.ts
@@ -8,9 +8,11 @@ declare namespace App {
interface Platform {}
interface Session extends SessionData {}
interface Stuff {
+ service: any;
application: any;
isRunning: boolean;
appId: string;
+ readOnly: boolean;
}
}
diff --git a/src/lib/components/svg/services/UptimeKuma.svelte b/src/lib/components/svg/services/UptimeKuma.svelte
new file mode 100644
index 000000000..e043ea54b
--- /dev/null
+++ b/src/lib/components/svg/services/UptimeKuma.svelte
@@ -0,0 +1,159 @@
+
+
+
diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts
index 67316fd06..19922cece 100644
--- a/src/lib/database/common.ts
+++ b/src/lib/database/common.ts
@@ -174,6 +174,15 @@ export const supportedServiceTypesAndVersions = [
ports: {
main: 5678
}
+ },
+ {
+ name: 'uptimekuma',
+ fancyName: 'Uptime Kuma',
+ baseImage: 'louislam/uptime-kuma',
+ versions: ['latest'],
+ ports: {
+ main: 3001
+ }
}
];
diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts
index 4ed11f7fe..daec2a5da 100644
--- a/src/lib/database/services.ts
+++ b/src/lib/database/services.ts
@@ -126,6 +126,13 @@ export async function configureServiceType({ id, type }) {
type
}
});
+ } else if (type === 'uptimekuma') {
+ await prisma.service.update({
+ where: { id },
+ data: {
+ type
+ }
+ });
}
}
export async function setServiceVersion({ id, version }) {
diff --git a/src/routes/services/[id]/configuration/type.svelte b/src/routes/services/[id]/configuration/type.svelte
index af10189a2..6a56354be 100644
--- a/src/routes/services/[id]/configuration/type.svelte
+++ b/src/routes/services/[id]/configuration/type.svelte
@@ -39,6 +39,7 @@
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
import N8n from '$lib/components/svg/services/N8n.svelte';
+ import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@@ -80,6 +81,8 @@
{:else if type.name === 'n8n'}
+ {:else if type.name === 'uptimekuma'}
+
{/if}{type.fancyName}
diff --git a/src/routes/services/[id]/index.svelte b/src/routes/services/[id]/index.svelte
index 6dbf5b6f6..bcc69b8a7 100644
--- a/src/routes/services/[id]/index.svelte
+++ b/src/routes/services/[id]/index.svelte
@@ -40,6 +40,7 @@
import { browser } from '$app/env';
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
import N8n from '$lib/components/svg/services/N8n.svelte';
+ import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte';
export let service;
export let isRunning;
@@ -114,6 +115,10 @@
+ {:else if service.type === 'uptimekuma'}
+
+
+
{/if}
diff --git a/src/routes/services/[id]/uptimekuma/index.json.ts b/src/routes/services/[id]/uptimekuma/index.json.ts
new file mode 100644
index 000000000..5ec3fa69a
--- /dev/null
+++ b/src/routes/services/[id]/uptimekuma/index.json.ts
@@ -0,0 +1,20 @@
+import { getUserDetails } from '$lib/common';
+import * as db from '$lib/database';
+import { ErrorHandler } from '$lib/database';
+import type { RequestHandler } from '@sveltejs/kit';
+
+export const post: RequestHandler = async (event) => {
+ const { status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+ const { id } = event.params;
+
+ let { name, fqdn } = await event.request.json();
+ if (fqdn) fqdn = fqdn.toLowerCase();
+
+ try {
+ await db.updateService({ id, fqdn, name });
+ return { status: 201 };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};
diff --git a/src/routes/services/[id]/uptimekuma/start.json.ts b/src/routes/services/[id]/uptimekuma/start.json.ts
new file mode 100644
index 000000000..961a546c4
--- /dev/null
+++ b/src/routes/services/[id]/uptimekuma/start.json.ts
@@ -0,0 +1,72 @@
+import { asyncExecShell, createDirectories, getEngine, getUserDetails } from '$lib/common';
+import * as db from '$lib/database';
+import { promises as fs } from 'fs';
+import yaml from 'js-yaml';
+import type { RequestHandler } from '@sveltejs/kit';
+import { ErrorHandler, getServiceImage } from '$lib/database';
+import { makeLabelForServices } from '$lib/buildPacks/common';
+
+export const post: RequestHandler = async (event) => {
+ const { teamId, status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+
+ const { id } = event.params;
+
+ try {
+ const service = await db.getService({ id, teamId });
+ const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service;
+ const network = destinationDockerId && destinationDocker.network;
+ const host = getEngine(destinationDocker.engine);
+
+ const { workdir } = await createDirectories({ repository: type, buildId: id });
+ const image = getServiceImage(type);
+
+ const config = {
+ image: `${image}:${version}`,
+ volume: `${id}-uptimekuma:/app/data`,
+ environmentVariables: {}
+ };
+ if (serviceSecret.length > 0) {
+ serviceSecret.forEach((secret) => {
+ config.environmentVariables[secret.name] = secret.value;
+ });
+ }
+ const composeFile = {
+ version: '3.8',
+ services: {
+ [id]: {
+ container_name: id,
+ image: config.image,
+ networks: [network],
+ volumes: [config.volume],
+ environment: config.environmentVariables,
+ restart: 'always',
+ labels: makeLabelForServices('uptimekuma')
+ }
+ },
+ networks: {
+ [network]: {
+ external: true
+ }
+ },
+ volumes: {
+ [config.volume.split(':')[0]]: {
+ name: config.volume.split(':')[0]
+ }
+ }
+ };
+ const composeFileDestination = `${workdir}/docker-compose.yaml`;
+ await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
+
+ try {
+ await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
+ return {
+ status: 200
+ };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};
diff --git a/src/routes/services/[id]/uptimekuma/stop.json.ts b/src/routes/services/[id]/uptimekuma/stop.json.ts
new file mode 100644
index 000000000..c604e1cc3
--- /dev/null
+++ b/src/routes/services/[id]/uptimekuma/stop.json.ts
@@ -0,0 +1,35 @@
+import { getUserDetails, removeDestinationDocker } from '$lib/common';
+import * as db from '$lib/database';
+import { ErrorHandler } from '$lib/database';
+import { checkContainer } from '$lib/haproxy';
+import type { RequestHandler } from '@sveltejs/kit';
+
+export const post: RequestHandler = async (event) => {
+ const { teamId, status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+
+ const { id } = event.params;
+
+ try {
+ const service = await db.getService({ id, teamId });
+ const { destinationDockerId, destinationDocker, fqdn } = service;
+ if (destinationDockerId) {
+ const engine = destinationDocker.engine;
+
+ try {
+ const found = await checkContainer(engine, id);
+ if (found) {
+ await removeDestinationDocker({ id, engine });
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ return {
+ status: 200
+ };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};