This commit is contained in:
Andras Bacsai
2022-12-12 16:04:41 +01:00
parent 2007ba0c3b
commit 4ad7e1f8e6
21 changed files with 520 additions and 198 deletions

View File

@@ -68,8 +68,8 @@ export const decrypt = (hashString: string) => {
return false;
};
export function generateRangeArray(start, end) {
return Array.from({ length: end - start }, (v, k) => k + start);
export function generateRangeArray(start: number, end: number) {
return Array.from({ length: end - start }, (_v, k) => k + start);
}
export function generateTimestamp(): string {
return `${day().format('HH:mm:ss.SSS')}`;
@@ -94,7 +94,7 @@ export async function getTemplates() {
let data = await open.readFile({ encoding: 'utf-8' });
let jsonData = JSON.parse(data);
if (isARM(process.arch)) {
jsonData = jsonData.filter((d) => d.arch !== 'amd64');
jsonData = jsonData.filter((d: { arch: string }) => d.arch !== 'amd64');
}
return jsonData;
} catch (error) {
@@ -109,3 +109,26 @@ export function isARM(arch: string) {
}
return false;
}
export async function removeService({ id }: { id: string }): Promise<void> {
await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
await prisma.serviceSetting.deleteMany({ where: { serviceId: id } });
await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
await prisma.fider.deleteMany({ where: { serviceId: id } });
await prisma.ghost.deleteMany({ where: { serviceId: id } });
await prisma.umami.deleteMany({ where: { serviceId: id } });
await prisma.hasura.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 } });
await prisma.wordpress.deleteMany({ where: { serviceId: id } });
await prisma.glitchTip.deleteMany({ where: { serviceId: id } });
await prisma.moodle.deleteMany({ where: { serviceId: id } });
await prisma.appwrite.deleteMany({ where: { serviceId: id } });
await prisma.searxng.deleteMany({ where: { serviceId: id } });
await prisma.weblate.deleteMany({ where: { serviceId: id } });
await prisma.taiga.deleteMany({ where: { serviceId: id } });
await prisma.service.delete({ where: { id } });
}

View File

@@ -1,31 +1,39 @@
import { executeCommand } from "./executeCommand";
import { executeCommand } from './executeCommand';
export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> {
export async function checkContainer({
dockerId,
container,
remove = false
}: {
dockerId: string;
container: string;
remove?: boolean;
}): Promise<{
found: boolean;
status?: { isExited: boolean; isRunning: boolean; isRestarting: boolean };
}> {
let containerFound = false;
try {
const { stdout } = await executeCommand({
dockerId,
command:
`docker inspect --format '{{json .State}}' ${container}`
command: `docker inspect --format '{{json .State}}' ${container}`
});
containerFound = true
containerFound = true;
const parsedStdout = JSON.parse(stdout);
const status = parsedStdout.Status;
const isRunning = status === 'running';
const isRestarting = status === 'restarting'
const isExited = status === 'exited'
const isRestarting = status === 'restarting';
const isExited = status === 'exited';
if (status === 'created') {
await executeCommand({
dockerId,
command:
`docker rm ${container}`
command: `docker rm ${container}`
});
}
if (remove && status === 'exited') {
await executeCommand({
dockerId,
command:
`docker rm ${container}`
command: `docker rm ${container}`
});
}
@@ -43,5 +51,74 @@ export async function checkContainer({ dockerId, container, remove = false }: {
return {
found: false
};
}
}
export async function removeContainer({
id,
dockerId
}: {
id: string;
dockerId: string;
}): Promise<void> {
try {
const { stdout } = await executeCommand({
dockerId,
command: `docker inspect --format '{{json .State}}' ${id}`
});
if (JSON.parse(stdout).Running) {
await executeCommand({ dockerId, command: `docker stop -t 0 ${id}` });
await executeCommand({ dockerId, command: `docker rm ${id}` });
}
if (JSON.parse(stdout).Status === 'exited') {
await executeCommand({ dockerId, command: `docker rm ${id}` });
}
} catch (error) {
throw error;
}
}
export async function stopDatabaseContainer(database: any): Promise<boolean> {
let everStarted = false;
const {
id,
destinationDockerId,
destinationDocker: { engine, id: dockerId }
} = database;
if (destinationDockerId) {
try {
const { stdout } = await executeCommand({
dockerId,
command: `docker inspect --format '{{json .State}}' ${id}`
});
if (stdout) {
everStarted = true;
await removeContainer({ id, dockerId });
}
} catch (error) {
//
}
}
return everStarted;
}
export async function stopTcpHttpProxy(
id: string,
destinationDocker: any,
publicPort: number,
forceName: string | null = null
): Promise<{ stdout: string; stderr: string } | Error | unknown> {
const { id: dockerId } = destinationDocker;
let container = `${id}-${publicPort}`;
if (forceName) container = forceName;
const { found } = await checkContainer({ dockerId, container });
try {
if (!found) return true;
return await executeCommand({
dockerId,
command: `docker stop -t 0 ${container} && docker rm ${container}`,
shell: true
});
} catch (error) {
return error;
}
}

View File

@@ -6,7 +6,7 @@ import sshConfig from 'ssh-config';
import { getFreeSSHLocalPort } from './ssh';
import { env } from '../env';
import { saveBuildLog } from './logging';
import { BuildLog, saveBuildLog } from './logging';
import { decrypt } from './common';
export async function executeCommand({
@@ -31,23 +31,26 @@ export async function executeCommand({
const { execa, execaCommand } = await import('execa');
const { parse } = await import('shell-quote');
const parsedCommand = parse(command);
const dockerCommand = parsedCommand[0];
const dockerArgs = parsedCommand.slice(1);
const dockerCommand = parsedCommand[0]?.toString();
const dockerArgs = parsedCommand.slice(1).toString();
if (dockerId) {
if (dockerId && dockerCommand && dockerArgs) {
const destinationDocker = await prisma.destinationDocker.findUnique({
where: { id: dockerId }
});
if (!destinationDocker) {
throw new Error('Destination docker not found');
}
let { remoteEngine, remoteIpAddress, engine } = destinationDocker;
let {
remoteEngine,
remoteIpAddress,
engine = 'unix:///var/run/docker.sock'
} = destinationDocker;
if (remoteEngine) {
await createRemoteEngineConfiguration(dockerId);
engine = `ssh://${remoteIpAddress}-remote`;
} else {
engine = 'unix:///var/run/docker.sock';
}
if (env.CODESANDBOX_HOST) {
if (command.startsWith('docker compose')) {
command = command.replace(/docker compose/gi, 'docker-compose');
@@ -73,12 +76,12 @@ export async function executeCommand({
}
const logs: any[] = [];
if (subprocess && subprocess.stdout && subprocess.stderr) {
subprocess.stdout.on('data', async (data) => {
subprocess.stdout.on('data', async (data: string) => {
const stdout = data.toString();
const array = stdout.split('\n');
for (const line of array) {
if (line !== '\n' && line !== '') {
const log = {
const log: BuildLog = {
line: `${line.replace('\n', '')}`,
buildId,
applicationId
@@ -90,7 +93,7 @@ export async function executeCommand({
}
}
});
subprocess.stderr.on('data', async (data) => {
subprocess.stderr.on('data', async (data: string) => {
const stderr = data.toString();
const array = stderr.split('\n');
for (const line of array) {
@@ -107,7 +110,7 @@ export async function executeCommand({
}
}
});
subprocess.on('exit', async (code) => {
subprocess.on('exit', async (code: number) => {
if (code === 0) {
resolve('success');
} else {

View File

@@ -2,15 +2,13 @@ import { prisma } from '../prisma';
import { encrypt, generateTimestamp, isDev } from './common';
import { day } from './dayjs';
export const saveBuildLog = async ({
line,
buildId,
applicationId
}: {
line: string;
buildId: string;
applicationId: string;
}): Promise<any> => {
export type Line = string | { shortMessage: string; stderr: string };
export type BuildLog = {
line: Line;
buildId?: string;
applicationId?: string;
};
export const saveBuildLog = async ({ line, buildId, applicationId }: BuildLog): Promise<any> => {
if (buildId === 'undefined' || buildId === 'null' || !buildId) return;
if (applicationId === 'undefined' || applicationId === 'null' || !applicationId) return;
const { default: got } = await import('got');