chore: version++
This commit is contained in:
parent
9b1ede3a59
commit
eb354f639f
@ -19,9 +19,10 @@ import { saveBuildLog, saveDockerRegistryCredentials } from './buildPacks/common
|
|||||||
import { scheduler } from './scheduler';
|
import { scheduler } from './scheduler';
|
||||||
import type { ExecaChildProcess } from 'execa';
|
import type { ExecaChildProcess } from 'execa';
|
||||||
|
|
||||||
export const version = '3.12.0';
|
export const version = '3.12.1';
|
||||||
export const isDev = process.env.NODE_ENV === 'development';
|
export const isDev = process.env.NODE_ENV === 'development';
|
||||||
export const sentryDSN = 'https://409f09bcb7af47928d3e0f46b78987f3@o1082494.ingest.sentry.io/4504236622217216';
|
export const sentryDSN =
|
||||||
|
'https://409f09bcb7af47928d3e0f46b78987f3@o1082494.ingest.sentry.io/4504236622217216';
|
||||||
const algorithm = 'aes-256-ctr';
|
const algorithm = 'aes-256-ctr';
|
||||||
const customConfig: Config = {
|
const customConfig: Config = {
|
||||||
dictionaries: [adjectives, colors, animals],
|
dictionaries: [adjectives, colors, animals],
|
||||||
@ -92,7 +93,7 @@ export const asyncExecShellStream = async ({
|
|||||||
line: `${line.replace('\n', '')}`,
|
line: `${line.replace('\n', '')}`,
|
||||||
buildId,
|
buildId,
|
||||||
applicationId
|
applicationId
|
||||||
}
|
};
|
||||||
logs.push(log);
|
logs.push(log);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
await saveBuildLog(log);
|
await saveBuildLog(log);
|
||||||
@ -109,7 +110,7 @@ export const asyncExecShellStream = async ({
|
|||||||
line: `${line.replace('\n', '')}`,
|
line: `${line.replace('\n', '')}`,
|
||||||
buildId,
|
buildId,
|
||||||
applicationId
|
applicationId
|
||||||
}
|
};
|
||||||
logs.push(log);
|
logs.push(log);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
await saveBuildLog(log);
|
await saveBuildLog(log);
|
||||||
@ -393,7 +394,6 @@ export function generateTimestamp(): string {
|
|||||||
return `${day().format('HH:mm:ss.SSS')}`;
|
return `${day().format('HH:mm:ss.SSS')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const supportedDatabaseTypesAndVersions = [
|
export const supportedDatabaseTypesAndVersions = [
|
||||||
{
|
{
|
||||||
name: 'mongodb',
|
name: 'mongodb',
|
||||||
@ -509,20 +509,19 @@ export async function createRemoteEngineConfiguration(id: string) {
|
|||||||
} = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } });
|
} = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } });
|
||||||
await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 });
|
await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 });
|
||||||
const config = sshConfig.parse('');
|
const config = sshConfig.parse('');
|
||||||
const Host = `${remoteIpAddress}-remote`
|
const Host = `${remoteIpAddress}-remote`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await executeCommand({ command: `ssh-keygen -R ${Host}` });
|
await executeCommand({ command: `ssh-keygen -R ${Host}` });
|
||||||
await executeCommand({ command: `ssh-keygen -R ${remoteIpAddress}` });
|
await executeCommand({ command: `ssh-keygen -R ${remoteIpAddress}` });
|
||||||
await executeCommand({ command: `ssh-keygen -R localhost:${localPort}` });
|
await executeCommand({ command: `ssh-keygen -R localhost:${localPort}` });
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
|
|
||||||
|
|
||||||
const found = config.find({ Host });
|
const found = config.find({ Host });
|
||||||
const foundIp = config.find({ Host: remoteIpAddress });
|
const foundIp = config.find({ Host: remoteIpAddress });
|
||||||
|
|
||||||
if (found) config.remove({ Host })
|
if (found) config.remove({ Host });
|
||||||
if (foundIp) config.remove({ Host: remoteIpAddress })
|
if (foundIp) config.remove({ Host: remoteIpAddress });
|
||||||
|
|
||||||
config.append({
|
config.append({
|
||||||
Host,
|
Host,
|
||||||
@ -543,15 +542,35 @@ export async function createRemoteEngineConfiguration(id: string) {
|
|||||||
}
|
}
|
||||||
return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config));
|
return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config));
|
||||||
}
|
}
|
||||||
export async function executeCommand({ command, dockerId = null, sshCommand = false, shell = false, stream = false, buildId, applicationId, debug }: { command: string, sshCommand?: boolean, shell?: boolean, stream?: boolean, dockerId?: string, buildId?: string, applicationId?: string, debug?: boolean }): Promise<ExecaChildProcess<string>> {
|
export async function executeCommand({
|
||||||
const { execa, execaCommand } = await import('execa')
|
command,
|
||||||
const { parse } = await import('shell-quote')
|
dockerId = null,
|
||||||
|
sshCommand = false,
|
||||||
|
shell = false,
|
||||||
|
stream = false,
|
||||||
|
buildId,
|
||||||
|
applicationId,
|
||||||
|
debug
|
||||||
|
}: {
|
||||||
|
command: string;
|
||||||
|
sshCommand?: boolean;
|
||||||
|
shell?: boolean;
|
||||||
|
stream?: boolean;
|
||||||
|
dockerId?: string;
|
||||||
|
buildId?: string;
|
||||||
|
applicationId?: string;
|
||||||
|
debug?: boolean;
|
||||||
|
}): Promise<ExecaChildProcess<string>> {
|
||||||
|
const { execa, execaCommand } = await import('execa');
|
||||||
|
const { parse } = await import('shell-quote');
|
||||||
const parsedCommand = parse(command);
|
const parsedCommand = parse(command);
|
||||||
const dockerCommand = parsedCommand[0];
|
const dockerCommand = parsedCommand[0];
|
||||||
const dockerArgs = parsedCommand.slice(1);
|
const dockerArgs = parsedCommand.slice(1);
|
||||||
|
|
||||||
if (dockerId) {
|
if (dockerId) {
|
||||||
let { remoteEngine, remoteIpAddress, engine } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } })
|
let { remoteEngine, remoteIpAddress, engine } = await prisma.destinationDocker.findUnique({
|
||||||
|
where: { id: dockerId }
|
||||||
|
});
|
||||||
if (remoteEngine) {
|
if (remoteEngine) {
|
||||||
await createRemoteEngineConfiguration(dockerId);
|
await createRemoteEngineConfiguration(dockerId);
|
||||||
engine = `ssh://${remoteIpAddress}-remote`;
|
engine = `ssh://${remoteIpAddress}-remote`;
|
||||||
@ -591,7 +610,7 @@ export async function executeCommand({ command, dockerId = null, sshCommand = fa
|
|||||||
line: `${line.replace('\n', '')}`,
|
line: `${line.replace('\n', '')}`,
|
||||||
buildId,
|
buildId,
|
||||||
applicationId
|
applicationId
|
||||||
}
|
};
|
||||||
logs.push(log);
|
logs.push(log);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
await saveBuildLog(log);
|
await saveBuildLog(log);
|
||||||
@ -608,7 +627,7 @@ export async function executeCommand({ command, dockerId = null, sshCommand = fa
|
|||||||
line: `${line.replace('\n', '')}`,
|
line: `${line.replace('\n', '')}`,
|
||||||
buildId,
|
buildId,
|
||||||
applicationId
|
applicationId
|
||||||
}
|
};
|
||||||
logs.push(log);
|
logs.push(log);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
await saveBuildLog(log);
|
await saveBuildLog(log);
|
||||||
@ -628,7 +647,7 @@ export async function executeCommand({ command, dockerId = null, sshCommand = fa
|
|||||||
reject(code);
|
reject(code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
if (shell) {
|
if (shell) {
|
||||||
return await execaCommand(command, {
|
return await execaCommand(command, {
|
||||||
@ -640,7 +659,6 @@ export async function executeCommand({ command, dockerId = null, sshCommand = fa
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (shell) {
|
if (shell) {
|
||||||
return execaCommand(command, { shell: true });
|
return execaCommand(command, { shell: true });
|
||||||
@ -650,8 +668,13 @@ export async function executeCommand({ command, dockerId = null, sshCommand = fa
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startTraefikProxy(id: string): Promise<void> {
|
export async function startTraefikProxy(id: string): Promise<void> {
|
||||||
const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } })
|
const { engine, network, remoteEngine, remoteIpAddress } =
|
||||||
const { found } = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true });
|
await prisma.destinationDocker.findUnique({ where: { id } });
|
||||||
|
const { found } = await checkContainer({
|
||||||
|
dockerId: id,
|
||||||
|
container: 'coolify-proxy',
|
||||||
|
remove: true
|
||||||
|
});
|
||||||
const { id: settingsId, ipv4, ipv6 } = await listSettings();
|
const { id: settingsId, ipv4, ipv6 } = await listSettings();
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
@ -768,9 +791,12 @@ export async function listSettings(): Promise<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateToken() {
|
export function generateToken() {
|
||||||
return jsonwebtoken.sign({
|
return jsonwebtoken.sign(
|
||||||
nbf: Math.floor(Date.now() / 1000) - 30,
|
{
|
||||||
}, process.env['COOLIFY_SECRET_KEY'])
|
nbf: Math.floor(Date.now() / 1000) - 30
|
||||||
|
},
|
||||||
|
process.env['COOLIFY_SECRET_KEY']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
export function generatePassword({
|
export function generatePassword({
|
||||||
length = 24,
|
length = 24,
|
||||||
@ -790,109 +816,102 @@ export function generatePassword({
|
|||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfiguration = {
|
type DatabaseConfiguration =
|
||||||
volume: string;
|
|
||||||
image: string;
|
|
||||||
command?: string;
|
|
||||||
ulimits: Record<string, unknown>;
|
|
||||||
privatePort: number;
|
|
||||||
environmentVariables: {
|
|
||||||
MYSQL_DATABASE: string;
|
|
||||||
MYSQL_PASSWORD: string;
|
|
||||||
MYSQL_ROOT_USER: string;
|
|
||||||
MYSQL_USER: string;
|
|
||||||
MYSQL_ROOT_PASSWORD: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
MONGO_INITDB_ROOT_USERNAME?: string;
|
MYSQL_DATABASE: string;
|
||||||
MONGO_INITDB_ROOT_PASSWORD?: string;
|
MYSQL_PASSWORD: string;
|
||||||
MONGODB_ROOT_USER?: string;
|
MYSQL_ROOT_USER: string;
|
||||||
MONGODB_ROOT_PASSWORD?: string;
|
MYSQL_USER: string;
|
||||||
};
|
MYSQL_ROOT_PASSWORD: string;
|
||||||
}
|
};
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
MARIADB_ROOT_USER: string;
|
MONGO_INITDB_ROOT_USERNAME?: string;
|
||||||
MARIADB_ROOT_PASSWORD: string;
|
MONGO_INITDB_ROOT_PASSWORD?: string;
|
||||||
MARIADB_USER: string;
|
MONGODB_ROOT_USER?: string;
|
||||||
MARIADB_PASSWORD: string;
|
MONGODB_ROOT_PASSWORD?: string;
|
||||||
MARIADB_DATABASE: string;
|
};
|
||||||
};
|
}
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
POSTGRES_PASSWORD?: string;
|
MARIADB_ROOT_USER: string;
|
||||||
POSTGRES_USER?: string;
|
MARIADB_ROOT_PASSWORD: string;
|
||||||
POSTGRES_DB?: string;
|
MARIADB_USER: string;
|
||||||
POSTGRESQL_POSTGRES_PASSWORD?: string;
|
MARIADB_PASSWORD: string;
|
||||||
POSTGRESQL_USERNAME?: string;
|
MARIADB_DATABASE: string;
|
||||||
POSTGRESQL_PASSWORD?: string;
|
};
|
||||||
POSTGRESQL_DATABASE?: string;
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
REDIS_AOF_ENABLED: string;
|
POSTGRES_PASSWORD?: string;
|
||||||
REDIS_PASSWORD: string;
|
POSTGRES_USER?: string;
|
||||||
};
|
POSTGRES_DB?: string;
|
||||||
}
|
POSTGRESQL_POSTGRES_PASSWORD?: string;
|
||||||
|
POSTGRESQL_USERNAME?: string;
|
||||||
|
POSTGRESQL_PASSWORD?: string;
|
||||||
|
POSTGRESQL_DATABASE?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
COUCHDB_PASSWORD: string;
|
REDIS_AOF_ENABLED: string;
|
||||||
COUCHDB_USER: string;
|
REDIS_PASSWORD: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
volume: string;
|
volume: string;
|
||||||
image: string;
|
image: string;
|
||||||
command?: string;
|
command?: string;
|
||||||
ulimits: Record<string, unknown>;
|
ulimits: Record<string, unknown>;
|
||||||
privatePort: number;
|
privatePort: number;
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
EDGEDB_SERVER_PASSWORD: string;
|
COUCHDB_PASSWORD: string;
|
||||||
EDGEDB_SERVER_USER: string;
|
COUCHDB_USER: string;
|
||||||
EDGEDB_SERVER_DATABASE: string;
|
};
|
||||||
EDGEDB_SERVER_TLS_CERT_MODE: string;
|
}
|
||||||
};
|
| {
|
||||||
}
|
volume: string;
|
||||||
|
image: string;
|
||||||
|
command?: string;
|
||||||
|
ulimits: Record<string, unknown>;
|
||||||
|
privatePort: number;
|
||||||
|
environmentVariables: {
|
||||||
|
EDGEDB_SERVER_PASSWORD: string;
|
||||||
|
EDGEDB_SERVER_USER: string;
|
||||||
|
EDGEDB_SERVER_DATABASE: string;
|
||||||
|
EDGEDB_SERVER_TLS_CERT_MODE: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
export function generateDatabaseConfiguration(database: any, arch: string): DatabaseConfiguration {
|
export function generateDatabaseConfiguration(database: any, arch: string): DatabaseConfiguration {
|
||||||
const {
|
const { id, dbUser, dbUserPassword, rootUser, rootUserPassword, defaultDatabase, version, type } =
|
||||||
id,
|
database;
|
||||||
dbUser,
|
|
||||||
dbUserPassword,
|
|
||||||
rootUser,
|
|
||||||
rootUserPassword,
|
|
||||||
defaultDatabase,
|
|
||||||
version,
|
|
||||||
type,
|
|
||||||
} = database;
|
|
||||||
const baseImage = getDatabaseImage(type, arch);
|
const baseImage = getDatabaseImage(type, arch);
|
||||||
if (type === 'mysql') {
|
if (type === 'mysql') {
|
||||||
const configuration = {
|
const configuration = {
|
||||||
@ -972,7 +991,9 @@ export function generateDatabaseConfiguration(database: any, arch: string): Data
|
|||||||
}
|
}
|
||||||
return configuration;
|
return configuration;
|
||||||
} else if (type === 'redis') {
|
} else if (type === 'redis') {
|
||||||
const { settings: { appendOnly } } = database;
|
const {
|
||||||
|
settings: { appendOnly }
|
||||||
|
} = database;
|
||||||
const configuration: DatabaseConfiguration = {
|
const configuration: DatabaseConfiguration = {
|
||||||
privatePort: 6379,
|
privatePort: 6379,
|
||||||
command: undefined,
|
command: undefined,
|
||||||
@ -986,8 +1007,9 @@ export function generateDatabaseConfiguration(database: any, arch: string): Data
|
|||||||
};
|
};
|
||||||
if (isARM(arch)) {
|
if (isARM(arch)) {
|
||||||
configuration.volume = `${id}-${type}-data:/data`;
|
configuration.volume = `${id}-${type}-data:/data`;
|
||||||
configuration.command = `/usr/local/bin/redis-server --appendonly ${appendOnly ? 'yes' : 'no'
|
configuration.command = `/usr/local/bin/redis-server --appendonly ${
|
||||||
} --requirepass ${dbUserPassword}`;
|
appendOnly ? 'yes' : 'no'
|
||||||
|
} --requirepass ${dbUserPassword}`;
|
||||||
}
|
}
|
||||||
return configuration;
|
return configuration;
|
||||||
} else if (type === 'couchdb') {
|
} else if (type === 'couchdb') {
|
||||||
@ -1004,7 +1026,7 @@ export function generateDatabaseConfiguration(database: any, arch: string): Data
|
|||||||
if (isARM(arch)) {
|
if (isARM(arch)) {
|
||||||
configuration.volume = `${id}-${type}-data:/opt/couchdb/data`;
|
configuration.volume = `${id}-${type}-data:/opt/couchdb/data`;
|
||||||
}
|
}
|
||||||
return configuration
|
return configuration;
|
||||||
} else if (type === 'edgedb') {
|
} else if (type === 'edgedb') {
|
||||||
const configuration: DatabaseConfiguration = {
|
const configuration: DatabaseConfiguration = {
|
||||||
privatePort: 5656,
|
privatePort: 5656,
|
||||||
@ -1018,7 +1040,7 @@ export function generateDatabaseConfiguration(database: any, arch: string): Data
|
|||||||
volume: `${id}-${type}-data:/var/lib/edgedb/data`,
|
volume: `${id}-${type}-data:/var/lib/edgedb/data`,
|
||||||
ulimits: {}
|
ulimits: {}
|
||||||
};
|
};
|
||||||
return configuration
|
return configuration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function isARM(arch: string) {
|
export function isARM(arch: string) {
|
||||||
@ -1071,12 +1093,12 @@ export type ComposeFileService = {
|
|||||||
command?: string;
|
command?: string;
|
||||||
ports?: string[];
|
ports?: string[];
|
||||||
build?:
|
build?:
|
||||||
| {
|
| {
|
||||||
context: string;
|
context: string;
|
||||||
dockerfile: string;
|
dockerfile: string;
|
||||||
args?: Record<string, unknown>;
|
args?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
| string;
|
| string;
|
||||||
deploy?: {
|
deploy?: {
|
||||||
restart_policy?: {
|
restart_policy?: {
|
||||||
condition?: string;
|
condition?: string;
|
||||||
@ -1141,13 +1163,13 @@ export const createDirectories = async ({
|
|||||||
repository: string;
|
repository: string;
|
||||||
buildId: string;
|
buildId: string;
|
||||||
}): Promise<{ workdir: string; repodir: string }> => {
|
}): Promise<{ workdir: string; repodir: string }> => {
|
||||||
if (repository) repository = repository.replaceAll(' ', '')
|
if (repository) repository = repository.replaceAll(' ', '');
|
||||||
const repodir = `/tmp/build-sources/${repository}/`;
|
const repodir = `/tmp/build-sources/${repository}/`;
|
||||||
const workdir = `/tmp/build-sources/${repository}/${buildId}`;
|
const workdir = `/tmp/build-sources/${repository}/${buildId}`;
|
||||||
let workdirFound = false;
|
let workdirFound = false;
|
||||||
try {
|
try {
|
||||||
workdirFound = !!(await fs.stat(workdir));
|
workdirFound = !!(await fs.stat(workdir));
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
if (workdirFound) {
|
if (workdirFound) {
|
||||||
await executeCommand({ command: `rm -fr ${workdir}` });
|
await executeCommand({ command: `rm -fr ${workdir}` });
|
||||||
}
|
}
|
||||||
@ -1254,19 +1276,45 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function checkExposedPort({ id, configuredPort, exposePort, engine, remoteEngine, remoteIpAddress }: { id: string, configuredPort?: number, exposePort: number, engine: string, remoteEngine: boolean, remoteIpAddress?: string }) {
|
export async function checkExposedPort({
|
||||||
|
id,
|
||||||
|
configuredPort,
|
||||||
|
exposePort,
|
||||||
|
engine,
|
||||||
|
remoteEngine,
|
||||||
|
remoteIpAddress
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
configuredPort?: number;
|
||||||
|
exposePort: number;
|
||||||
|
engine: string;
|
||||||
|
remoteEngine: boolean;
|
||||||
|
remoteIpAddress?: string;
|
||||||
|
}) {
|
||||||
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.` };
|
||||||
}
|
}
|
||||||
if (configuredPort) {
|
if (configuredPort) {
|
||||||
if (configuredPort !== exposePort) {
|
if (configuredPort !== exposePort) {
|
||||||
const availablePort = await getFreeExposedPort(id, exposePort, engine, remoteEngine, remoteIpAddress);
|
const availablePort = await getFreeExposedPort(
|
||||||
|
id,
|
||||||
|
exposePort,
|
||||||
|
engine,
|
||||||
|
remoteEngine,
|
||||||
|
remoteIpAddress
|
||||||
|
);
|
||||||
if (availablePort.toString() !== exposePort.toString()) {
|
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.` };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const availablePort = await getFreeExposedPort(id, exposePort, engine, remoteEngine, remoteIpAddress);
|
const availablePort = await getFreeExposedPort(
|
||||||
|
id,
|
||||||
|
exposePort,
|
||||||
|
engine,
|
||||||
|
remoteEngine,
|
||||||
|
remoteIpAddress
|
||||||
|
);
|
||||||
if (availablePort.toString() !== exposePort.toString()) {
|
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.` };
|
||||||
}
|
}
|
||||||
@ -1277,25 +1325,33 @@ export async function getFreeExposedPort(id, exposePort, engine, remoteEngine, r
|
|||||||
if (remoteEngine) {
|
if (remoteEngine) {
|
||||||
const applicationUsed = await (
|
const applicationUsed = await (
|
||||||
await prisma.application.findMany({
|
await prisma.application.findMany({
|
||||||
where: { exposePort: { not: null }, id: { not: id }, destinationDocker: { remoteIpAddress } },
|
where: {
|
||||||
|
exposePort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
destinationDocker: { remoteIpAddress }
|
||||||
|
},
|
||||||
select: { exposePort: true }
|
select: { exposePort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.exposePort);
|
).map((a) => a.exposePort);
|
||||||
const serviceUsed = await (
|
const serviceUsed = await (
|
||||||
await prisma.service.findMany({
|
await prisma.service.findMany({
|
||||||
where: { exposePort: { not: null }, id: { not: id }, destinationDocker: { remoteIpAddress } },
|
where: {
|
||||||
|
exposePort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
destinationDocker: { remoteIpAddress }
|
||||||
|
},
|
||||||
select: { exposePort: true }
|
select: { exposePort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.exposePort);
|
).map((a) => a.exposePort);
|
||||||
const usedPorts = [...applicationUsed, ...serviceUsed];
|
const usedPorts = [...applicationUsed, ...serviceUsed];
|
||||||
if (usedPorts.includes(exposePort)) {
|
if (usedPorts.includes(exposePort)) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
const found = await checkPort(exposePort, { host: remoteIpAddress });
|
const found = await checkPort(exposePort, { host: remoteIpAddress });
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return exposePort
|
return exposePort;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const applicationUsed = await (
|
const applicationUsed = await (
|
||||||
await prisma.application.findMany({
|
await prisma.application.findMany({
|
||||||
@ -1311,13 +1367,13 @@ export async function getFreeExposedPort(id, exposePort, engine, remoteEngine, r
|
|||||||
).map((a) => a.exposePort);
|
).map((a) => a.exposePort);
|
||||||
const usedPorts = [...applicationUsed, ...serviceUsed];
|
const usedPorts = [...applicationUsed, ...serviceUsed];
|
||||||
if (usedPorts.includes(exposePort)) {
|
if (usedPorts.includes(exposePort)) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
const found = await checkPort(exposePort, { host: 'localhost' });
|
const found = await checkPort(exposePort, { host: 'localhost' });
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return exposePort
|
return exposePort;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function generateRangeArray(start, end) {
|
export function generateRangeArray(start, end) {
|
||||||
@ -1330,38 +1386,54 @@ export async function getFreePublicPort({ id, remoteEngine, engine, remoteIpAddr
|
|||||||
if (remoteEngine) {
|
if (remoteEngine) {
|
||||||
const dbUsed = await (
|
const dbUsed = await (
|
||||||
await prisma.database.findMany({
|
await prisma.database.findMany({
|
||||||
where: { publicPort: { not: null }, id: { not: id }, destinationDocker: { remoteIpAddress } },
|
where: {
|
||||||
|
publicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
destinationDocker: { remoteIpAddress }
|
||||||
|
},
|
||||||
select: { publicPort: true }
|
select: { publicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.publicPort);
|
).map((a) => a.publicPort);
|
||||||
const wpFtpUsed = await (
|
const wpFtpUsed = await (
|
||||||
await prisma.wordpress.findMany({
|
await prisma.wordpress.findMany({
|
||||||
where: { ftpPublicPort: { not: null }, id: { not: id }, service: { destinationDocker: { remoteIpAddress } } },
|
where: {
|
||||||
|
ftpPublicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { remoteIpAddress } }
|
||||||
|
},
|
||||||
select: { ftpPublicPort: true }
|
select: { ftpPublicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.ftpPublicPort);
|
).map((a) => a.ftpPublicPort);
|
||||||
const wpUsed = await (
|
const wpUsed = await (
|
||||||
await prisma.wordpress.findMany({
|
await prisma.wordpress.findMany({
|
||||||
where: { mysqlPublicPort: { not: null }, id: { not: id }, service: { destinationDocker: { remoteIpAddress } } },
|
where: {
|
||||||
|
mysqlPublicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { remoteIpAddress } }
|
||||||
|
},
|
||||||
select: { mysqlPublicPort: true }
|
select: { mysqlPublicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.mysqlPublicPort);
|
).map((a) => a.mysqlPublicPort);
|
||||||
const minioUsed = await (
|
const minioUsed = await (
|
||||||
await prisma.minio.findMany({
|
await prisma.minio.findMany({
|
||||||
where: { publicPort: { not: null }, id: { not: id }, service: { destinationDocker: { remoteIpAddress } } },
|
where: {
|
||||||
|
publicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { remoteIpAddress } }
|
||||||
|
},
|
||||||
select: { publicPort: true }
|
select: { publicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.publicPort);
|
).map((a) => a.publicPort);
|
||||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
||||||
const range = generateRangeArray(minPort, maxPort)
|
const range = generateRangeArray(minPort, maxPort);
|
||||||
const availablePorts = range.filter(port => !usedPorts.includes(port))
|
const availablePorts = range.filter((port) => !usedPorts.includes(port));
|
||||||
for (const port of availablePorts) {
|
for (const port of availablePorts) {
|
||||||
const found = await isReachable(port, { host: remoteIpAddress })
|
const found = await isReachable(port, { host: remoteIpAddress });
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return port
|
return port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const dbUsed = await (
|
const dbUsed = await (
|
||||||
await prisma.database.findMany({
|
await prisma.database.findMany({
|
||||||
@ -1371,32 +1443,44 @@ export async function getFreePublicPort({ id, remoteEngine, engine, remoteIpAddr
|
|||||||
).map((a) => a.publicPort);
|
).map((a) => a.publicPort);
|
||||||
const wpFtpUsed = await (
|
const wpFtpUsed = await (
|
||||||
await prisma.wordpress.findMany({
|
await prisma.wordpress.findMany({
|
||||||
where: { ftpPublicPort: { not: null }, id: { not: id }, service: { destinationDocker: { engine } } },
|
where: {
|
||||||
|
ftpPublicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { engine } }
|
||||||
|
},
|
||||||
select: { ftpPublicPort: true }
|
select: { ftpPublicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.ftpPublicPort);
|
).map((a) => a.ftpPublicPort);
|
||||||
const wpUsed = await (
|
const wpUsed = await (
|
||||||
await prisma.wordpress.findMany({
|
await prisma.wordpress.findMany({
|
||||||
where: { mysqlPublicPort: { not: null }, id: { not: id }, service: { destinationDocker: { engine } } },
|
where: {
|
||||||
|
mysqlPublicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { engine } }
|
||||||
|
},
|
||||||
select: { mysqlPublicPort: true }
|
select: { mysqlPublicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.mysqlPublicPort);
|
).map((a) => a.mysqlPublicPort);
|
||||||
const minioUsed = await (
|
const minioUsed = await (
|
||||||
await prisma.minio.findMany({
|
await prisma.minio.findMany({
|
||||||
where: { publicPort: { not: null }, id: { not: id }, service: { destinationDocker: { engine } } },
|
where: {
|
||||||
|
publicPort: { not: null },
|
||||||
|
id: { not: id },
|
||||||
|
service: { destinationDocker: { engine } }
|
||||||
|
},
|
||||||
select: { publicPort: true }
|
select: { publicPort: true }
|
||||||
})
|
})
|
||||||
).map((a) => a.publicPort);
|
).map((a) => a.publicPort);
|
||||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
||||||
const range = generateRangeArray(minPort, maxPort)
|
const range = generateRangeArray(minPort, maxPort);
|
||||||
const availablePorts = range.filter(port => !usedPorts.includes(port))
|
const availablePorts = range.filter((port) => !usedPorts.includes(port));
|
||||||
for (const port of availablePorts) {
|
for (const port of availablePorts) {
|
||||||
const found = await isReachable(port, { host: 'localhost' })
|
const found = await isReachable(port, { host: 'localhost' });
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return port
|
return port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1502,11 +1586,11 @@ export async function getServiceFromDB({
|
|||||||
serviceSecret: true,
|
serviceSecret: true,
|
||||||
serviceSetting: true,
|
serviceSetting: true,
|
||||||
wordpress: true,
|
wordpress: true,
|
||||||
plausibleAnalytics: true,
|
plausibleAnalytics: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
// body.type = fixType(body.type);
|
// body.type = fixType(body.type);
|
||||||
|
|
||||||
@ -1523,7 +1607,6 @@ export async function getServiceFromDB({
|
|||||||
return { ...body, settings };
|
return { ...body, settings };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function fixType(type) {
|
export function fixType(type) {
|
||||||
return type?.replaceAll(' ', '').toLowerCase() || null;
|
return type?.replaceAll(' ', '').toLowerCase() || null;
|
||||||
}
|
}
|
||||||
@ -1610,7 +1693,7 @@ export async function stopBuild(buildId, applicationId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1640,16 +1723,22 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
|
|||||||
|
|
||||||
images = images.trim();
|
images = images.trim();
|
||||||
if (images) {
|
if (images) {
|
||||||
await executeCommand({ dockerId, command: `docker rmi -f ${images}" -q | xargs -r`, shell: true });
|
await executeCommand({
|
||||||
|
dockerId,
|
||||||
|
command: `docker rmi -f ${images}" -q | xargs -r`,
|
||||||
|
shell: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
if (lowDiskSpace || force) {
|
if (lowDiskSpace || force) {
|
||||||
// Cleanup images that are not used
|
// Cleanup images that are not used
|
||||||
try {
|
try {
|
||||||
await executeCommand({ dockerId, command: `docker image prune -f` });
|
await executeCommand({ dockerId, command: `docker image prune -f` });
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
|
|
||||||
const { numberOfDockerImagesKeptLocally } = await prisma.setting.findUnique({ where: { id: '0' } })
|
const { numberOfDockerImagesKeptLocally } = await prisma.setting.findUnique({
|
||||||
|
where: { id: '0' }
|
||||||
|
});
|
||||||
const { stdout: images } = await executeCommand({
|
const { stdout: images } = await executeCommand({
|
||||||
dockerId,
|
dockerId,
|
||||||
command: `docker images|grep -v "<none>"|grep -v REPOSITORY|awk '{print $1, $2}'`,
|
command: `docker images|grep -v "<none>"|grep -v REPOSITORY|awk '{print $1, $2}'`,
|
||||||
@ -1657,18 +1746,17 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
|
|||||||
});
|
});
|
||||||
const imagesArray = images.trim().replaceAll(' ', ':').split('\n');
|
const imagesArray = images.trim().replaceAll(' ', ':').split('\n');
|
||||||
const imagesSet = new Set(imagesArray.map((image) => image.split(':')[0]));
|
const imagesSet = new Set(imagesArray.map((image) => image.split(':')[0]));
|
||||||
let deleteImage = []
|
let deleteImage = [];
|
||||||
for (const image of imagesSet) {
|
for (const image of imagesSet) {
|
||||||
let keepImage = []
|
let keepImage = [];
|
||||||
for (const image2 of imagesArray) {
|
for (const image2 of imagesArray) {
|
||||||
if (image2.startsWith(image)) {
|
if (image2.startsWith(image)) {
|
||||||
if (keepImage.length >= numberOfDockerImagesKeptLocally) {
|
if (keepImage.length >= numberOfDockerImagesKeptLocally) {
|
||||||
deleteImage.push(image2)
|
deleteImage.push(image2);
|
||||||
} else {
|
} else {
|
||||||
keepImage.push(image2)
|
keepImage.push(image2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const image of deleteImage) {
|
for (const image of deleteImage) {
|
||||||
@ -1681,12 +1769,12 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) {
|
|||||||
dockerId,
|
dockerId,
|
||||||
command: `docker container prune -f --filter "label=coolify.managed=true"`
|
command: `docker container prune -f --filter "label=coolify.managed=true"`
|
||||||
});
|
});
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
|
|
||||||
// Cleanup build caches
|
// Cleanup build caches
|
||||||
try {
|
try {
|
||||||
await executeCommand({ dockerId, command: `docker builder prune -a -f` });
|
await executeCommand({ dockerId, command: `docker builder prune -a -f` });
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1768,16 +1856,22 @@ export function decryptApplication(application: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pushToRegistry(application: any, workdir: string, tag: string, imageName: string, customTag: string) {
|
export async function pushToRegistry(
|
||||||
const location = `${workdir}/.docker`
|
application: any,
|
||||||
const tagCommand = `docker tag ${application.id}:${tag} ${imageName}:${customTag}`
|
workdir: string,
|
||||||
const pushCommand = `docker --config ${location} push ${imageName}:${customTag}`
|
tag: string,
|
||||||
|
imageName: string,
|
||||||
|
customTag: string
|
||||||
|
) {
|
||||||
|
const location = `${workdir}/.docker`;
|
||||||
|
const tagCommand = `docker tag ${application.id}:${tag} ${imageName}:${customTag}`;
|
||||||
|
const pushCommand = `docker --config ${location} push ${imageName}:${customTag}`;
|
||||||
await executeCommand({
|
await executeCommand({
|
||||||
dockerId: application.destinationDockerId,
|
dockerId: application.destinationDockerId,
|
||||||
command: tagCommand
|
command: tagCommand
|
||||||
})
|
});
|
||||||
await executeCommand({
|
await executeCommand({
|
||||||
dockerId: application.destinationDockerId,
|
dockerId: application.destinationDockerId,
|
||||||
command: pushCommand
|
command: pushCommand
|
||||||
})
|
});
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "coolify",
|
"name": "coolify",
|
||||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||||
"version": "3.12.0",
|
"version": "3.12.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": "github:coollabsio/coolify",
|
"repository": "github:coollabsio/coolify",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user