This commit is contained in:
Andras Bacsai 2022-11-02 15:19:20 +01:00
parent 923241ce1e
commit 2e713b459e
11 changed files with 243 additions and 93 deletions

View File

@ -1,3 +1,59 @@
- templateVersion: 1.0.0
defaultVersion: 0.56.2
type: trilium
name: Trilium Notes
services:
$$id:
image: zadam/trilium:$$core_version
environment: []
volumes:
- $$id-trilium:/home/node/trilium-data
ports:
- '8080'
variables: []
documentation: https://hub.docker.com/r/zadam/trilium
- templateVersion: 1.0.0
defaultVersion: 1.9.2
type: uptimekuma
name: UptimeKuma
services:
$$id:
image: louislam/uptime-kuma:$$core_version
environment: []
volumes:
- $$id-uptimekuma:/app/data
ports:
- '3001'
variables: []
documentation: https://hub.docker.com/r/louislam/uptime-kuma
- templateVersion: 1.0.0
defaultVersion: 5.8
type: languagetool
name: LanguageTool
services:
$$id:
image: silviof/docker-languagetool:$$core_version
environment: []
volumes:
- $$id-ngrams:/ngrams
ports:
- '8010'
variables: []
documentation: https://hub.docker.com/r/silviof/docker-languagetool
- templateVersion: 1.0.0
defaultVersion: 1.26.0
type: vaultwarden
name: VaultWarden
services:
$$id:
image: vaultwarden/server:$$core_version
environment: []
volumes:
- $$id-data:/data
ports:
- '80'
variables: []
documentation: https://hub.docker.com/r/vaultwarden/server
- templateVersion: 1.0.0
defaultVersion: 9.2.3
type: grafana
@ -39,8 +95,8 @@
- _APP_OPTIONS_ABUSE=$$config__app_options_abuse
- _APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn
- _APP_DOMAIN_TARGET=$$generate_fqdn
- _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port
- _APP_REDIS_USER=$$config__app_redis_user
@ -170,8 +226,8 @@
environment:
- _APP_ENV=$$config__app_env
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn
- _APP_DOMAIN_TARGET=$$generate_fqdn
- _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port
- _APP_REDIS_USER=$$config__app_redis_user
@ -272,7 +328,7 @@
- OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
volumes: []
entrypoint: usage --type database
"$$id-usage-timeseries":
"$$id-usage":
image: appwrite/appwrite:$$core_version
environment:
- _APP_ENV=$$config__app_env
@ -340,8 +396,8 @@
environment:
- _APP_ENV=$$config__app_env
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn
- _APP_DOMAIN_TARGET=$$generate_fqdn
- _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address
- _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port
@ -503,7 +559,7 @@
- id: "$$secret__app_db_root_pass"
name: MARIADB_ROOT_PASSWORD
label: MariaDB | _APP_DB_ROOT_PASS
defaultValue: "$$generate_hex(16)"
defaultValue: $$generate_hex(16)
description: MariaDB server root password.
- id: "$$config__app_db_schema"
name: MARIADB_DATABASE
@ -518,7 +574,7 @@
- id: "$$secret__app_db_pass"
name: MARIADB_PASSWORD
label: MariaDB | _APP_DB_PASS
defaultValue: "$$generate_hex(16)"
defaultValue: $$generate_hex(16)
description: MariaDB server user password.
- id: "$$config__app_influxdb_host"
name: _APP_INFLUXDB_HOST
@ -622,18 +678,18 @@
sensitive data on your server. Appwrite server encrypts all secret data on your
server like webhooks, HTTP passwords, user sessions, and storage files. Keep
it a secret and have a backup for it.
- id: "$$generate_fqdn"
- id: "$$config__app_domain"
name: _APP_DOMAIN
label: General | _APP_DOMAIN
defaultValue: localhost
defaultValue: $$generate_domain
description: Your Appwrite domain address. When setting a public suffix domain,
Appwrite will attempt to issue a valid SSL certificate automatically. When used
with a dev domain, Appwrite will assign a self-signed SSL certificate. The default
value is 'localhost'.
- id: "$$generate_fqdn"
- id: "$$config__app_domain_target"
name: _APP_DOMAIN_TARGET
label: General | _APP_DOMAIN_TARGET
defaultValue: localhost
defaultValue: $$generate_fqdn
description: A DNS A record hostname to serve as a CNAME target for your Appwrite
custom domains. You can use the same value as used for the Appwrite '_APP_DOMAIN'
variable. The default value is 'localhost'.
@ -1214,12 +1270,12 @@
image: 'glitchtip/glitchtip:$$core_version'
volumes: []
environment:
- PORT=3000
- GLITCHTIP_DOMAIN=$$config_glitchtip_domain
- SECRET_KEY=$$secret_secret_key
- DATABASE_URL=$$secret_database_url
- REDIS_URL=$$secret_redis_url
- DEFAULT_FROM_EMAIL=$$config_default_from_email
- EMAIL_URL=$$secret_email_url
- EMAIL_HOST=$$config_email_host
- EMAIL_PORT=$$config_email_port
- EMAIL_HOST_USER=$$config_email_host_user
@ -1233,8 +1289,41 @@
- DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email
- DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password
- DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username
- CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency
ports:
- '8000'
- '8080'
$$id-worker:
name: Celery Worker
command: ./bin/run-celery-with-beat.sh
depends_on:
- $$id-postgresql
- $$id-redis
image: 'glitchtip/glitchtip:$$core_version'
environment:
- GLITCHTIP_DOMAIN=$$config_glitchtip_domain
- SECRET_KEY=$$secret_secret_key
- DATABASE_URL=$$secret_database_url
- REDIS_URL=$$secret_redis_url
- DEFAULT_FROM_EMAIL=$$config_default_from_email
- EMAIL_URL=$$secret_email_url
- CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency
ports: []
$$id-migrate:
exclude: true
name: Migrate
command: ./manage.py migrate
depends_on:
- $$id-postgresql
- $$id-redis
image: 'glitchtip/glitchtip:$$core_version'
environment:
- GLITCHTIP_DOMAIN=$$config_glitchtip_domain
- SECRET_KEY=$$secret_secret_key
- DATABASE_URL=$$secret_database_url
- REDIS_URL=$$secret_redis_url
- DEFAULT_FROM_EMAIL=$$config_default_from_email
- EMAIL_URL=$$secret_email_url
ports: []
$$id-postgresql:
name: PostgreSQL
depends_on: []
@ -1255,11 +1344,23 @@
environment: []
ports: []
variables:
- id: $$config_celery_worker_concurrency
main: $$id-worker
name: CELERY_WORKER_CONCURRENCY
label: Celery Worker Concurrency
defaultValue: '2'
description: ''
- id: $$config_glitchtip_domain
name: GLITCHTIP_DOMAIN
label: GlitchTip Domain
defaultValue: $$generate_fqdn
description: ''
- id: $$secret_email_url
name: EMAIL_URL
label: SMTP Email URL
defaultValue: >-
smtp://$$config_email_host_user:$$secret_email_host_password@$$config_email_host:$$config_email_port
description: ''
- id: $$secret_database_url
name: DATABASE_URL
label: Database URL for PostgreSQL
@ -1321,11 +1422,13 @@
label: Mailgun API Key
defaultValue: ''
description: ''
showOnConfiguration: true
- id: $$secret_sendgrid_api_key
name: SENDGRID_API_KEY
label: Sendgrid API Key
defaultValue: ''
description: ''
showOnConfiguration: true
- id: $$config_enable_open_user_registration
name: ENABLE_OPEN_USER_REGISTRATION
label: Enable Open User Registration
@ -1334,12 +1437,12 @@
- id: $$config_django_superuser_email
name: DJANGO_SUPERUSER_EMAIL
label: Django Superuser Email
defaultValue: ''
defaultValue: noreply@example.com
description: ''
- id: $$config_django_superuser_username
name: DJANGO_SUPERUSER_USERNAME
label: Django Superuser Username
defaultValue: ''
defaultValue: $$generate_username
description: ''
- id: $$secret_django_superuser_password
name: DJANGO_SUPERUSER_PASSWORD
@ -1356,13 +1459,13 @@
main: $$id-postgresql
name: POSTGRES_PASSWORD
label: PostgreSQL Password
defaultValue: ''
defaultValue: $$generate_password
description: ''
- id: $$config_postgres_db
main: $$id-postgresql
name: POSTGRES_DB
label: PostgreSQL Database
defaultValue: hasura
defaultValue: glitchtip
description: ''
- templateVersion: 1.0.0
defaultVersion: v2.13.0
@ -1429,8 +1532,8 @@
description: ''
- templateVersion: 1.0.0
defaultVersion: postgresql-v1.38.0
type: umami
name: Umami
type: umami-postgresql
name: Umami (PostgreSQL)
description: >-
Umami is a simple, easy to use, self-hosted web analytics solution. The goal
is to provide you with a friendly privacy-focused alternative to Google
@ -1446,7 +1549,7 @@
environment:
- ADMIN_PASSWORD=$$secret_admin_password
- DATABASE_URL=$$secret_database_url
- DATABASE_TYPE=postgresql
- DATABASE_TYPE=$$config_database_type
- HASH_SALT=$$secret_hash_salt
ports:
- '3000'
@ -1610,6 +1713,11 @@
label: Hash Salt
defaultValue: $$generate_hex(64)
description: ''
- id: $$config_database_type
name: DATABASE_TYPE
label: Database Type
defaultValue: 'postgresql'
description: ''
- id: $$config_postgres_user
name: POSTGRES_USER
label: PostgreSQL User
@ -1711,7 +1819,7 @@
- id: $$config_ghost_host
name: GHOST_HOST
label: Ghost Host
defaultValue: ''
defaultValue: $$generate_domain
description: ''
- id: $$config_ghost_enable_https
name: GHOST_ENABLE_HTTPS
@ -1728,6 +1836,7 @@
label: Ghost Default Password
defaultValue: $$generate_password
description: ''
showOnConfiguration: true
- id: $$config_ghost_database_host
name: GHOST_DATABASE_HOST
label: Ghost Database Host
@ -1879,7 +1988,7 @@
- templateVersion: 1.0.0
defaultVersion: php8.1
type: wordpress-only
name: WordPress (without MySQL)
name: WordPress Only (No Database)
description: WordPress is a content management system based on PHP without MySQL.
services:
$$id:
@ -2148,7 +2257,7 @@
description: ''
- templateVersion: 1.0.0
defaultVersion: 0.198.1
type: n8nio
type: n8n
name: n8n.io
description: n8n is a free and open node based Workflow Automation Tool.
services:

View File

@ -113,18 +113,20 @@ export async function migrateServicesToNewTemplate() {
}
}
async function appwrite(service: any, template: any) {
const { opensslKeyV1, executorSecret, mariadbUser, mariadbPassword, mariadbRootUserPassword, mariadbDatabase } = service.appwrite
const { opensslKeyV1, executorSecret, mariadbHost, mariadbPort, mariadbUser, mariadbPassword, mariadbRootUserPassword, mariadbDatabase } = service.appwrite
const secrets = [
`_APP_EXECUTOR_SECRET@@@${executorSecret}`,
`_APP_OPENSSL_KEY_V1@@@${opensslKeyV1}`,
`MARIADB_PASSWORD@@@${mariadbPassword}`,
`MARIADB_ROOT_PASSWORD@@@${mariadbRootUserPassword}`,
`_APP_DB_PASS@@@${mariadbPassword}`,
`_APP_DB_ROOT_PASS@@@${mariadbRootUserPassword}`,
]
const settings = [
`MARIADB_USER@@@${mariadbUser}`,
`MARIADB_DATABASE@@@${mariadbDatabase}`,
`_APP_DB_HOST@@@${mariadbHost}`,
`_APP_DB_PORT@@@${mariadbPort}`,
`_APP_DB_USER@@@${mariadbUser}`,
`_APP_DB_SCHEMA@@@${mariadbDatabase}`,
]
await migrateSecrets(secrets, service);
await migrateSettings(settings, service, template);
@ -157,7 +159,6 @@ async function weblate(service: any, template: any) {
}
async function searxng(service: any, template: any) {
const { secretKey, redisPassword } = service.searxng
const { fqdn } = service
const secrets = [
`SECRET_KEY@@@${secretKey}`,
@ -165,7 +166,7 @@ async function searxng(service: any, template: any) {
]
const settings = [
`SEARXNG_BASE_URL@@@${fqdn || '$$generate_fqdn'}`
`SEARXNG_BASE_URL@@@$$generate_fqdn`
]
await migrateSettings(settings, service, template);
await migrateSecrets(secrets, service);
@ -180,20 +181,17 @@ async function glitchtip(service: any, template: any) {
const secrets = [
`POSTGRES_PASSWORD@@@${postgresqlPassword}`,
`SECRET_KEY@@@${secretKeyBase}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
`REDIS_URL@@@${encrypt(`redis://${id}-redis:6379`)}`,
`EMAIL_HOST_PASSWORD@@@${emailSmtpPassword}`,
`MAILGUN_API_KEY@@@${mailgunApiKey}`,
`SENDGRID_API_KEY@@@${sendgridApiKey}`,
`DJANGO_SUPERUSER_PASSWORD@@@${defaultPassword}`,
`EMAIL_URL@@@${encrypt(`smtp://${emailSmtpUser}:${decrypt(emailSmtpPassword)}@${emailSmtpHost}:${emailSmtpPort}`)}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
`REDIS_URL@@@${encrypt(`redis://${id}-redis:6379`)}`
]
const settings = [
`POSTGRES_USER@@@${postgresqlUser}`,
`POSTGRES_DB@@@${postgresqlDatabase}`,
`DEFAULT_FROM_EMAIL@@@${defaultEmailFrom}`,
`EMAIL_HOST@@@${emailSmtpHost}`,
`EMAIL_PORT@@@${emailSmtpPort}`,
`EMAIL_HOST_USER@@@${emailSmtpUser}`,
`EMAIL_USE_TLS@@@${emailSmtpUseTls}`,
`EMAIL_USE_SSL@@@${emailSmtpUseSsl}`,
`EMAIL_BACKEND@@@${emailBackend}`,
@ -205,7 +203,7 @@ async function glitchtip(service: any, template: any) {
await migrateSecrets(secrets, service);
// Remove old service data
// await prisma.service.update({ where: { id: service.id }, data: { wordpress: { delete: true } } })
await prisma.service.update({ where: { id: service.id }, data: { type: 'glitchtip' } })
}
async function hasura(service: any, template: any) {
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, graphQLAdminPassword } = service.hasura
@ -237,6 +235,7 @@ async function umami(service: any, template: any) {
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
]
const settings = [
`DATABASE_TYPE@@@postgresql`,
`POSTGRES_USER@@@${postgresqlUser}`,
`POSTGRES_DB@@@${postgresqlDatabase}`,
]
@ -280,8 +279,8 @@ async function ghost(service: any, template: any) {
`MARIADB_USER@@@${mariadbUser}`,
`MARIADB_DATABASE@@@${mariadbDatabase}`,
`MARIADB_ROOT_USER@@@${mariadbRootUser}`,
`GHOST_HOST@@@${getDomain(fqdn) || '$$generate_fqdn'}`,
`url@@@${fqdn || '$$generate_fqdn'}`,
`GHOST_HOST@@@$$generate_domain`,
`url@@@$$generate_fqdn`,
`GHOST_ENABLE_HTTPS@@@${isHttps ? 'yes' : 'no'}`
]
await migrateSettings(settings, service, template);
@ -355,7 +354,6 @@ async function vscodeserver(service: any, template: any) {
}
async function minio(service: any, template: any) {
const { rootUser, rootUserPassword, apiFqdn } = service.minio
const { fqdn } = service
const secrets = [
`MINIO_ROOT_PASSWORD@@@${rootUserPassword}`,
@ -363,8 +361,8 @@ async function minio(service: any, template: any) {
const settings = [
`MINIO_ROOT_USER@@@${rootUser}`,
`MINIO_SERVER_URL@@@${apiFqdn}`,
`MINIO_BROWSER_REDIRECT_URL@@@${fqdn || '$$generate_fqdn'}`,
`MINIO_DOMAIN@@@${getDomain(fqdn) || '$$generate_fqdn'}`,
`MINIO_BROWSER_REDIRECT_URL@@@$$generate_fqdn`,
`MINIO_DOMAIN@@@$$generate_domain`,
]
await migrateSettings(settings, service, template);
await migrateSecrets(secrets, service);
@ -374,15 +372,16 @@ async function minio(service: any, template: any) {
}
async function fider(service: any, template: any) {
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, jwtSecret, emailNoreply, emailMailgunApiKey, emailMailgunDomain, emailMailgunRegion, emailSmtpHost, emailSmtpPort, emailSmtpUser, emailSmtpPassword, emailSmtpEnableStartTls } = service.fider
const { fqdn } = service
const { id } = service
const secrets = [
`JWT_SECRET@@@${jwtSecret}`,
emailMailgunApiKey && `EMAIL_MAILGUN_API_KEY@@@${emailMailgunApiKey}`,
emailMailgunApiKey && `EMAIL_MAILGUN_API@@@${emailMailgunApiKey}`,
emailSmtpPassword && `EMAIL_SMTP_PASSWORD@@@${emailSmtpPassword}`,
`POSTGRES_PASSWORD@@@${postgresqlPassword}`,
`DATABASE_URL@@@${encrypt(`postgresql://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}?sslmode=disable`)}`
]
const settings = [
`BASE_URL@@@${fqdn || '$$generate_fqdn'}`,
`BASE_URL@@@$$generate_fqdn`,
`EMAIL_NOREPLY@@@${emailNoreply || 'noreply@example.com'}`,
`EMAIL_MAILGUN_DOMAIN@@@${emailMailgunDomain || ''}`,
`EMAIL_MAILGUN_REGION@@@${emailMailgunRegion || ''}`,
@ -403,22 +402,22 @@ async function fider(service: any, template: any) {
}
async function plausibleAnalytics(service: any, template: any) {
const { email, username, password, postgresqlUser, postgresqlPassword, postgresqlDatabase, secretKeyBase, scriptName } = service.plausibleAnalytics;
const { id, fqdn } = service
const { id } = service
const settings = [
`BASE_URL@@@${fqdn || '$$generate_fqdn'}`,
`BASE_URL@@@$$generate_fqdn`,
`ADMIN_USER_EMAIL@@@${email}`,
`ADMIN_USER_NAME@@@${username}`,
`DISABLE_AUTH@@@false`,
`DISABLE_REGISTRATION@@@true`,
`POSTGRESQL_USER@@@${postgresqlUser}`,
`POSTGRESQL_USERNAME@@@${postgresqlUser}`,
`POSTGRESQL_DATABASE@@@${postgresqlDatabase}`,
`SCRIPT_NAME@@@${scriptName}`,
]
const secrets = [
`ADMIN_USER_PWD@@@${password}`,
`SECRET_KEY_BASE@@@${secretKeyBase}`,
`POSTGRES_PASSWORD@@@${postgresqlPassword}`,
`POSTGRESQL_PASSWORD@@@${postgresqlPassword}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
]
await migrateSettings(settings, service, template);
@ -435,8 +434,12 @@ async function migrateSettings(settings: any[], service: any, template: any) {
if (!value || value === 'null') {
continue;
}
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name)
const variableName = template.variables.find((v: any) => v.name === name)?.id
let variableName = template.variables.find((v: any) => v.name === name)?.id
if (!variableName) {
variableName = `$$config_${name.toLowerCase()}`
}
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name, 'variableName: ', variableName)
await prisma.serviceSetting.findFirst({ where: { name, serviceId: service.id } }) || await prisma.serviceSetting.create({ data: { name, value, variableName, service: { connect: { id: service.id } } } })
}
}

View File

@ -80,11 +80,28 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
});
const containersArray = containers.trim().split('\n');
if (containersArray.length > 0 && containersArray[0] !== '') {
const templates = await getTemplates();
let template = templates.find(t => t.type === service.type);
template = JSON.parse(JSON.stringify(template).replaceAll('$$id', service.id));
for (const container of containersArray) {
let isRunning = false;
let isExited = false;
let isRestarting = false;
let isExcluded = false;
const containerObj = JSON.parse(container);
const exclude = template.services[containerObj.Names]?.exclude;
if (exclude) {
payload[containerObj.Names] = {
status: {
isExcluded: true,
isRunning: false,
isExited: false,
isRestarting: false,
}
}
continue;
}
const status = containerObj.State
if (status === 'running') {
isRunning = true;
@ -97,11 +114,11 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
}
payload[containerObj.Names] = {
status: {
isExcluded,
isRunning,
isExited,
isRestarting
}
}
}
}
@ -119,8 +136,20 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
if (!isDeploy) {
for (const [key, value] of Object.entries(foundTemplate.services)) {
const realKey = key.replace('$$id', service.id)
let name = value.name
if (!name) {
if (Object.keys(foundTemplate.services).length === 1) {
name = foundTemplate.name || service.name.toLowerCase()
} else {
if (key === '$$id') {
name = foundTemplate.name || key.replaceAll('$$id-', '') || service.name.toLowerCase()
} else {
name = key.replaceAll('$$id-', '') || service.name.toLowerCase()
}
}
}
parsedTemplate[realKey] = {
name: value.name,
name,
image: value.image,
environment: [],
fqdns: [],
@ -131,23 +160,26 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
let [envKey, ...envValue] = env.split('=')
envValue = envValue.join("=")
const variable = foundTemplate.variables.find(v => v.name === envKey) || foundTemplate.variables.find(v => v.id === envValue)
const id = variable.id.replaceAll('$$', '')
const label = variable?.label
const description = variable?.description
const defaultValue = variable?.defaultValue
const main = variable?.main || '$$id'
const type = variable?.type || 'input'
const placeholder = variable?.placeholder || ''
const readonly = variable?.readonly || false
const required = variable?.required || false
if (envValue.startsWith('$$config') || variable?.showOnConfiguration) {
if (envValue.startsWith('$$config_coolify')) {
continue
if (variable) {
const id = variable.id.replaceAll('$$', '')
const label = variable?.label
const description = variable?.description
const defaultValue = variable?.defaultValue
const main = variable?.main || '$$id'
const type = variable?.type || 'input'
const placeholder = variable?.placeholder || ''
const readonly = variable?.readonly || false
const required = variable?.required || false
if (envValue.startsWith('$$config') || variable?.showOnConfiguration) {
if (envValue.startsWith('$$config_coolify')) {
continue
}
parsedTemplate[realKey].environment.push(
{ id, name: envKey, value: envValue, main, label, description, defaultValue, type, placeholder, required, readonly }
)
}
parsedTemplate[realKey].environment.push(
{ id, name: envKey, value: envValue, main, label, description, defaultValue, type, placeholder, required, readonly }
)
}
}
}
if (value?.proxy && value.proxy.length > 0) {
@ -170,6 +202,7 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
} else {
parsedTemplate = foundTemplate
}
let strParsedTemplate = JSON.stringify(parsedTemplate)
// replace $$id and $$workdir
@ -185,17 +218,18 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
if (service.serviceSetting.length > 0) {
for (const setting of service.serviceSetting) {
const { value, variableName } = setting
const regex = new RegExp(`\\$\\$config_${variableName.replace('$$config_','')}\\"`, 'gi')
if (variableName.startsWith('$$config_coolify')) {
continue;
}
if (value === '$$generate_fqdn') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.fqdn || '')
strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn || '' + "\"")
} else if (value === '$$generate_domain') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, getDomain(service.fqdn))
strParsedTemplate = strParsedTemplate.replaceAll(regex, getDomain(service.fqdn) + "\"")
} else if (service.destinationDocker?.network && value === '$$generate_network') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.destinationDocker.network)
strParsedTemplate = strParsedTemplate.replaceAll(regex, service.destinationDocker.network + "\"")
} else {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, value)
strParsedTemplate = strParsedTemplate.replaceAll(regex, value + "\"")
}
}
}
@ -207,8 +241,8 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
const regexHashed = new RegExp(`\\$\\$hashed\\$\\$secret_${name}\\"`, 'gi')
const regex = new RegExp(`\\$\\$secret_${name}\\"`, 'gi')
if (value) {
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, bcrypt.hashSync(value, 10) + "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regex, value + "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, bcrypt.hashSync(value.replaceAll("\"", "\\\""), 10) + "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regex, value.replaceAll("\"", "\\\"") + "\"")
} else {
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regex, "\"")
@ -229,10 +263,11 @@ export async function getService(request: FastifyRequest<OnlyId>) {
throw { status: 404, message: 'Service not found.' }
}
let template = {}
let tags = []
if (service.type) {
template = await parseAndFindServiceTemplates(service)
tags = await getTags(service.type)
}
const tags = await getTags(service.type)
return {
settings: await listSettings(),
service,
@ -240,7 +275,6 @@ export async function getService(request: FastifyRequest<OnlyId>) {
tags
}
} catch ({ status, message }) {
console.log(status, message)
return errorHandler({ status, message })
}
}
@ -291,7 +325,7 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
}
}
if (variable.id.startsWith('$$config_')) {
if (variable.id.startsWith('$$config_') || variable.id.startsWith('$$coolify_fqdn_')) {
const found = await prisma.serviceSetting.findFirst({ where: { name: variable.name, serviceId: id } })
if (!found) {
await prisma.serviceSetting.create({
@ -513,7 +547,6 @@ export async function saveService(request: FastifyRequest<SaveService>, reply: F
});
return reply.code(201).send()
} catch ({ status, message }) {
console.log({ status, message })
return errorHandler({ status, message })
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,27 +2,33 @@
export let id: any;
import { status } from '$lib/store';
let serviceStatus = {
isExcluded: false,
isExited: false,
isRunning: false,
isRestarting: false,
isStopped: false
};
$: if (Object.keys($status.service.statuses).length > 0) {
let { isExited, isRunning, isRestarting } = $status.service.statuses[id].status;
$: if (Object.keys($status.service.statuses).length > 0 && $status.service.statuses[id]?.status) {
let { isExited, isRunning, isRestarting, isExcluded } = $status.service.statuses[id].status;
serviceStatus.isExited = isExited;
serviceStatus.isRunning = isRunning;
serviceStatus.isExcluded = isExcluded;
serviceStatus.isRestarting = isRestarting;
serviceStatus.isStopped = !isExited && !isRunning && !isRestarting;
} else {
serviceStatus.isExited = false;
serviceStatus.isRunning = false;
serviceStatus.isExcluded = false;
serviceStatus.isRestarting = false;
serviceStatus.isStopped = true;
}
</script>
{#if serviceStatus.isRunning}
{#if serviceStatus.isExcluded}
<span class="badge font-bold uppercase rounded text-orange-500 mt-2">Excluded</span>
{:else if serviceStatus.isRunning}
<span class="badge font-bold uppercase rounded text-green-500 mt-2">Running</span>
{:else if serviceStatus.isStopped || serviceStatus.isExited}
<span class="badge font-bold uppercase rounded text-red-500 mt-2">Stopped</span>

View File

@ -1,8 +1,8 @@
<script lang="ts">
import { Tooltip } from 'flowbite-svelte';
export let placement = 'bottom';
export let color = 'bg-coollabs font-thin text-left';
export let color = 'bg-coollabs font-thin text-left border-none p-4';
export let triggeredBy = '#tooltip-default';
</script>
<Tooltip {triggeredBy} {placement} arrow={false} {color} style="custom"><slot /></Tooltip>
<Tooltip {triggeredBy} {placement} arrow={false} defaultClass={color} style="custom"><slot /></Tooltip>

View File

@ -81,12 +81,11 @@
<span>Logs</span>
</li>
<li
class:text-stone-600={$status.service.overallStatus === 'stopped'}
class="rounded"
class:bg-coollabs={$page.url.pathname === `/services/${$page.params.id}/logs`}
>
<a
href={$status.service.overallStatus !== 'stopped' ? `/services/${$page.params.id}/logs` : ''}
href={`/services/${$page.params.id}/logs`}
class="no-underline w-full"
><svg
xmlns="http://www.w3.org/2000/svg"

View File

@ -127,7 +127,7 @@
await post(`/services/${id}/wordpress/ftp`, {
ftpEnabled: false
});
service.wordpress?.ftpEnabled && window.location.reload()
service.wordpress?.ftpEnabled && window.location.reload();
}
} catch (error) {
return errorNotification(error);

View File

@ -34,7 +34,7 @@
if (sure) {
$status.service.initialLoading = true;
try {
if (service.type && $status.service.isRunning) {
if (service.type && $status.service.overallStatus !== 'stopped') {
await post(`/services/${service.id}/stop`, {});
}
await del(`/services/${service.id}`, { id: service.id });
@ -61,6 +61,6 @@
class:hover:bg-red-500={$appSession.isAdmin}
class="btn btn-lg btn-error text-sm"
>
Delete Application
Delete Service
</button>
</div>

View File

@ -420,7 +420,7 @@
{#if template[oneService].environment.length > 0}
{#each template[oneService].environment as variable}
{#if variable.main === oneService}
<div class="grid grid-cols-2 items-center gap-2" >
<div class="grid grid-cols-2 items-center gap-2">
<label class="h-10" for={variable.name}
>{variable.label || variable.name}
{#if variable.description}