feat: Public port range (WIP)

This commit is contained in:
Andras Bacsai 2022-02-20 15:12:01 +01:00
parent d3d9754277
commit add441675d
7 changed files with 48 additions and 28 deletions

View File

@ -0,0 +1,20 @@
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Setting" (
"id" TEXT NOT NULL PRIMARY KEY,
"fqdn" TEXT,
"isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
"dualCerts" BOOLEAN NOT NULL DEFAULT false,
"minPort" INTEGER NOT NULL DEFAULT 9000,
"maxPort" INTEGER NOT NULL DEFAULT 9100,
"proxyPassword" TEXT NOT NULL,
"proxyUser" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
DROP TABLE "Setting";
ALTER TABLE "new_Setting" RENAME TO "Setting";
CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

View File

@ -12,6 +12,8 @@ model Setting {
fqdn String? @unique fqdn String? @unique
isRegistrationEnabled Boolean @default(false) isRegistrationEnabled Boolean @default(false)
dualCerts Boolean @default(false) dualCerts Boolean @default(false)
minPort Int @default(9000)
maxPort Int @default(9100)
proxyPassword String proxyPassword String
proxyUser String proxyUser String
createdAt DateTime @default(now()) createdAt DateTime @default(now())

View File

@ -1,9 +1,9 @@
import { decrypt, encrypt } from '$lib/crypto'; import { decrypt, encrypt } from '$lib/crypto';
import { dockerInstance } from '$lib/docker'; import * as db from '$lib/database';
import cuid from 'cuid'; import cuid from 'cuid';
import { generatePassword } from '.'; import { generatePassword } from '.';
import { prisma, ErrorHandler } from './common'; import { prisma, ErrorHandler } from './common';
import getPort from 'get-port'; import getPort, { portNumbers } from 'get-port';
import { asyncExecShell, getEngine, removeContainer } from '$lib/common'; import { asyncExecShell, getEngine, removeContainer } from '$lib/common';
export async function listDatabases(teamId) { export async function listDatabases(teamId) {
@ -16,24 +16,9 @@ export async function newDatabase({ name, teamId }) {
const rootUserPassword = encrypt(generatePassword()); const rootUserPassword = encrypt(generatePassword());
const defaultDatabase = cuid(); const defaultDatabase = cuid();
let publicPort = await getPort();
let i = 0;
do {
const usedPorts = await prisma.database.findMany({ where: { publicPort } });
if (usedPorts.length === 0) break;
publicPort = await getPort();
i++;
} while (i < 10);
if (i === 9) {
throw {
error: 'No free port found!? Is it possible?'
};
}
return await prisma.database.create({ return await prisma.database.create({
data: { data: {
name, name,
publicPort,
defaultDatabase, defaultDatabase,
dbUser, dbUser,
dbUserPassword, dbUserPassword,

View File

@ -3,23 +3,24 @@ import { forceSSLOffApplication, forceSSLOnApplication } from '$lib/haproxy';
import { asyncExecShell, getEngine } from './common'; import { asyncExecShell, getEngine } from './common';
import * as db from '$lib/database'; import * as db from '$lib/database';
import cuid from 'cuid'; import cuid from 'cuid';
import getPort from 'get-port'; import getPort, { portNumbers } from 'get-port';
export async function letsEncrypt({ domain, isCoolify = false, id = null }) { export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
try { try {
const data = await db.prisma.setting.findFirst();
const { minPort, maxPort } = data;
const nakedDomain = domain.replace('www.', ''); const nakedDomain = domain.replace('www.', '');
const wwwDomain = `www.${nakedDomain}`; const wwwDomain = `www.${nakedDomain}`;
const randomCuid = cuid(); const randomCuid = cuid();
const randomPort = 9080; const randomPort = await getPort({ port: portNumbers(minPort, maxPort) });
let host; let host;
let dualCerts = false; let dualCerts = false;
if (isCoolify) { if (isCoolify) {
const data = await db.prisma.setting.findFirst();
dualCerts = data.dualCerts; dualCerts = data.dualCerts;
host = 'unix:///var/run/docker.sock'; host = 'unix:///var/run/docker.sock';
} else { } else {
// Check Application
const applicationData = await db.prisma.application.findUnique({ const applicationData = await db.prisma.application.findUnique({
where: { id }, where: { id },
include: { destinationDocker: true, settings: true } include: { destinationDocker: true, settings: true }

View File

@ -56,9 +56,11 @@
appendOnly = !appendOnly; appendOnly = !appendOnly;
} }
try { try {
await post(`/databases/${id}/settings.json`, { isPublic, appendOnly }); const { publicPort } = await post(`/databases/${id}/settings.json`, { isPublic, appendOnly });
if (isPublic) {
database.publicPort = publicPort;
}
databaseUrl = generateUrl(); databaseUrl = generateUrl();
return;
} catch ({ error }) { } catch ({ error }) {
return errorNotification(error); return errorNotification(error);
} }
@ -135,7 +137,7 @@
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="publicPort">Port</label> <label for="publicPort">Port</label>
<CopyPasswordField <CopyPasswordField
placeholder="Generated automatically after start" placeholder="Generated automatically after set to public"
id="publicPort" id="publicPort"
readonly readonly
disabled disabled

View File

@ -3,30 +3,39 @@ import * as db from '$lib/database';
import { generateDatabaseConfiguration, ErrorHandler } from '$lib/database'; import { generateDatabaseConfiguration, ErrorHandler } from '$lib/database';
import { startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy'; import { startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy';
import type { RequestHandler } from '@sveltejs/kit'; import type { RequestHandler } from '@sveltejs/kit';
import getPort, { portNumbers } from 'get-port';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { status, body, teamId } = await getUserDetails(event); const { status, body, teamId } = await getUserDetails(event);
if (status === 401) return { status, body }; if (status === 401) return { status, body };
const { id } = event.params; const { id } = event.params;
const data = await db.prisma.setting.findFirst();
const { minPort, maxPort } = data;
const { isPublic, appendOnly = true } = await event.request.json(); const { isPublic, appendOnly = true } = await event.request.json();
const publicPort = await getPort({ port: portNumbers(minPort, maxPort) });
try { try {
await db.setDatabase({ id, isPublic, appendOnly }); await db.setDatabase({ id, isPublic, appendOnly });
const database = await db.getDatabase({ id, teamId }); const database = await db.getDatabase({ id, teamId });
const { destinationDockerId, destinationDocker, publicPort } = database; const { destinationDockerId, destinationDocker, publicPort: oldPublicPort } = database;
const { privatePort } = generateDatabaseConfiguration(database); const { privatePort } = generateDatabaseConfiguration(database);
if (destinationDockerId) { if (destinationDockerId) {
if (isPublic) { if (isPublic) {
await db.prisma.database.update({ where: { id }, data: { publicPort } });
await startTcpProxy(destinationDocker, id, publicPort, privatePort); await startTcpProxy(destinationDocker, id, publicPort, privatePort);
} else { } else {
await stopTcpHttpProxy(destinationDocker, publicPort); await db.prisma.database.update({ where: { id }, data: { publicPort: null } });
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
} }
} }
return { return {
status: 201 status: 201,
body: {
publicPort
}
}; };
} catch (error) { } catch (error) {
return ErrorHandler(error); return ErrorHandler(error);

View File

@ -15,6 +15,7 @@ export const post: RequestHandler = async (event) => {
const everStarted = await stopDatabase(database); const everStarted = await stopDatabase(database);
if (everStarted) await stopTcpHttpProxy(database.destinationDocker, database.publicPort); if (everStarted) await stopTcpHttpProxy(database.destinationDocker, database.publicPort);
await db.setDatabase({ id, isPublic: false }); await db.setDatabase({ id, isPublic: false });
await db.prisma.database.update({ where: { id }, data: { publicPort: null } });
return { return {
status: 200 status: 200