mirror of
https://github.com/ershisan99/coolify.git
synced 2026-02-04 21:02:05 +00:00
219 lines
6.8 KiB
TypeScript
219 lines
6.8 KiB
TypeScript
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';
|
|
import type { ComposeFile } from '$lib/types/composeFile';
|
|
import type { Service, DestinationDocker, Prisma } from '@prisma/client';
|
|
import bcrypt from 'bcryptjs';
|
|
import { getServiceMainPort } from '$lib/components/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: Service & Prisma.ServiceInclude & { destinationDocker: DestinationDocker } =
|
|
await db.getService({ id, teamId });
|
|
const {
|
|
type,
|
|
version,
|
|
destinationDockerId,
|
|
destinationDocker,
|
|
serviceSecret,
|
|
exposePort,
|
|
umami: {
|
|
umamiAdminPassword,
|
|
postgresqlUser,
|
|
postgresqlPassword,
|
|
postgresqlDatabase,
|
|
hashSalt
|
|
}
|
|
} = service;
|
|
const network = destinationDockerId && destinationDocker.network;
|
|
const host = getEngine(destinationDocker.engine);
|
|
const port = getServiceMainPort('umami');
|
|
|
|
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
|
const image = getServiceImage(type);
|
|
|
|
const config = {
|
|
umami: {
|
|
image: `${image}:${version}`,
|
|
environmentVariables: {
|
|
DATABASE_URL: `postgresql://${postgresqlUser}:${postgresqlPassword}@${id}-postgresql:5432/${postgresqlDatabase}`,
|
|
DATABASE_TYPE: 'postgresql',
|
|
HASH_SALT: hashSalt
|
|
}
|
|
},
|
|
postgresql: {
|
|
image: 'postgres:12-alpine',
|
|
volume: `${id}-postgresql-data:/var/lib/postgresql/data`,
|
|
environmentVariables: {
|
|
POSTGRES_USER: postgresqlUser,
|
|
POSTGRES_PASSWORD: postgresqlPassword,
|
|
POSTGRES_DB: postgresqlDatabase
|
|
}
|
|
}
|
|
};
|
|
if (serviceSecret.length > 0) {
|
|
serviceSecret.forEach((secret) => {
|
|
config.umami.environmentVariables[secret.name] = secret.value;
|
|
});
|
|
}
|
|
|
|
const initDbSQL = `
|
|
drop table if exists event;
|
|
drop table if exists pageview;
|
|
drop table if exists session;
|
|
drop table if exists website;
|
|
drop table if exists account;
|
|
|
|
create table account (
|
|
user_id serial primary key,
|
|
username varchar(255) unique not null,
|
|
password varchar(60) not null,
|
|
is_admin bool not null default false,
|
|
created_at timestamp with time zone default current_timestamp,
|
|
updated_at timestamp with time zone default current_timestamp
|
|
);
|
|
|
|
create table website (
|
|
website_id serial primary key,
|
|
website_uuid uuid unique not null,
|
|
user_id int not null references account(user_id) on delete cascade,
|
|
name varchar(100) not null,
|
|
domain varchar(500),
|
|
share_id varchar(64) unique,
|
|
created_at timestamp with time zone default current_timestamp
|
|
);
|
|
|
|
create table session (
|
|
session_id serial primary key,
|
|
session_uuid uuid unique not null,
|
|
website_id int not null references website(website_id) on delete cascade,
|
|
created_at timestamp with time zone default current_timestamp,
|
|
hostname varchar(100),
|
|
browser varchar(20),
|
|
os varchar(20),
|
|
device varchar(20),
|
|
screen varchar(11),
|
|
language varchar(35),
|
|
country char(2)
|
|
);
|
|
|
|
create table pageview (
|
|
view_id serial primary key,
|
|
website_id int not null references website(website_id) on delete cascade,
|
|
session_id int not null references session(session_id) on delete cascade,
|
|
created_at timestamp with time zone default current_timestamp,
|
|
url varchar(500) not null,
|
|
referrer varchar(500)
|
|
);
|
|
|
|
create table event (
|
|
event_id serial primary key,
|
|
website_id int not null references website(website_id) on delete cascade,
|
|
session_id int not null references session(session_id) on delete cascade,
|
|
created_at timestamp with time zone default current_timestamp,
|
|
url varchar(500) not null,
|
|
event_type varchar(50) not null,
|
|
event_value varchar(50) not null
|
|
);
|
|
|
|
create index website_user_id_idx on website(user_id);
|
|
|
|
create index session_created_at_idx on session(created_at);
|
|
create index session_website_id_idx on session(website_id);
|
|
|
|
create index pageview_created_at_idx on pageview(created_at);
|
|
create index pageview_website_id_idx on pageview(website_id);
|
|
create index pageview_session_id_idx on pageview(session_id);
|
|
create index pageview_website_id_created_at_idx on pageview(website_id, created_at);
|
|
create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at);
|
|
|
|
create index event_created_at_idx on event(created_at);
|
|
create index event_website_id_idx on event(website_id);
|
|
create index event_session_id_idx on event(session_id);
|
|
|
|
insert into account (username, password, is_admin) values ('admin', '${bcrypt.hashSync(
|
|
umamiAdminPassword,
|
|
10
|
|
)}', true);`;
|
|
await fs.writeFile(`${workdir}/schema.postgresql.sql`, initDbSQL);
|
|
const Dockerfile = `
|
|
FROM ${config.postgresql.image}
|
|
COPY ./schema.postgresql.sql /docker-entrypoint-initdb.d/schema.postgresql.sql`;
|
|
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile);
|
|
const composeFile: ComposeFile = {
|
|
version: '3.8',
|
|
services: {
|
|
[id]: {
|
|
container_name: id,
|
|
image: config.umami.image,
|
|
environment: config.umami.environmentVariables,
|
|
networks: [network],
|
|
volumes: [],
|
|
restart: 'always',
|
|
...(exposePort ? { ports: [`${port}:${port}`] } : {}),
|
|
labels: makeLabelForServices('umami'),
|
|
deploy: {
|
|
restart_policy: {
|
|
condition: 'on-failure',
|
|
delay: '5s',
|
|
max_attempts: 3,
|
|
window: '120s'
|
|
}
|
|
},
|
|
depends_on: [`${id}-postgresql`]
|
|
},
|
|
[`${id}-postgresql`]: {
|
|
build: workdir,
|
|
container_name: `${id}-postgresql`,
|
|
environment: config.postgresql.environmentVariables,
|
|
networks: [network],
|
|
volumes: [config.postgresql.volume],
|
|
restart: 'always',
|
|
deploy: {
|
|
restart_policy: {
|
|
condition: 'on-failure',
|
|
delay: '5s',
|
|
max_attempts: 3,
|
|
window: '120s'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
networks: {
|
|
[network]: {
|
|
external: true
|
|
}
|
|
},
|
|
volumes: {
|
|
[config.postgresql.volume.split(':')[0]]: {
|
|
name: config.postgresql.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} pull`);
|
|
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
|
return {
|
|
status: 200
|
|
};
|
|
} catch (error) {
|
|
console.log(error);
|
|
return ErrorHandler(error);
|
|
}
|
|
} catch (error) {
|
|
return ErrorHandler(error);
|
|
}
|
|
};
|