From 0d12f3043b4d8a247695902a9e3df1218236fdc3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 26 Oct 2022 13:44:32 +0200 Subject: [PATCH] fix + cleanup --- apps/api/devTemplates.yaml | 1 + apps/api/src/lib/common.ts | 2 +- apps/api/src/lib/services/handlers.ts | 16 +- .../api/src/lib/services/supportedVersions.ts | 278 ------------------ apps/api/src/routes/api/v1/handlers.ts | 2 - .../src/routes/api/v1/services/handlers.ts | 28 +- apps/api/src/routes/api/v1/services/index.ts | 2 - apps/api/src/routes/api/v1/services/types.ts | 3 +- .../src/routes/webhooks/traefik/handlers.ts | 4 +- apps/ui/src/lib/store.ts | 2 - apps/ui/src/routes/__layout.svelte | 2 - .../src/routes/services/[id]/_Storage.svelte | 164 ++++++----- .../[id]/configuration/version.svelte | 3 - apps/ui/src/routes/services/[id]/index.svelte | 2 +- .../src/routes/services/[id]/storages.svelte | 28 +- 15 files changed, 148 insertions(+), 389 deletions(-) delete mode 100644 apps/api/src/lib/services/supportedVersions.ts diff --git a/apps/api/devTemplates.yaml b/apps/api/devTemplates.yaml index c94309932..cb5722345 100644 --- a/apps/api/devTemplates.yaml +++ b/apps/api/devTemplates.yaml @@ -2204,6 +2204,7 @@ Server, SQLite & MariaDB into a smart-spreadsheet. services: $$id: + name: NocoDB image: nocodb/nocodb:$$core_version environment: - PORT=$$config_port diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 3feb77d7c..4a4de8be7 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -1091,7 +1091,7 @@ export const createDirectories = async ({ repository: string; buildId: string; }): Promise<{ workdir: string; repodir: string }> => { - repository = repository.replaceAll(' ','') + repository = repository.replaceAll(' ', '') const repodir = `/tmp/build-sources/${repository}/`; const workdir = `/tmp/build-sources/${repository}/${buildId}`; let workdirFound = false; diff --git a/apps/api/src/lib/services/handlers.ts b/apps/api/src/lib/services/handlers.ts index 38751321b..29e487749 100644 --- a/apps/api/src/lib/services/handlers.ts +++ b/apps/api/src/lib/services/handlers.ts @@ -35,7 +35,6 @@ export async function startService(request: FastifyRequest) { const teamId = request.user.teamId; const service = await getServiceFromDB({ id, teamId }); const arm = isARM(service.arch) - console.log(arm) const { type, destinationDockerId, destinationDocker, persistentStorage } = service; @@ -76,6 +75,16 @@ export async function startService(request: FastifyRequest) { } } } + const customVolumes = await prisma.servicePersistentStorage.findMany({ where: { serviceId: service } }) + let volumes = arm ? template.services[service].volumesArm : template.services[service].volumes + if (customVolumes.length > 0) { + for (const customVolume of customVolumes) { + const { volumeName, path } = customVolume + if (!volumes.includes(`${volumeName}:${path}`)) { + volumes.push(`${volumeName}:${path}`) + } + } + } config[service] = { container_name: service, build: template.services[service].build || undefined, @@ -84,7 +93,7 @@ export async function startService(request: FastifyRequest) { image: arm ? template.services[service].imageArm : template.services[service].image, expose: template.services[service].ports, // ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), - volumes: arm ? template.services[service].volumesArm : template.services[service].volumes, + volumes, environment: newEnvironments, depends_on: template.services[service]?.depends_on, ulimits: template.services[service]?.ulimits, @@ -93,7 +102,7 @@ export async function startService(request: FastifyRequest) { labels: makeLabelForServices(type), ...defaultComposeConfiguration(network), } - + // Generate files for builds if (template.services[service]?.files?.length > 0) { if (!template.services[service].build) { @@ -113,7 +122,6 @@ export async function startService(request: FastifyRequest) { await fs.writeFile(`${workdir}/Dockerfile.${service}`, Dockerfile); } } - const { volumeMounts } = persistentVolumes(id, persistentStorage, config) const composeFile: ComposeFile = { version: '3.8', diff --git a/apps/api/src/lib/services/supportedVersions.ts b/apps/api/src/lib/services/supportedVersions.ts deleted file mode 100644 index d84d1bd65..000000000 --- a/apps/api/src/lib/services/supportedVersions.ts +++ /dev/null @@ -1,278 +0,0 @@ -/* - Example of a supported version: -{ - // Name used to identify the service internally - name: 'umami', - // Fancier name to show to the user - fancyName: 'Umami', - // Docker base image for the service - baseImage: 'ghcr.io/mikecao/umami', - // Optional: If there is any dependent image, you should list it here - images: [], - // Usable tags - versions: ['postgresql-latest'], - // Which tag is the recommended - recommendedVersion: 'postgresql-latest', - // Application's default port, Umami listens on 3000 - ports: { - main: 3000 - } - } -*/ -export const supportedServiceTypesAndVersions = [ - { - name: 'plausibleanalytics', - fancyName: 'Plausible Analytics', - baseImage: 'plausible/analytics', - images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], - versions: ['latest', 'stable'], - recommendedVersion: 'stable', - ports: { - main: 8000 - }, - labels: ['analytics', 'plausible', 'plausible-analytics', 'gdpr', 'no-cookie'] - }, - { - name: 'nocodb', - fancyName: 'NocoDB', - baseImage: 'nocodb/nocodb', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - }, - labels: ['nocodb', 'airtable', 'database'] - }, - { - name: 'minio', - fancyName: 'MinIO', - baseImage: 'minio/minio', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 9001 - }, - labels: ['minio', 's3', 'storage'] - }, - { - name: 'vscodeserver', - fancyName: 'VSCode Server', - baseImage: 'codercom/code-server', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - }, - labels: ['vscodeserver', 'vscode', 'code-server', 'ide'] - }, - { - name: 'wordpress', - fancyName: 'WordPress', - baseImage: 'wordpress', - images: ['bitnami/mysql:5.7'], - versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], - recommendedVersion: 'latest', - ports: { - main: 80 - }, - labels: ['wordpress', 'blog', 'cms'] - }, - { - name: 'vaultwarden', - fancyName: 'Vaultwarden', - baseImage: 'vaultwarden/server', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 80 - }, - labels: ['vaultwarden', 'password-manager', 'passwords'] - }, - { - name: 'languagetool', - fancyName: 'LanguageTool', - baseImage: 'silviof/docker-languagetool', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8010 - }, - labels: ['languagetool', 'grammar', 'spell-checker'] - }, - { - name: 'n8n', - fancyName: 'n8n', - baseImage: 'n8nio/n8n', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 5678 - }, - labels: ['n8n', 'workflow', 'automation', 'ifttt', 'zapier', 'nodered'] - }, - { - name: 'uptimekuma', - fancyName: 'Uptime Kuma', - baseImage: 'louislam/uptime-kuma', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 3001 - }, - labels: ['uptimekuma', 'uptime', 'monitoring'] - }, - { - name: 'ghost', - fancyName: 'Ghost', - baseImage: 'bitnami/ghost', - images: ['bitnami/mariadb'], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 2368 - }, - labels: ['ghost', 'blog', 'cms'] - }, - { - name: 'meilisearch', - fancyName: 'Meilisearch', - baseImage: 'getmeili/meilisearch', - images: [], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 7700 - }, - labels: ['meilisearch', 'search', 'search-engine'] - }, - { - name: 'umami', - fancyName: 'Umami', - baseImage: 'ghcr.io/umami-software/umami', - images: ['postgres:12-alpine'], - versions: ['postgresql-latest'], - recommendedVersion: 'postgresql-latest', - ports: { - main: 3000 - }, - labels: ['umami', 'analytics', 'gdpr', 'no-cookie'] - }, - { - name: 'hasura', - fancyName: 'Hasura', - baseImage: 'hasura/graphql-engine', - images: ['postgres:12-alpine'], - versions: ['latest', 'v2.10.0', 'v2.5.1'], - recommendedVersion: 'v2.10.0', - ports: { - main: 8080 - }, - labels: ['hasura', 'graphql', 'database'] - }, - { - name: 'fider', - fancyName: 'Fider', - baseImage: 'getfider/fider', - images: ['postgres:12-alpine'], - versions: ['stable'], - recommendedVersion: 'stable', - ports: { - main: 3000 - }, - labels: ['fider', 'feedback', 'suggestions'] - }, - { - name: 'appwrite', - fancyName: 'Appwrite', - baseImage: 'appwrite/appwrite', - images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'], - versions: ['latest', '1.0', '0.15.3'], - recommendedVersion: '1.0', - ports: { - main: 80 - }, - labels: ['appwrite', 'database', 'storage', 'api', 'serverless'] - }, - // { - // name: 'moodle', - // fancyName: 'Moodle', - // baseImage: 'bitnami/moodle', - // images: [], - // versions: ['latest', 'v4.0.2'], - // recommendedVersion: 'latest', - // ports: { - // main: 8080 - // } - // } - { - name: 'glitchTip', - fancyName: 'GlitchTip', - baseImage: 'glitchtip/glitchtip', - images: ['postgres:14-alpine', 'redis:7-alpine'], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8000 - }, - labels: ['glitchtip', 'error-reporting', 'error', 'sentry', 'bugsnag'] - }, - { - name: 'searxng', - fancyName: 'SearXNG', - baseImage: 'searxng/searxng', - images: [], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - }, - labels: ['searxng', 'search', 'search-engine'] - }, - { - name: 'weblate', - fancyName: 'Weblate', - baseImage: 'weblate/weblate', - images: ['postgres:14-alpine', 'redis:6-alpine'], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - }, - labels: ['weblate', 'translation', 'localization'] - }, - // { - // name: 'taiga', - // fancyName: 'Taiga', - // baseImage: 'taigaio/taiga-front', - // images: ['postgres:12.3', 'rabbitmq:3.8-management-alpine', 'taigaio/taiga-back', 'taigaio/taiga-events', 'taigaio/taiga-protected'], - // versions: ['latest'], - // recommendedVersion: 'latest', - // ports: { - // main: 80 - // } - // }, - { - name: 'grafana', - fancyName: 'Grafana', - baseImage: 'grafana/grafana', - images: [], - versions: ['latest', '9.1.3', '9.1.2', '9.0.8', '8.3.11', '8.4.11', '8.5.11'], - recommendedVersion: 'latest', - ports: { - main: 3000 - }, - labels: ['grafana', 'monitoring', 'metrics', 'dashboard'] - }, - { - name: 'trilium', - fancyName: 'Trilium Notes', - baseImage: 'zadam/trilium', - images: [], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - }, - labels: ['trilium', 'notes', 'note-taking', 'wiki'] - }, -]; diff --git a/apps/api/src/routes/api/v1/handlers.ts b/apps/api/src/routes/api/v1/handlers.ts index e99cb3f61..8645e3856 100644 --- a/apps/api/src/routes/api/v1/handlers.ts +++ b/apps/api/src/routes/api/v1/handlers.ts @@ -15,7 +15,6 @@ import { uniqueName, version, } from "../../../lib/common"; -import { supportedServiceTypesAndVersions } from "../../../lib/services/supportedVersions"; import { scheduler } from "../../../lib/scheduler"; import type { FastifyReply, FastifyRequest } from "fastify"; import type { Login, Update } from "."; @@ -382,7 +381,6 @@ export async function getCurrentUser( return { settings: await prisma.setting.findFirst(), pendingInvitations, - supportedServiceTypesAndVersions, token, ...request.user, }; diff --git a/apps/api/src/routes/api/v1/services/handlers.ts b/apps/api/src/routes/api/v1/services/handlers.ts index 31637307c..092656771 100644 --- a/apps/api/src/routes/api/v1/services/handlers.ts +++ b/apps/api/src/routes/api/v1/services/handlers.ts @@ -10,7 +10,6 @@ import cuid from 'cuid'; import type { OnlyId } from '../../../../types'; import type { ActivateWordpressFtp, CheckService, CheckServiceDomain, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetGlitchTipSettings, SetWordpressSettings } from './types'; -import { supportedServiceTypesAndVersions } from '../../../../lib/services/supportedVersions'; import { configureServiceType, removeService } from '../../../../lib/services/common'; import { hashPassword } from '../handlers'; import { getTemplates } from '../../../../lib/services'; @@ -316,19 +315,7 @@ export async function saveServiceType(request: FastifyRequest, return errorHandler({ status, message }) } } -export async function getServiceVersions(request: FastifyRequest) { - try { - const teamId = request.user.teamId; - const { id } = request.params; - const { type } = await getServiceFromDB({ id, teamId }); - return { - type, - versions: supportedServiceTypesAndVersions.find((name) => name.name === type).versions - } - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} + export async function saveServiceVersion(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; @@ -601,16 +588,21 @@ export async function getServiceStorages(request: FastifyRequest) { export async function saveServiceStorage(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params - const { path, newStorage, storageId } = request.body + const { path, isNewStorage, storageId, containerId } = request.body - if (newStorage) { + if (isNewStorage) { + const volumeName = `${id}-custom${path.replace(/\//gi, '-')}` + const found = await prisma.servicePersistentStorage.findFirst({ where: { path, containerId } }); + if (found) { + throw { status: 500, message: 'Persistent storage already exists for this container and path.' } + } await prisma.servicePersistentStorage.create({ - data: { path, service: { connect: { id } } } + data: { path, volumeName, containerId, service: { connect: { id } } } }); } else { await prisma.servicePersistentStorage.update({ where: { id: storageId }, - data: { path } + data: { path, containerId } }); } return reply.code(201).send() diff --git a/apps/api/src/routes/api/v1/services/index.ts b/apps/api/src/routes/api/v1/services/index.ts index 830687bf7..b659484a2 100644 --- a/apps/api/src/routes/api/v1/services/index.ts +++ b/apps/api/src/routes/api/v1/services/index.ts @@ -16,7 +16,6 @@ import { getServiceStorages, getServiceType, getServiceUsage, - getServiceVersions, listServices, newService, saveService, @@ -64,7 +63,6 @@ const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/:id/configuration/type', async (request) => await getServiceType(request)); fastify.post('/:id/configuration/type', async (request, reply) => await saveServiceType(request, reply)); - fastify.get('/:id/configuration/version', async (request) => await getServiceVersions(request)); fastify.post('/:id/configuration/version', async (request, reply) => await saveServiceVersion(request, reply)); fastify.post('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply)); diff --git a/apps/api/src/routes/api/v1/services/types.ts b/apps/api/src/routes/api/v1/services/types.ts index 4d54792ed..0ade00359 100644 --- a/apps/api/src/routes/api/v1/services/types.ts +++ b/apps/api/src/routes/api/v1/services/types.ts @@ -66,8 +66,9 @@ export interface DeleteServiceSecret extends OnlyId { export interface SaveServiceStorage extends OnlyId { Body: { path: string, - newStorage: string, + containerId: string, storageId: string, + isNewStorage: boolean, } } diff --git a/apps/api/src/routes/webhooks/traefik/handlers.ts b/apps/api/src/routes/webhooks/traefik/handlers.ts index f89bcea46..30726f04c 100644 --- a/apps/api/src/routes/webhooks/traefik/handlers.ts +++ b/apps/api/src/routes/webhooks/traefik/handlers.ts @@ -1,6 +1,5 @@ import { FastifyRequest } from "fastify"; import { errorHandler, getDomain, isDev, prisma, executeDockerCmd, fixType } from "../../../lib/common"; -import { supportedServiceTypesAndVersions } from "../../../lib/services/supportedVersions"; import { TraefikOtherConfiguration } from "./types"; import { OnlyId } from "../../../types"; import { getTemplates } from "../../../lib/services"; @@ -873,7 +872,8 @@ export async function remoteTraefikConfiguration(request: FastifyRequest plausibleAnalytics } = service; if (destinationDockerId) { - const found = supportedServiceTypesAndVersions.find((a) => a.name === type); + const templates = await getTemplates(); + let found = templates.find((a) => fixType(a.name) === fixType(type)); if (found) { const port = found.ports.main; const publicPort = service[type]?.publicPort; diff --git a/apps/ui/src/lib/store.ts b/apps/ui/src/lib/store.ts index 89fd8308a..31ef89287 100644 --- a/apps/ui/src/lib/store.ts +++ b/apps/ui/src/lib/store.ts @@ -19,7 +19,6 @@ interface AppSession { github: string | null, gitlab: string | null, }, - supportedServiceTypesAndVersions: Array pendingInvitations: Array } interface AddToast { @@ -48,7 +47,6 @@ export const appSession: Writable = writable({ github: null, gitlab: null }, - supportedServiceTypesAndVersions: [], pendingInvitations: [] }); export const disabledButton: Writable = writable(false); diff --git a/apps/ui/src/routes/__layout.svelte b/apps/ui/src/routes/__layout.svelte index 248ac22ec..680bc02be 100644 --- a/apps/ui/src/routes/__layout.svelte +++ b/apps/ui/src/routes/__layout.svelte @@ -65,7 +65,6 @@
@@ -43,19 +55,27 @@
{#if persistentStorages.filter((s) => s.predefined).length > 0} -
Predefined
+
Predefined Volumes
+
+
+
Container
+
Volume ID : Mount Dir
+
+
{/if} {#each persistentStorages.filter((s) => s.predefined) as storage} {#key storage.id} - + {/key} {/each} -
s.predefined).length > 0}>User Defined
+
s.predefined).length > 0}> + Custom Volumes +
{#each persistentStorages.filter((s) => !s.predefined) as storage} {#key storage.id} {/key} {/each} - +