Merge pull request #653 from coollabsio/next

v3.10.14
This commit is contained in:
Andras Bacsai 2022-10-05 09:24:39 +02:00 committed by GitHub
commit ef40f7349e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 59 deletions

View File

@ -3,6 +3,7 @@
"description": "Coolify's Fastify API",
"license": "Apache-2.0",
"scripts": {
"db:generate":"prisma generate",
"db:push": "prisma db push && prisma generate",
"db:seed": "prisma db seed",
"db:studio": "prisma studio",
@ -11,7 +12,7 @@
"build": "rimraf build && esbuild `find src \\( -name '*.ts' \\)| grep -v client/` --minify=true --platform=node --outdir=build --format=cjs",
"format": "prettier --write 'src/**/*.{js,ts,json,md}'",
"lint": "prettier --check 'src/**/*.{js,ts,json,md}' && eslint --ignore-path .eslintignore .",
"start": "NODE_ENV=production npx -y prisma migrate deploy && npx prisma generate && npx prisma db seed && node index.js"
"start": "NODE_ENV=production pnpm prisma migrate deploy && pnpm prisma generate && pnpm prisma db seed && node index.js"
},
"dependencies": {
"@breejs/ts-worker": "2.0.0",
@ -25,6 +26,7 @@
"@iarna/toml": "2.2.5",
"@ladjs/graceful": "3.0.2",
"@prisma/client": "4.4.0",
"prisma": "4.4.0",
"axios": "0.27.2",
"bcryptjs": "2.4.3",
"bree": "9.1.2",
@ -66,7 +68,7 @@
"eslint-plugin-prettier": "4.2.1",
"nodemon": "2.0.20",
"prettier": "2.7.1",
"prisma": "4.4.0",
"rimraf": "3.0.2",
"tsconfig-paths": "4.1.0",
"typescript": "4.8.4"

View File

@ -10,6 +10,7 @@ import { asyncExecShell, createRemoteEngineConfiguration, getDomain, isDev, list
import { scheduler } from './lib/scheduler';
import { compareVersions } from 'compare-versions';
import Graceful from '@ladjs/graceful'
import { verifyRemoteDockerEngineFn } from './routes/api/v1/destinations/handlers';
declare module 'fastify' {
interface FastifyInstance {
config: {
@ -27,7 +28,8 @@ declare module 'fastify' {
const port = isDev ? 3001 : 3000;
const host = '0.0.0.0';
prisma.setting.findFirst().then(async (settings) => {
(async () => {
const settings = await prisma.setting.findFirst()
const fastify = Fastify({
logger: settings?.isAPIDebuggingEnabled || false,
trustProxy: true
@ -117,11 +119,8 @@ prisma.setting.findFirst().then(async (settings) => {
// console.log('not allowed', request.headers.host)
}
})
fastify.listen({ port, host }, async (err: any, address: any) => {
if (err) {
console.error(err);
process.exit(1);
}
try {
await fastify.listen({ port, host })
console.log(`Coolify's API is listening on ${host}:${port}`);
await initServer();
@ -140,12 +139,12 @@ prisma.setting.findFirst().then(async (settings) => {
// autoUpdater
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:autoUpdater")
}, isDev ? 5000 : 60000 * 15)
}, 60000 * 15)
// cleanupStorage
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupStorage")
}, isDev ? 6000 : 60000 * 10)
}, 60000 * 10)
// checkProxies and checkFluentBit
setInterval(async () => {
@ -162,19 +161,28 @@ prisma.setting.findFirst().then(async (settings) => {
getIPAddress(),
configureRemoteDockers(),
])
});
})
} catch (error) {
console.error(error);
process.exit(1);
}
})();
async function getIPAddress() {
const { publicIpv4, publicIpv6 } = await import('public-ip')
try {
const settings = await listSettings();
if (!settings.ipv4) {
console.log(`Getting public IPv4 address...`);
const ipv4 = await publicIpv4({ timeout: 2000 })
await prisma.setting.update({ where: { id: settings.id }, data: { ipv4 } })
}
if (!settings.ipv6) {
console.log(`Getting public IPv6 address...`);
const ipv6 = await publicIpv6({ timeout: 2000 })
await prisma.setting.update({ where: { id: settings.id }, data: { ipv6 } })
}
@ -183,6 +191,7 @@ async function getIPAddress() {
}
async function initServer() {
try {
console.log(`Initializing server...`);
await asyncExecShell(`docker network create --attachable coolify`);
} catch (error) { }
try {
@ -196,6 +205,7 @@ async function getArch() {
try {
const settings = await prisma.setting.findFirst({})
if (settings && !settings.arch) {
console.log(`Getting architecture...`);
await prisma.setting.update({ where: { id: settings.id }, data: { arch: process.arch } })
}
} catch (error) { }
@ -207,9 +217,13 @@ async function configureRemoteDockers() {
where: { remoteVerified: true, remoteEngine: true }
});
if (remoteDocker.length > 0) {
console.log(`Verifying Remote Docker Engines...`);
for (const docker of remoteDocker) {
await createRemoteEngineConfiguration(docker.id)
console.log('Verifying:', docker.remoteIpAddress)
await verifyRemoteDockerEngineFn(docker.id);
}
}
} catch (error) { }
} catch (error) {
console.log(error)
}
}

View File

@ -20,7 +20,7 @@ import { scheduler } from './scheduler';
import { supportedServiceTypesAndVersions } from './services/supportedVersions';
import { includeServices } from './services/common';
export const version = '3.10.13';
export const version = '3.10.14';
export const isDev = process.env.NODE_ENV === 'development';
const algorithm = 'aes-256-ctr';

View File

@ -919,7 +919,7 @@ async function startMeilisearchService(request: FastifyRequest<ServiceStartStop>
const config = {
meilisearch: {
image: `${image}:${version}`,
volumes: [`${id}-datams:/data.ms`],
volumes: [`${id}-datams:/meili_data/data.ms`, `${id}-data:/meili_data `],
environmentVariables: {
MEILI_MASTER_KEY: masterKey
}

View File

@ -63,7 +63,7 @@ export const supportedServiceTypesAndVersions = [
},
{
name: 'wordpress',
fancyName: 'Wordpress',
fancyName: 'WordPress',
baseImage: 'wordpress',
images: ['bitnami/mysql:5.7'],
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
@ -255,4 +255,4 @@ export const supportedServiceTypesAndVersions = [
main: 8080
}
},
];
];

View File

@ -2,12 +2,13 @@ import { FastifyPluginAsync } from 'fastify';
import { errorHandler, listSettings, version } from '../../../../lib/common';
const root: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.get('/', async () => {
fastify.get('/', async (request) => {
const teamId = request.user?.teamId;
const settings = await listSettings()
try {
return {
ipv4: settings.ipv4,
ipv6: settings.ipv6,
ipv4: teamId ? settings.ipv4 : 'nope',
ipv6: teamId ? settings.ipv6 : 'nope',
version,
whiteLabeled: process.env.COOLIFY_WHITE_LABELED === 'true',
whiteLabeledIcon: process.env.COOLIFY_WHITE_LABELED_ICON,

View File

@ -4,7 +4,7 @@ import sshConfig from 'ssh-config'
import fs from 'fs/promises'
import os from 'os';
import { asyncExecShell, createRemoteEngineConfiguration, decrypt, errorHandler, executeDockerCmd, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common';
import { asyncExecShell, createRemoteEngineConfiguration, decrypt, errorHandler, executeDockerCmd, executeSSHCmd, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common';
import { checkContainer } from '../../../../lib/docker';
import type { OnlyId } from '../../../../types';
@ -202,25 +202,58 @@ export async function assignSSHKey(request: FastifyRequest) {
return errorHandler({ status, message })
}
}
export async function verifyRemoteDockerEngine(request: FastifyRequest<OnlyId>, reply: FastifyReply) {
export async function verifyRemoteDockerEngineFn(id: string) {
await createRemoteEngineConfiguration(id);
const { remoteIpAddress, remoteUser, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst({ where: { id } })
const host = `ssh://${remoteUser}@${remoteIpAddress}`
const { stdout } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=${network}' --no-trunc --format "{{json .}}"`);
if (!stdout) {
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`);
}
const { stdout: coolifyNetwork } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"`);
if (!coolifyNetwork) {
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable coolify-infra`);
}
if (isCoolifyProxyUsed) await startTraefikProxy(id);
const { stdout: daemonJson } = await executeSSHCmd({ dockerId: id, command: `cat /etc/docker/daemon.json` });
try {
const { id } = request.params;
await createRemoteEngineConfiguration(id);
const { remoteIpAddress, remoteUser, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst({ where: { id } })
const host = `ssh://${remoteUser}@${remoteIpAddress}`
const { stdout } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=${network}' --no-trunc --format "{{json .}}"`);
if (!stdout) {
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`);
}
const { stdout: coolifyNetwork } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"`);
if (!coolifyNetwork) {
await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable coolify-infra`);
}
if (isCoolifyProxyUsed) await startTraefikProxy(id);
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: true } })
return reply.code(201).send()
let daemonJsonParsed = JSON.parse(daemonJson);
let isUpdated = false;
if (!daemonJsonParsed['live-restore'] || daemonJsonParsed['live-restore'] !== true) {
isUpdated = true;
daemonJsonParsed['live-restore'] = true
}
if (!daemonJsonParsed?.features?.buildkit) {
isUpdated = true;
daemonJsonParsed.features = {
buildkit: true
}
}
if (isUpdated) {
await executeSSHCmd({ dockerId: id, command: `echo '${JSON.stringify(daemonJsonParsed)}' > /etc/docker/daemon.json` });
await executeSSHCmd({ dockerId: id, command: `systemctl restart docker` });
}
} catch (error) {
const daemonJsonParsed = {
"live-restore": true,
"features": {
"buildkit": true
}
}
await executeSSHCmd({ dockerId: id, command: `echo '${JSON.stringify(daemonJsonParsed)}' > /etc/docker/daemon.json` });
await executeSSHCmd({ dockerId: id, command: `systemctl restart docker` });
} finally {
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: true } })
}
}
export async function verifyRemoteDockerEngine(request: FastifyRequest<OnlyId>, reply: FastifyReply) {
const { id } = request.params;
try {
await verifyRemoteDockerEngineFn(id);
return reply.code(201).send()
} catch ({ status, message }) {
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: false } })
return errorHandler({ status, message })
}
}

View File

@ -8,7 +8,16 @@ export async function listServers(request: FastifyRequest) {
try {
const userId = request.user.userId;
const teamId = request.user.teamId;
const servers = await prisma.destinationDocker.findMany({ where: { teams: { some: { id: teamId === '0' ? undefined : teamId } }}, distinct: ['remoteIpAddress', 'engine'] })
let servers = await prisma.destinationDocker.findMany({ where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }, distinct: ['remoteIpAddress', 'engine'] })
servers = servers.filter((server) => {
if (server.remoteEngine) {
if (server.remoteVerified) {
return server
}
} else {
return server
}
})
return {
servers
}
@ -78,7 +87,7 @@ export async function showUsage(request: FastifyRequest) {
freeMemPercentage: (parsed.totalMemoryKB - parsed.usedMemoryKB) / parsed.totalMemoryKB * 100
},
cpu: {
load: [0,0,0],
load: [0, 0, 0],
usage: cpuUsage,
count: cpus
},

View File

@ -175,24 +175,23 @@
disabled={loading.save}
>{$t('forms.save')}
</button>
{#if !destination.remoteVerified}
<button
disabled={loading.verify}
class="btn btn-sm"
class:loading={loading.verify}
on:click|preventDefault|stopPropagation={verifyRemoteDocker}
>Verify Remote Docker Engine</button
>
{:else}
<button
class="btn btn-sm"
class:loading={loading.restart}
class:bg-error={!loading.restart}
disabled={loading.restart}
on:click|preventDefault={forceRestartProxy}
>{$t('destination.force_restart_proxy')}</button
>
{/if}
<button
disabled={loading.verify}
class="btn btn-sm"
class:loading={loading.verify}
on:click|preventDefault|stopPropagation={verifyRemoteDocker}
>{!destination.remoteVerified
? 'Verify Remote Docker Engine'
: 'Check Remote Docker Engine'}</button
>
<button
class="btn btn-sm"
class:loading={loading.restart}
class:bg-error={!loading.restart}
disabled={loading.restart}
on:click|preventDefault={forceRestartProxy}>{$t('destination.force_restart_proxy')}</button
>
{/if}
</div>
<div class="grid grid-cols-2 items-center px-10 ">

View File

@ -1,7 +1,7 @@
{
"name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
"version": "3.10.13",
"version": "3.10.14",
"license": "Apache-2.0",
"repository": "github:coollabsio/coolify",
"scripts": {