feat: Ghost service
This commit is contained in:
parent
e471b11d3b
commit
2475031f88
19
prisma/migrations/20220327180323_ghost/migration.sql
Normal file
19
prisma/migrations/20220327180323_ghost/migration.sql
Normal file
@ -0,0 +1,19 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Ghost" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"defaultEmail" TEXT NOT NULL,
|
||||
"defaultPassword" TEXT NOT NULL,
|
||||
"mariadbUser" TEXT NOT NULL,
|
||||
"mariadbPassword" TEXT NOT NULL,
|
||||
"mariadbRootUser" TEXT NOT NULL,
|
||||
"mariadbRootUserPassword" TEXT NOT NULL,
|
||||
"mariadbDatabase" TEXT,
|
||||
"mariadbPublicPort" INTEGER,
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Ghost_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Ghost_serviceId_key" ON "Ghost"("serviceId");
|
@ -278,6 +278,7 @@ model Service {
|
||||
minio Minio?
|
||||
vscodeserver Vscodeserver?
|
||||
wordpress Wordpress?
|
||||
ghost Ghost?
|
||||
serviceSecret ServiceSecret[]
|
||||
}
|
||||
|
||||
@ -332,3 +333,19 @@ model Wordpress {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Ghost {
|
||||
id String @id @default(cuid())
|
||||
defaultEmail String
|
||||
defaultPassword String
|
||||
mariadbUser String
|
||||
mariadbPassword String
|
||||
mariadbRootUser String
|
||||
mariadbRootUserPassword String
|
||||
mariadbDatabase String?
|
||||
mariadbPublicPort Int?
|
||||
serviceId String @unique
|
||||
service Service @relation(fields: [serviceId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
9
src/lib/components/svg/services/Ghost.svelte
Normal file
9
src/lib/components/svg/services/Ghost.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
export let isAbsolute = false;
|
||||
</script>
|
||||
|
||||
<img
|
||||
alt="ghost logo"
|
||||
class={isAbsolute ? 'w-12 absolute top-0 left-0 -m-3 -mt-5' : 'w-10 mx-auto'}
|
||||
src="/ghost.png"
|
||||
/>
|
@ -107,6 +107,7 @@ 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'],
|
||||
ports: {
|
||||
main: 8000
|
||||
@ -143,6 +144,7 @@ export const supportedServiceTypesAndVersions = [
|
||||
name: 'wordpress',
|
||||
fancyName: 'Wordpress',
|
||||
baseImage: 'wordpress',
|
||||
images: ['bitnami/mysql:5.7'],
|
||||
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
|
||||
ports: {
|
||||
main: 80
|
||||
@ -183,6 +185,16 @@ export const supportedServiceTypesAndVersions = [
|
||||
ports: {
|
||||
main: 3001
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ghost',
|
||||
fancyName: 'Ghost',
|
||||
baseImage: 'bitnami/ghost',
|
||||
images: ['bitnami/mariadb'],
|
||||
versions: ['latest'],
|
||||
ports: {
|
||||
main: 2368
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@ -207,6 +219,13 @@ export function getServiceImage(type) {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
export function getServiceImages(type) {
|
||||
const found = supportedServiceTypesAndVersions.find((t) => t.name === type);
|
||||
if (found) {
|
||||
return found.images;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
export function generateDatabaseConfiguration(database) {
|
||||
const {
|
||||
id,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { asyncExecShell, getEngine } from '$lib/common';
|
||||
import { decrypt, encrypt } from '$lib/crypto';
|
||||
import cuid from 'cuid';
|
||||
import { generatePassword } from '.';
|
||||
@ -20,6 +21,7 @@ export async function getService({ id, teamId }) {
|
||||
minio: true,
|
||||
vscodeserver: true,
|
||||
wordpress: true,
|
||||
ghost: true,
|
||||
serviceSecret: true
|
||||
}
|
||||
});
|
||||
@ -43,12 +45,18 @@ export async function getService({ id, teamId }) {
|
||||
if (body.wordpress?.mysqlRootUserPassword)
|
||||
body.wordpress.mysqlRootUserPassword = decrypt(body.wordpress.mysqlRootUserPassword);
|
||||
|
||||
if (body.ghost?.mariadbPassword) body.ghost.mariadbPassword = decrypt(body.ghost.mariadbPassword);
|
||||
if (body.ghost?.mariadbRootUserPassword)
|
||||
body.ghost.mariadbRootUserPassword = decrypt(body.ghost.mariadbRootUserPassword);
|
||||
if (body.ghost?.defaultPassword) body.ghost.defaultPassword = decrypt(body.ghost.defaultPassword);
|
||||
|
||||
if (body?.serviceSecret.length > 0) {
|
||||
body.serviceSecret = body.serviceSecret.map((s) => {
|
||||
s.value = decrypt(s.value);
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
return { ...body };
|
||||
}
|
||||
|
||||
@ -133,6 +141,30 @@ export async function configureServiceType({ id, type }) {
|
||||
type
|
||||
}
|
||||
});
|
||||
} else if (type === 'ghost') {
|
||||
const defaultEmail = `${cuid()}@coolify.io`;
|
||||
const defaultPassword = encrypt(generatePassword());
|
||||
const mariadbUser = cuid();
|
||||
const mariadbPassword = encrypt(generatePassword());
|
||||
const mariadbRootUser = cuid();
|
||||
const mariadbRootUserPassword = encrypt(generatePassword());
|
||||
|
||||
await prisma.service.update({
|
||||
where: { id },
|
||||
data: {
|
||||
type,
|
||||
ghost: {
|
||||
create: {
|
||||
defaultEmail,
|
||||
defaultPassword,
|
||||
mariadbUser,
|
||||
mariadbPassword,
|
||||
mariadbRootUser,
|
||||
mariadbRootUserPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
export async function setServiceVersion({ id, version }) {
|
||||
@ -174,8 +206,15 @@ export async function updateWordpress({ id, fqdn, name, mysqlDatabase, extraConf
|
||||
export async function updateMinioService({ id, publicPort }) {
|
||||
return await prisma.minio.update({ where: { serviceId: id }, data: { publicPort } });
|
||||
}
|
||||
export async function updateGhostService({ id, fqdn, name, mariadbDatabase }) {
|
||||
return await prisma.service.update({
|
||||
where: { id },
|
||||
data: { fqdn, name, ghost: { update: { mariadbDatabase } } }
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeService({ id }) {
|
||||
await prisma.ghost.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.minio.deleteMany({ where: { serviceId: id } });
|
||||
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
|
||||
|
@ -104,6 +104,7 @@ export async function generateSSLCerts() {
|
||||
});
|
||||
for (const application of applications) {
|
||||
try {
|
||||
if (application.fqdn && application.destinationDockerId) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
@ -133,6 +134,7 @@ export async function generateSSLCerts() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Error during generateSSLCerts with ${application.fqdn}: ${error}`);
|
||||
}
|
||||
@ -143,13 +145,15 @@ export async function generateSSLCerts() {
|
||||
minio: true,
|
||||
plausibleAnalytics: true,
|
||||
vscodeserver: true,
|
||||
wordpress: true
|
||||
wordpress: true,
|
||||
ghost: true
|
||||
},
|
||||
orderBy: { createdAt: 'desc' }
|
||||
});
|
||||
|
||||
for (const service of services) {
|
||||
try {
|
||||
if (service.fqdn && service.destinationDockerId) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
@ -165,6 +169,7 @@ export async function generateSSLCerts() {
|
||||
if (isHttps) ssls.push({ domain, id, isCoolify: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Error during generateSSLCerts with ${service.fqdn}: ${error}`);
|
||||
}
|
||||
|
@ -103,7 +103,7 @@
|
||||
}
|
||||
async function forceRestartProxy() {
|
||||
const sure = confirm(
|
||||
'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
|
||||
'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
|
||||
);
|
||||
if (sure) {
|
||||
try {
|
||||
|
@ -106,7 +106,7 @@
|
||||
}
|
||||
async function forceRestartProxy() {
|
||||
const sure = confirm(
|
||||
'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
|
||||
'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
|
||||
);
|
||||
if (sure) {
|
||||
try {
|
||||
|
90
src/routes/services/[id]/_Services/_Ghost.svelte
Normal file
90
src/routes/services/[id]/_Services/_Ghost.svelte
Normal file
@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
export let readOnly;
|
||||
export let service;
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">Ghost</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="email">Default Email Address</label>
|
||||
<input
|
||||
name="email"
|
||||
id="email"
|
||||
disabled
|
||||
readonly
|
||||
placeholder="Email address"
|
||||
value={service.ghost.defaultEmail}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="defaultPassword">Default Password</label>
|
||||
<CopyPasswordField
|
||||
id="defaultPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="defaultPassword"
|
||||
value={service.ghost.defaultPassword}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex space-x-1 py-5 font-bold">
|
||||
<div class="title">MariaDB</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbUser">Username</label>
|
||||
<CopyPasswordField
|
||||
name="mariadbUser"
|
||||
id="mariadbUser"
|
||||
value={service.ghost.mariadbUser}
|
||||
readonly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbPassword">Password</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mariadbPassword"
|
||||
value={service.ghost.mariadbPassword}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbDatabase">Database</label>
|
||||
<input
|
||||
name="mariadbDatabase"
|
||||
id="mariadbDatabase"
|
||||
required
|
||||
readonly={readOnly}
|
||||
disabled={readOnly}
|
||||
bind:value={service.ghost.mariadbDatabase}
|
||||
placeholder="eg: ghost_db"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUser">Root DB User</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbRootUser"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mariadbRootUser"
|
||||
value={service.ghost.mariadbRootUser}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="mariadbRootUserPassword">Root DB Password</label>
|
||||
<CopyPasswordField
|
||||
id="mariadbRootUserPassword"
|
||||
isPasswordField
|
||||
readonly
|
||||
disabled
|
||||
name="mariadbRootUserPassword"
|
||||
value={service.ghost.mariadbRootUserPassword}
|
||||
/>
|
||||
</div>
|
@ -10,6 +10,7 @@
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import Ghost from './_Ghost.svelte';
|
||||
import MinIo from './_MinIO.svelte';
|
||||
import PlausibleAnalytics from './_PlausibleAnalytics.svelte';
|
||||
import VsCodeServer from './_VSCodeServer.svelte';
|
||||
@ -142,6 +143,8 @@
|
||||
<VsCodeServer {service} />
|
||||
{:else if service.type === 'wordpress'}
|
||||
<Wordpress bind:service {isRunning} {readOnly} />
|
||||
{:else if service.type === 'ghost'}
|
||||
<Ghost bind:service {readOnly} />
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
|
@ -35,6 +35,7 @@
|
||||
}
|
||||
if (service.plausibleAnalytics?.email && service.plausibleAnalytics.username) readOnly = true;
|
||||
if (service.wordpress?.mysqlDatabase) readOnly = true;
|
||||
if (service.ghost?.mariadbDatabase && service.ghost.mariadbDatabase) readOnly = true;
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
@ -40,6 +40,7 @@
|
||||
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';
|
||||
import Ghost from '$lib/components/svg/services/Ghost.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@ -83,6 +84,8 @@
|
||||
<N8n isAbsolute />
|
||||
{:else if type.name === 'uptimekuma'}
|
||||
<UptimeKuma isAbsolute />
|
||||
{:else if type.name === 'ghost'}
|
||||
<Ghost isAbsolute />
|
||||
{/if}{type.fancyName}
|
||||
</button>
|
||||
</form>
|
||||
|
23
src/routes/services/[id]/ghost/index.json.ts
Normal file
23
src/routes/services/[id]/ghost/index.json.ts
Normal file
@ -0,0 +1,23 @@
|
||||
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,
|
||||
ghost: { mariadbDatabase }
|
||||
} = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
try {
|
||||
await db.updateGhostService({ id, fqdn, name, mariadbDatabase });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
134
src/routes/services/[id]/ghost/start.json.ts
Normal file
134
src/routes/services/[id]/ghost/start.json.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import {
|
||||
asyncExecShell,
|
||||
createDirectories,
|
||||
getDomain,
|
||||
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,
|
||||
fqdn,
|
||||
ghost: {
|
||||
defaultEmail,
|
||||
defaultPassword,
|
||||
mariadbRootUser,
|
||||
mariadbRootUserPassword,
|
||||
mariadbDatabase,
|
||||
mariadbPassword,
|
||||
mariadbUser
|
||||
}
|
||||
} = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
const domain = getDomain(fqdn);
|
||||
const config = {
|
||||
ghost: {
|
||||
image: `${image}:${version}`,
|
||||
volume: `${id}-ghost:/bitnami/ghost`,
|
||||
environmentVariables: {
|
||||
GHOST_HOST: domain,
|
||||
GHOST_EMAIL: defaultEmail,
|
||||
GHOST_PASSWORD: defaultPassword,
|
||||
GHOST_DATABASE_HOST: `${id}-mariadb`,
|
||||
GHOST_DATABASE_USER: mariadbUser,
|
||||
GHOST_DATABASE_PASSWORD: mariadbPassword,
|
||||
GHOST_DATABASE_NAME: mariadbDatabase,
|
||||
GHOST_DATABASE_PORT_NUMBER: 3306
|
||||
}
|
||||
},
|
||||
mariadb: {
|
||||
image: `bitnami/mariadb:latest`,
|
||||
volume: `${id}-mariadb:/bitnami/mariadb`,
|
||||
environmentVariables: {
|
||||
MARIADB_USER: mariadbUser,
|
||||
MARIADB_PASSWORD: mariadbPassword,
|
||||
MARIADB_DATABASE: mariadbDatabase,
|
||||
MARIADB_ROOT_USER: mariadbRootUser,
|
||||
MARIADB_ROOT_PASSWORD: mariadbRootUserPassword
|
||||
}
|
||||
}
|
||||
};
|
||||
if (serviceSecret.length > 0) {
|
||||
serviceSecret.forEach((secret) => {
|
||||
config.ghost.environmentVariables[secret.name] = secret.value;
|
||||
});
|
||||
}
|
||||
const composeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[id]: {
|
||||
container_name: id,
|
||||
image: config.ghost.image,
|
||||
networks: [network],
|
||||
volumes: [config.ghost.volume],
|
||||
environment: config.ghost.environmentVariables,
|
||||
restart: 'always',
|
||||
labels: makeLabelForServices('ghost'),
|
||||
depends_on: [`${id}-mariadb`]
|
||||
},
|
||||
[`${id}-mariadb`]: {
|
||||
container_name: `${id}-mariadb`,
|
||||
image: config.mariadb.image,
|
||||
networks: [network],
|
||||
volumes: [config.mariadb.volume],
|
||||
environment: config.mariadb.environmentVariables,
|
||||
restart: 'always'
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: true
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[config.ghost.volume.split(':')[0]]: {
|
||||
name: config.ghost.volume.split(':')[0]
|
||||
},
|
||||
[config.mariadb.volume.split(':')[0]]: {
|
||||
name: config.mariadb.volume.split(':')[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
console.log(JSON.stringify(composeFile.volumes));
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
}
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
39
src/routes/services/[id]/ghost/stop.json.ts
Normal file
39
src/routes/services/[id]/ghost/stop.json.ts
Normal file
@ -0,0 +1,39 @@
|
||||
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 {
|
||||
let found = await checkContainer(engine, id);
|
||||
if (found) {
|
||||
await removeDestinationDocker({ id, engine });
|
||||
}
|
||||
found = await checkContainer(engine, `${id}-mariadb`);
|
||||
if (found) {
|
||||
await removeDestinationDocker({ id: `${id}-mariadb`, engine });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
@ -4,7 +4,8 @@ import {
|
||||
generateDatabaseConfiguration,
|
||||
getServiceImage,
|
||||
getVersions,
|
||||
ErrorHandler
|
||||
ErrorHandler,
|
||||
getServiceImages
|
||||
} from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
@ -23,7 +24,13 @@ export const get: RequestHandler = async (event) => {
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const docker = dockerInstance({ destinationDocker });
|
||||
const baseImage = getServiceImage(type);
|
||||
const images = getServiceImages(type);
|
||||
docker.engine.pull(`${baseImage}:${version}`);
|
||||
if (images?.length > 0) {
|
||||
for (const image of images) {
|
||||
docker.engine.pull(`${image}:latest`);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}`
|
||||
|
@ -41,6 +41,7 @@
|
||||
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';
|
||||
import Ghost from '$lib/components/svg/services/Ghost.svelte';
|
||||
|
||||
export let service;
|
||||
export let isRunning;
|
||||
@ -119,6 +120,10 @@
|
||||
<a href="https://github.com/louislam/uptime-kuma" target="_blank">
|
||||
<UptimeKuma />
|
||||
</a>
|
||||
{:else if service.type === 'ghost'}
|
||||
<a href="https://ghost.org" target="_blank">
|
||||
<Ghost />
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,7 +41,7 @@ export const post: RequestHandler = async (event) => {
|
||||
networks: [network],
|
||||
environment: config.environmentVariables,
|
||||
restart: 'always',
|
||||
volumes: [`${id}-ngrams:/ngrams`],
|
||||
volumes: [config.volume],
|
||||
labels: makeLabelForServices('languagetool')
|
||||
}
|
||||
},
|
||||
@ -51,20 +51,20 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[`${id}-ngrams`]: {
|
||||
external: true
|
||||
[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 volume create ${id}-ngrams`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
}
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
@ -76,19 +76,13 @@ export const post: RequestHandler = async (event) => {
|
||||
},
|
||||
volumes: {
|
||||
[config.volume.split(':')[0]]: {
|
||||
external: true
|
||||
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 volume create ${config.volume.split(':')[0]}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await db.updateMinioService({ id, publicPort });
|
||||
|
@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => {
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
}
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
@ -52,6 +52,11 @@ export const post: RequestHandler = async (event) => {
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
}
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
@ -158,29 +158,21 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
||||
},
|
||||
volumes: {
|
||||
[config.postgresql.volume.split(':')[0]]: {
|
||||
external: true
|
||||
name: config.postgresql.volume.split(':')[0]
|
||||
},
|
||||
[config.clickhouse.volume.split(':')[0]]: {
|
||||
external: true
|
||||
name: config.clickhouse.volume.split(':')[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
try {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker volume create ${config.postgresql.volume.split(':')[0]}`
|
||||
);
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker volume create ${config.clickhouse.volume.split(':')[0]}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
|
||||
}
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up --build -d`
|
||||
);
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => {
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
}
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
@ -52,20 +52,18 @@ export const post: RequestHandler = async (event) => {
|
||||
},
|
||||
volumes: {
|
||||
[config.volume.split(':')[0]]: {
|
||||
external: true
|
||||
name: config.volume.split(':')[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}`
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
@ -61,22 +61,16 @@ export const post: RequestHandler = async (event) => {
|
||||
},
|
||||
volumes: {
|
||||
[config.volume.split(':')[0]]: {
|
||||
external: true
|
||||
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 volume create ${config.volume.split(':')[0]}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
@ -84,7 +78,4 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
@ -72,6 +72,7 @@ export const post: RequestHandler = async (event) => {
|
||||
container_name: id,
|
||||
image: config.wordpress.image,
|
||||
environment: config.wordpress.environmentVariables,
|
||||
volumes: [config.wordpress.volume],
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
depends_on: [`${id}-mysql`],
|
||||
@ -80,6 +81,7 @@ export const post: RequestHandler = async (event) => {
|
||||
[`${id}-mysql`]: {
|
||||
container_name: `${id}-mysql`,
|
||||
image: config.mysql.image,
|
||||
volumes: [config.mysql.volume],
|
||||
environment: config.mysql.environmentVariables,
|
||||
networks: [network],
|
||||
restart: 'always'
|
||||
@ -91,29 +93,22 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[config.mysql.volume.split(':')[0]]: {
|
||||
external: true
|
||||
},
|
||||
[config.wordpress.volume.split(':')[0]]: {
|
||||
external: true
|
||||
name: config.wordpress.volume.split(':')[0]
|
||||
},
|
||||
[config.mysql.volume.split(':')[0]]: {
|
||||
name: config.mysql.volume.split(':')[0]
|
||||
}
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
|
||||
try {
|
||||
if (version === 'latest') {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker volume create ${config.mysql.volume.split(':')[0]}`
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
|
||||
);
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker volume create ${config.wordpress.volume.split(':')[0]}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
|
BIN
static/ghost.png
Normal file
BIN
static/ghost.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Loading…
Reference in New Issue
Block a user