fix: states and exposed ports

This commit is contained in:
Andras Bacsai
2022-07-22 12:01:07 +00:00
parent df01139c41
commit a02bcc3d02
13 changed files with 112 additions and 75 deletions

View File

@@ -31,7 +31,7 @@ const customConfig: Config = {
export const defaultProxyImage = `coolify-haproxy-alpine:latest`;
export const defaultProxyImageTcp = `coolify-haproxy-tcp-alpine:latest`;
export const defaultProxyImageHttp = `coolify-haproxy-http-alpine:latest`;
export const defaultTraefikImage = `traefik:v2.6`;
export const defaultTraefikImage = `traefik:v2.8`;
export function getAPIUrl() {
if (process.env.GITPOD_WORKSPACE_URL) {
const { href } = new URL(process.env.GITPOD_WORKSPACE_URL)
@@ -994,49 +994,58 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) {
}
}
}
export async function getExposedFreePort(id, exposePort) {
export async function getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress) {
const { default: getPort } = await import('get-port');
const applicationUsed = await (
await prisma.application.findMany({
where: { exposePort: { not: null }, id: { not: id } },
where: { exposePort: { not: null }, id: { not: id }, destinationDockerId: dockerId },
select: { exposePort: true }
})
).map((a) => a.exposePort);
const serviceUsed = await (
await prisma.service.findMany({
where: { exposePort: { not: null }, id: { not: id } },
where: { exposePort: { not: null }, id: { not: id }, destinationDockerId: dockerId },
select: { exposePort: true }
})
).map((a) => a.exposePort);
const usedPorts = [...applicationUsed, ...serviceUsed];
return await getPort({ port: exposePort, exclude: usedPorts });
if (remoteIpAddress) {
const { default: checkPort } = await import('is-port-reachable');
const found = await checkPort(exposePort, { host: remoteIpAddress });
if (!found) {
return exposePort
}
return false
}
return await getPort({ port: Number(exposePort), exclude: usedPorts });
}
export async function getFreePublicPort() {
export async function getFreePublicPort(id, dockerId) {
const { default: getPort, portNumbers } = await import('get-port');
const data = await prisma.setting.findFirst();
const { minPort, maxPort } = data;
const dbUsed = await (
await prisma.database.findMany({
where: { publicPort: { not: null } },
where: { publicPort: { not: null }, id: { not: id }, destinationDockerId: dockerId },
select: { publicPort: true }
})
).map((a) => a.publicPort);
const wpFtpUsed = await (
await prisma.wordpress.findMany({
where: { ftpPublicPort: { not: null } },
where: { ftpPublicPort: { not: null }, id: { not: id }, service: { destinationDockerId: dockerId } },
select: { ftpPublicPort: true }
})
).map((a) => a.ftpPublicPort);
const wpUsed = await (
await prisma.wordpress.findMany({
where: { mysqlPublicPort: { not: null } },
where: { mysqlPublicPort: { not: null }, id: { not: id }, service: { destinationDockerId: dockerId } },
select: { mysqlPublicPort: true }
})
).map((a) => a.mysqlPublicPort);
const minioUsed = await (
await prisma.minio.findMany({
where: { publicPort: { not: null } },
where: { publicPort: { not: null }, id: { not: id }, service: { destinationDockerId: dockerId } },
select: { publicPort: true }
})
).map((a) => a.publicPort);
@@ -1044,7 +1053,6 @@ export async function getFreePublicPort() {
return await getPort({ port: portNumbers(minPort, maxPort), exclude: usedPorts });
}
export async function startTraefikTCPProxy(
destinationDocker: any,
id: string,
@@ -1067,19 +1075,19 @@ export async function startTraefikTCPProxy(
const ip = JSON.parse(Config)[0].Gateway;
const tcpProxy = {
version: '3.5',
version: '3.8',
services: {
[`${id}-${publicPort}`]: {
container_name: container,
image: 'traefik:v2.6',
image: 'traefik:v2.8',
command: [
`--entrypoints.tcp.address =: ${publicPort}`,
`--entryPoints.tcp.forwardedHeaders.insecure = true`,
`--providers.http.endpoint = ${otherTraefikEndpoint} ? id = ${id} & privatePort=${privatePort} & publicPort=${publicPort} & type=tcp & address=${dependentId}`,
`--entrypoints.tcp.address=:${publicPort}`,
`--entryPoints.tcp.forwardedHeaders.insecure=true`,
`--providers.http.endpoint=${otherTraefikEndpoint} ? id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=tcp&address=${dependentId}`,
'--providers.http.pollTimeout=2s',
'--log.level=error'
],
ports: [`${publicPort}: ${publicPort}`],
ports: [`${publicPort}:${publicPort}`],
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal: ${ip}`],
volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
networks: ['coolify-infra', network]

View File

@@ -5,7 +5,7 @@ import axios from 'axios';
import { FastifyReply } from 'fastify';
import { day } from '../../../../lib/dayjs';
import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common';
import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getExposedFreePort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common';
import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common';
import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker';
import { scheduler } from '../../../../lib/scheduler';
@@ -18,7 +18,7 @@ export async function listApplications(request: FastifyRequest) {
const { teamId } = request.user
const applications = await prisma.application.findMany({
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
include: { teams: true }
include: { teams: true, destinationDocker: true }
});
const settings = await prisma.setting.findFirst()
return {
@@ -249,7 +249,6 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
dockerFileLocation,
denoMainFile
});
console.log({ baseImage })
await prisma.application.update({
where: { id },
data: {
@@ -353,7 +352,7 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
const { id } = request.params
let { exposePort, fqdn, forceSave, dualCerts } = request.body
if (fqdn) fqdn = fqdn.toLowerCase();
if (exposePort) exposePort = Number(exposePort);
@@ -363,13 +362,15 @@ export async function checkDNS(request: FastifyRequest<CheckDNS>) {
throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` }
}
if (exposePort) {
if (exposePort < 1024 || exposePort > 65535) {
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
}
const availablePort = await getExposedFreePort(id, exposePort);
if (availablePort.toString() !== exposePort.toString()) {
throw { status: 500, message: `Port ${exposePort} is already in use.` }
const { destinationDocker: { id: dockerId, remoteIpAddress }, exposePort: configuredPort } = await prisma.application.findUnique({ where: { id }, include: { destinationDocker: true } })
if (configuredPort !== exposePort) {
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
if (availablePort.toString() !== exposePort.toString()) {
throw { status: 500, message: `Port ${exposePort} is already in use.` }
}
}
}
if (isDNSCheckEnabled && !isDev && !forceSave) {

View File

@@ -13,15 +13,10 @@ import { SaveDatabaseType } from './types';
export async function listDatabases(request: FastifyRequest) {
try {
const teamId = request.user.teamId;
let databases = []
if (teamId === '0') {
databases = await prisma.database.findMany({ include: { teams: true } });
} else {
databases = await prisma.database.findMany({
where: { teams: { some: { id: teamId } } },
include: { teams: true }
});
}
const databases = await prisma.database.findMany({
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
include: { teams: true, destinationDocker: true }
});
return {
databases
}
@@ -335,13 +330,13 @@ export async function getDatabaseLogs(request: FastifyRequest<GetDatabaseLogs>)
try {
// const found = await checkContainer({ dockerId, container: id })
// if (found) {
const { default: ansi } = await import('strip-ansi')
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 stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const logs = stripLogsStderr.concat(stripLogsStdout)
const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1))
return { logs: sortedLogs }
const { default: ansi } = await import('strip-ansi')
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 stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
const logs = stripLogsStderr.concat(stripLogsStdout)
const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1))
return { logs: sortedLogs }
// }
} catch (error) {
const { statusCode } = error;
@@ -431,8 +426,10 @@ export async function saveDatabaseSettings(request: FastifyRequest<SaveDatabaseS
const teamId = request.user.teamId;
const { id } = request.params;
const { isPublic, appendOnly = true } = request.body;
const publicPort = await getFreePublicPort();
const settings = await listSettings();
const { destinationDocker: { id: dockerId } } = await prisma.database.findUnique({ where: { id }, include: { destinationDocker: true } })
const publicPort = await getFreePublicPort(id, dockerId);
await prisma.database.update({
where: { id },
data: {

View File

@@ -2,7 +2,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify';
import fs from 'fs/promises';
import yaml from 'js-yaml';
import bcrypt from 'bcryptjs';
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 { 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, getFreeExposedPort } from '../../../../lib/common';
import { day } from '../../../../lib/dayjs';
import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker';
import cuid from 'cuid';
@@ -145,15 +145,10 @@ import type { ActivateWordpressFtp, CheckService, DeleteServiceSecret, DeleteSer
export async function listServices(request: FastifyRequest) {
try {
const teamId = request.user.teamId;
let services = []
if (teamId === '0') {
services = await prisma.service.findMany({ include: { teams: true } });
} else {
services = await prisma.service.findMany({
where: { teams: { some: { id: teamId } } },
include: { teams: true }
});
}
const services = await prisma.service.findMany({
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
include: { teams: true, destinationDocker: true }
});
return {
services
}
@@ -376,10 +371,12 @@ export async function checkService(request: FastifyRequest<CheckService>) {
if (exposePort < 1024 || exposePort > 65535) {
throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` }
}
const availablePort = await getExposedFreePort(id, exposePort);
if (availablePort.toString() !== exposePort.toString()) {
throw { status: 500, message: `Port ${exposePort} is already in use.` }
const { destinationDocker: { id: dockerId, remoteIpAddress }, exposePort: configuredPort } = await prisma.service.findUnique({ where: { id }, include: { destinationDocker: true } })
if (configuredPort !== exposePort) {
const availablePort = await getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress);
if (availablePort.toString() !== exposePort.toString()) {
throw { status: 500, message: `Port ${exposePort} is already in use.` }
}
}
}
return {}
@@ -980,7 +977,9 @@ async function startMinioService(request: FastifyRequest<ServiceStartStop>) {
const network = destinationDockerId && destinationDocker.network;
const port = getServiceMainPort('minio');
const publicPort = await getFreePublicPort();
const { service: { destinationDocker: { id: dockerId } } } = await prisma.minio.findUnique({ where: { id }, include: { service: { include: { destinationDocker: true } } } })
const publicPort = await getFreePublicPort(id, dockerId);
const consolePort = 9001;
const { workdir } = await createDirectories({ repository: type, buildId: id });
@@ -2675,8 +2674,8 @@ export async function activatePlausibleUsers(request: FastifyRequest<OnlyId>, re
export async function activateWordpressFtp(request: FastifyRequest<ActivateWordpressFtp>, reply: FastifyReply) {
const { id } = request.params
const { ftpEnabled } = request.body;
const publicPort = await getFreePublicPort();
const { service: { destinationDocker: { id: dockerId } } } = await prisma.wordpress.findUnique({ where: { id }, include: { service: { include: { destinationDocker: true } } } })
const publicPort = await getFreePublicPort(id, dockerId);
let ftpUser = cuid();
let ftpPassword = generatePassword();