fix: expose port checker

This commit is contained in:
Andras Bacsai 2022-07-22 08:57:11 +00:00
parent ac1991291d
commit df01139c41
4 changed files with 47 additions and 33 deletions

View File

@ -994,8 +994,24 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) {
} }
} }
} }
export async function getExposedFreePort(id, exposePort) {
export async function getFreePort() { const { default: getPort } = await import('get-port');
const applicationUsed = await (
await prisma.application.findMany({
where: { exposePort: { not: null }, id: { not: id } },
select: { exposePort: true }
})
).map((a) => a.exposePort);
const serviceUsed = await (
await prisma.service.findMany({
where: { exposePort: { not: null }, id: { not: id } },
select: { exposePort: true }
})
).map((a) => a.exposePort);
const usedPorts = [...applicationUsed, ...serviceUsed];
return await getPort({ port: exposePort, exclude: usedPorts });
}
export async function getFreePublicPort() {
const { default: getPort, portNumbers } = await import('get-port'); const { default: getPort, portNumbers } = await import('get-port');
const data = await prisma.setting.findFirst(); const data = await prisma.setting.findFirst();
const { minPort, maxPort } = data; const { minPort, maxPort } = data;

View File

@ -5,7 +5,7 @@ import axios from 'axios';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import { day } from '../../../../lib/dayjs'; import { day } from '../../../../lib/dayjs';
import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common';
import { asyncExecShell, checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common'; import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getExposedFreePort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common';
import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker'; import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker';
import { scheduler } from '../../../../lib/scheduler'; import { scheduler } from '../../../../lib/scheduler';
@ -57,7 +57,7 @@ export async function getImages(request: FastifyRequest<GetImages>) {
} }
return { baseImage, baseBuildImage, baseBuildImages, baseImages, publishDirectory, port } return { baseBuildImage, baseBuildImages, publishDirectory, port }
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
@ -249,6 +249,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
dockerFileLocation, dockerFileLocation,
denoMainFile denoMainFile
}); });
console.log({ baseImage })
await prisma.application.update({ await prisma.application.update({
where: { id }, where: { id },
data: { data: {
@ -352,7 +353,9 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
const { id } = request.params const { id } = request.params
let { exposePort, fqdn, forceSave, dualCerts } = request.body let { exposePort, fqdn, forceSave, dualCerts } = request.body
fqdn = fqdn.toLowerCase();
if (fqdn) fqdn = fqdn.toLowerCase();
if (exposePort) exposePort = Number(exposePort);
const { isDNSCheckEnabled } = await prisma.setting.findFirst({}); const { isDNSCheckEnabled } = await prisma.setting.findFirst({});
const found = await isDomainConfigured({ id, fqdn }); const found = await isDomainConfigured({ id, fqdn });
@ -360,14 +363,12 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` } throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` }
} }
if (exposePort) { if (exposePort) {
exposePort = Number(exposePort);
if (exposePort < 1024 || exposePort > 65535) { if (exposePort < 1024 || exposePort > 65535) {
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` } throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
} }
const { default: getPort } = await import('get-port'); const availablePort = await getExposedFreePort(id, exposePort);
const publicPort = await getPort({ port: exposePort }); if (availablePort.toString() !== exposePort.toString()) {
if (publicPort !== exposePort) {
throw { status: 500, message: `Port ${exposePort} is already in use.` } throw { status: 500, message: `Port ${exposePort} is already in use.` }
} }
} }
@ -765,13 +766,13 @@ export async function getApplicationLogs(request: FastifyRequest<GetApplicationL
try { try {
// const found = await checkContainer({ dockerId, container: id }) // const found = await checkContainer({ dockerId, container: id })
// if (found) { // if (found) {
const { default: ansi } = await import('strip-ansi') const { default: ansi } = await import('strip-ansi')
const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` })
const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const logs = stripLogsStderr.concat(stripLogsStdout) const logs = stripLogsStderr.concat(stripLogsStdout)
const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1))
return { logs: sortedLogs } return { logs: sortedLogs }
// } // }
} catch (error) { } catch (error) {
const { statusCode } = error; const { statusCode } = error;

View File

@ -3,7 +3,7 @@ import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common';
import { checkContainer } from '../../../../lib/docker'; import { checkContainer } from '../../../../lib/docker';
import { day } from '../../../../lib/dayjs'; import { day } from '../../../../lib/dayjs';
@ -431,7 +431,7 @@ export async function saveDatabaseSettings(request: FastifyRequest<SaveDatabaseS
const teamId = request.user.teamId; const teamId = request.user.teamId;
const { id } = request.params; const { id } = request.params;
const { isPublic, appendOnly = true } = request.body; const { isPublic, appendOnly = true } = request.body;
const publicPort = await getFreePort(); const publicPort = await getFreePublicPort();
const settings = await listSettings(); const settings = await listSettings();
await prisma.database.update({ await prisma.database.update({
where: { id }, where: { id },

View File

@ -2,7 +2,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify';
import fs from 'fs/promises'; import fs from 'fs/promises';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import { prisma, uniqueName, asyncExecShell, getServiceImage, getServiceImages, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions, executeDockerCmd, listSettings } from '../../../../lib/common'; import { prisma, uniqueName, asyncExecShell, getServiceImage, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions, executeDockerCmd, listSettings, getExposedFreePort } from '../../../../lib/common';
import { day } from '../../../../lib/dayjs'; import { day } from '../../../../lib/dayjs';
import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker'; import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker';
import cuid from 'cuid'; import cuid from 'cuid';
@ -305,13 +305,13 @@ export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) {
try { try {
// const found = await checkContainer({ dockerId, container: id }) // const found = await checkContainer({ dockerId, container: id })
// if (found) { // if (found) {
const { default: ansi } = await import('strip-ansi') const { default: ansi } = await import('strip-ansi')
const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` })
const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const logs = stripLogsStderr.concat(stripLogsStdout) const logs = stripLogsStderr.concat(stripLogsStdout)
const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1))
return { logs: sortedLogs } return { logs: sortedLogs }
// } // }
} catch (error) { } catch (error) {
const { statusCode } = error; const { statusCode } = error;
@ -373,15 +373,12 @@ export async function checkService(request: FastifyRequest<CheckService>) {
} }
} }
if (exposePort) { if (exposePort) {
const { default: getPort } = await import('get-port');
exposePort = Number(exposePort);
if (exposePort < 1024 || exposePort > 65535) { if (exposePort < 1024 || exposePort > 65535) {
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` } throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
} }
const publicPort = await getPort({ port: exposePort }); const availablePort = await getExposedFreePort(id, exposePort);
if (publicPort !== exposePort) { if (availablePort.toString() !== exposePort.toString()) {
throw { status: 500, message: `Port ${exposePort} is already in use.` } throw { status: 500, message: `Port ${exposePort} is already in use.` }
} }
} }
@ -983,7 +980,7 @@ async function startMinioService(request: FastifyRequest<ServiceStartStop>) {
const network = destinationDockerId && destinationDocker.network; const network = destinationDockerId && destinationDocker.network;
const port = getServiceMainPort('minio'); const port = getServiceMainPort('minio');
const publicPort = await getFreePort(); const publicPort = await getFreePublicPort();
const consolePort = 9001; const consolePort = 9001;
const { workdir } = await createDirectories({ repository: type, buildId: id }); const { workdir } = await createDirectories({ repository: type, buildId: id });
@ -2679,7 +2676,7 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp
const { id } = request.params const { id } = request.params
const { ftpEnabled } = request.body; const { ftpEnabled } = request.body;
const publicPort = await getFreePort(); const publicPort = await getFreePublicPort();
let ftpUser = cuid(); let ftpUser = cuid();
let ftpPassword = generatePassword(); let ftpPassword = generatePassword();