From 8ef5604ce81077ffb3cdf9c8af7e764b7e02ffd2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 18 Oct 2022 13:52:47 +0200 Subject: [PATCH] updates --- apps/api/src/lib.ts | 96 ++++++++--- apps/api/src/lib/templates.ts | 154 ++++++++++++++++++ .../src/routes/api/v1/services/handlers.ts | 1 - .../src/routes/services/[id]/storages.svelte | 4 +- 4 files changed, 230 insertions(+), 25 deletions(-) diff --git a/apps/api/src/lib.ts b/apps/api/src/lib.ts index cdd197e1f..dbe67a064 100644 --- a/apps/api/src/lib.ts +++ b/apps/api/src/lib.ts @@ -8,38 +8,90 @@ export async function migrateServicesToNewTemplate() { const services = await prisma.service.findMany({ include: includeServices }) for (const service of services) { if (service.type === 'plausibleanalytics' && service.plausibleAnalytics) await plausibleAnalytics(service) - + if (service.type === 'fider' && service.fider) await fider(service) } } catch (error) { console.log(error) } } -async function n8n(service: any) { +async function migrateSettings(settings: any[], service: any) { + for (const setting of settings) { + if (!setting) continue; + const [name, value] = setting.split('@@@') + console.log('Migrating setting', name, value) + await prisma.serviceSetting.findFirst({ where: { name } }) || await prisma.serviceSetting.create({ data: { name, value, service: { connect: { id: service.id } } } }) + } +} +async function migrateSecrets(secrets: any[], service: any) { + for (const secret of secrets) { + if (!secret) continue; + const [name, value] = secret.split('@@@') + console.log('Migrating secret', name, value) + await prisma.serviceSecret.findFirst({ where: { name } }) || await prisma.serviceSecret.create({ data: { name, value, service: { connect: { id: service.id } } } }) + } +} +async function createVolumes(volumes: any[], service: any) { + for (const volume of volumes) { + const [volumeName, path, containerId] = volume.split('@@@') + await prisma.servicePersistentStorage.findFirst({ where: { volumeName } }) || await prisma.servicePersistentStorage.create({ data: { volumeName, path, containerId, predefined: true, service: { connect: { id: service.id } } } }) + } +} +async function fider(service: any) { + const { postgresqlUser, postgresqlPassword, postgresqlDatabase, jwtSecret, emailNoreply, emailMailgunApiKey, emailMailgunDomain, emailMailgunRegion, emailSmtpHost, emailSmtpPort, emailSmtpUser, emailSmtpPassword, emailSmtpEnableStartTls } = service.fider + + const secrets = [ + `JWT_SECRET@@@${jwtSecret}`, + emailMailgunApiKey && `EMAIL_MAILGUN_API_KEY@@@${emailMailgunApiKey}`, + emailSmtpPassword && `EMAIL_SMTP_PASSWORD@@@${emailSmtpPassword}`, + `POSTGRES_PASSWORD@@@${postgresqlPassword}`, + ] + const settings = [ + `BASE_URL@@@$$generate_fqdn`, + `EMAIL_NOREPLY@@@${emailNoreply || 'noreply@example.com'}`, + `EMAIL_MAILGUN_DOMAIN@@@${emailMailgunDomain || ''}`, + `EMAIL_MAILGUN_REGION@@@${emailMailgunRegion || ''}`, + `EMAIL_SMTP_HOST@@@${emailSmtpHost || ''}`, + `EMAIL_SMTP_PORT@@@${emailSmtpPort || 587}`, + `EMAIL_SMTP_USER@@@${emailSmtpUser || ''}`, + `EMAIL_SMTP_PASSWORD@@@${emailSmtpPassword || ''}`, + `EMAIL_SMTP_ENABLE_STARTTLS@@@${emailSmtpEnableStartTls || 'false'}`, + `POSTGRES_USER@@@${postgresqlUser}`, + `POSTGRES_DB@@@${postgresqlDatabase}`, + ] + await migrateSettings(settings, service); + await migrateSecrets(secrets, service); + + // Remove old service data + await prisma.service.update({ where: { id: service.id }, data: { fider: { delete: true } } }) + } async function plausibleAnalytics(service: any) { const { email = 'admin@example.com', username = 'admin', password, postgresqlUser, postgresqlPassword, postgresqlDatabase, secretKeyBase, scriptName } = service.plausibleAnalytics; - // Migrate Secrets - await prisma.serviceSecret.create({ data: { name: 'ADMIN_USER_PWD', value: password, service: { connect: { id: service.id } } } }) - await prisma.serviceSecret.create({ data: { name: 'SECRET_KEY_BASE', value: secretKeyBase, service: { connect: { id: service.id } } } }) - await prisma.serviceSecret.create({ data: { name: 'POSTGRESQL_PASSWORD', value: postgresqlPassword, service: { connect: { id: service.id } } } }) - await prisma.serviceSecret.create({ data: { name: 'DATABASE_URL', value: encrypt(`postgresql://${postgresqlUser}:${decrypt(postgresqlPassword)}@${service.id}-postgresql:5432/${postgresqlDatabase}`), service: { connect: { id: service.id } } } }) - await prisma.serviceSecret.create({ data: { name: 'CLICKHOUSE_DATABASE_URL', value: encrypt(`http://${service.id}-clickhouse:8123/plausible`), service: { connect: { id: service.id } } } }) - - // Migrate Configs - await prisma.serviceSetting.create({ data: { name: 'BASE_URL', value: '$$generate_fqdn', service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'ADMIN_USER_EMAIL', value: email, service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'ADMIN_USER_NAME', value: username, service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'DISABLE_AUTH', value: 'false', service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'DISABLE_REGISTRATION', value: 'true', service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'POSTGRESQL_USERNAME', value: postgresqlUser, service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'POSTGRESQL_DATABASE', value: postgresqlDatabase, service: { connect: { id: service.id } } } }) - await prisma.serviceSetting.create({ data: { name: 'SCRIPT_NAME', value: scriptName, service: { connect: { id: service.id } } } }) - - // Create predefined persistent volumes - await prisma.servicePersistentStorage.create({ data: { path: '/bitnami/postgresql', containerId: `${service.id}-postgresql`, volumeName: `${service.id}-postgresql-data`, predefined: true, service: { connect: { id: service.id } } } }) - await prisma.servicePersistentStorage.create({ data: { path: '/var/lib/clickhouse', containerId: `${service.id}-clickhouse`, volumeName: `${service.id}-clickhouse-data`, predefined: true, service: { connect: { id: service.id } } } }) + const settings = [ + `BASE_URL@@@$$generate_fqdn`, + `ADMIN_USER_EMAIL@@@${email}`, + `ADMIN_USER_NAME@@@${username}`, + `DISABLE_AUTH@@@false`, + `DISABLE_REGISTRATION@@@true`, + `POSTGRESQL_USER@@@${postgresqlUser}`, + `POSTGRESQL_DATABASE@@@${postgresqlDatabase}`, + `SCRIPT_NAME@@@${scriptName}`, + ] + const secrets = [ + `ADMIN_USER_PWD@@@${password}`, + `SECRET_KEY_BASE@@@${secretKeyBase}`, + `POSTGRES_PASSWORD@@@${postgresqlPassword}`, + `DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@$$generate_fqdn:5432/${postgresqlDatabase}`)}`, + ] + const volumes = [ + `${service.id}-postgresql-data@@@/bitnami/postgresql@@@${service.id}-postgresql`, + `${service.id}-clickhouse-data@@@/var/lib/clickhouse/data@@@${service.id}-clickhouse`, + ] + await migrateSettings(settings, service); + await migrateSecrets(secrets, service); + await createVolumes(volumes, service); // Remove old service data await prisma.service.update({ where: { id: service.id }, data: { plausibleAnalytics: { delete: true } } }) diff --git a/apps/api/src/lib/templates.ts b/apps/api/src/lib/templates.ts index 2454f0ab7..4b57163da 100644 --- a/apps/api/src/lib/templates.ts +++ b/apps/api/src/lib/templates.ts @@ -1,4 +1,158 @@ export default [ + { + "templateVersion": "1.0.0", + "serviceDefaultVersion": "0.21.1", + "name": "fider", + "displayName": "Fider", + "description": "Fider is a platform to collect and organize customer feedback.", + "services": { + "$$id": { + "name": "Fider", + "image": "getfider/fider:$$core_version", + "documentation": "Taken from https://hub.docker.com/r/getfider/fider/", + "depends_on": [ + '$$id-postgresql' + ], + "environment": [ + "BASE_URL=$$config_base_url", + "JWT_SECRET=$$secret_jwt_secret", + "EMAIL_NOREPLY=$$config_email_noreply", + "EMAIL_MAILGUN_API_KEY=$$secret_email_mailgun_api_key", + "EMAIL_MAILGUN_REGION=$$config_email_mailgun_region", + "EMAIL_MAILGUN_DOMAIN=$$config_email_mailgun_domain", + "EMAIL_SMTP_HOST=$$config_email_smtp_host", + "EMAIL_SMTP_PORT=$$config_email_smtp_port", + "EMAIL_SMTP_USER=$$config_email_smtp_user", + "EMAIL_SMTP_PASSWORD=$$secret_email_smtp_password", + "EMAIL_SMTP_ENABLE_STARTTLS=$$config_email_smtp_enable_starttls", + ], + "ports": [ + "3000" + ] + }, + "$$id-postgresql": { + "name": "PostgreSQL", + "documentation": "Taken from https://hub.docker.com/r/getfider/fider/", + "depends_on": [], + "image": "postgres:12-alpine", + "volumes": [ + "$$id-postgresql-data:/var/lib/postgresql/data" + ], + "environment": [ + "POSTGRES_USER=$$config_postgres_user", + "POSTGRES_PASSWORD=$$secret_postgres_password", + "POSTGRES_DB=$$config_postgres_db", + ] + } + }, + "variables": [ + { + "id": "$$config_base_url", + "name": "BASE_URL", + "label": "Base URL", + "defaultValue": "$$generate_fqdn", + "description": "", + }, + { + "id": "$$secret_database_url", + "name": "DATABASE_URL", + "label": "Database URL for PostgreSQL", + "defaultValue": "postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db", + "description": "", + }, + { + "id": "$$secret_jwt_secret", + "name": "JWT_SECRET", + "label": "JWT Secret", + "defaultValue": "$$generate_passphrase", + "description": "", + }, + { + "id": "$$config_email_noreply", + "name": "EMAIL_NOREPLY", + "label": "No Reply Email Address", + "defaultValue": "noreply@example.com", + "description": "", + }, + { + "id": "$$secret_email_mailgun_api_key", + "name": "EMAIL_MAILGUN_API_KEY", + "label": "Mailgun API Key", + "defaultValue": "", + "description": "", + }, + { + "id": "$$config_email_mailgun_region", + "name": "EMAIL_MAILGUN_REGION", + "label": "Mailgun Region", + "defaultValue": "EU", + "description": "", + }, + { + "id": "$$config_email_mailgun_domain", + "name": "EMAIL_MAILGUN_DOMAIN", + "label": "Mailgun Domain", + "defaultValue": "", + "description": "", + }, + { + "id": "$$config_email_smtp_host", + "name": "EMAIL_SMTP_HOST", + "label": "SMTP Host", + "defaultValue": "", + "description": "", + }, + { + "id": "$$config_email_smtp_port", + "name": "EMAIL_SMTP_PORT", + "label": "SMTP Port", + "defaultValue": "587", + "description": "", + }, + { + "id": "$$config_email_smtp_user", + "name": "EMAIL_SMTP_USER", + "label": "SMTP User", + "defaultValue": "", + "description": "", + }, + { + "id": "$$secret_email_smtp_password", + "name": "EMAIL_SMTP_PASSWORD", + "label": "SMTP Password", + "defaultValue": "", + "description": "", + }, + { + "id": "$$config_email_smtp_enable_starttls", + "name": "EMAIL_SMTP_ENABLE_STARTTLS", + "label": "SMTP Enable StartTLS", + "defaultValue": "false", + "description": "", + }, + { + "id": "$$config_postgres_user", + "name": "POSTGRES_USER", + "label": "PostgreSQL User", + "defaultValue": "$$generate_username", + "description": "", + }, + { + "id": "$$secret_postgres_password", + "name": "POSTGRES_PASSWORD", + "label": "PostgreSQL Password", + "defaultValue": "$$generate_password", + "description": "", + }, + { + "id": "$$config_postgres_db", + "name": "POSTGRES_DB", + "label": "PostgreSQL Database", + "defaultValue": "$$generate_username", + "description": "", + }, + ] + }, { "templateVersion": "1.0.0", "serviceDefaultVersion": "0.198.1", diff --git a/apps/api/src/routes/api/v1/services/handlers.ts b/apps/api/src/routes/api/v1/services/handlers.ts index 732b9f01f..a0149bc26 100644 --- a/apps/api/src/routes/api/v1/services/handlers.ts +++ b/apps/api/src/routes/api/v1/services/handlers.ts @@ -171,7 +171,6 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin } } return parsedTemplate - } export async function getService(request: FastifyRequest) { diff --git a/apps/ui/src/routes/services/[id]/storages.svelte b/apps/ui/src/routes/services/[id]/storages.svelte index a67ffe15b..663a262e8 100644 --- a/apps/ui/src/routes/services/[id]/storages.svelte +++ b/apps/ui/src/routes/services/[id]/storages.svelte @@ -43,14 +43,14 @@ {#if persistentStorages.filter((s) => s.predefined).length > 0} -
Predefined Persistent Volumes
+
Predefined
{/if} {#each persistentStorages.filter((s) => s.predefined) as storage} {#key storage.id} {/key} {/each} -
s.predefined).length > 0}>User Defined Persistent Volumes
+
s.predefined).length > 0}>User Defined
{#each persistentStorages.filter((s) => !s.predefined) as storage} {#key storage.id}