fix: Some nasty bug

fix: Automatic reconfiguration of all services and service proxies
This commit is contained in:
Andras Bacsai 2022-02-15 21:44:36 +01:00
parent 3ae7624361
commit 531c712ea5
11 changed files with 181 additions and 100 deletions

View File

@ -74,26 +74,12 @@ export async function makeLabelForStandaloneDatabase({ id, image, volume }) {
]; ];
} }
export async function makeLabelForPlausibleAnalytics({ id, images, volume }) { export function makeLabelForServices(type) {
const service = await db.prisma.service.findFirst({
where: { id },
include: { plausibleAnalytics: true }
});
delete service.destinationDockerId;
delete service.createdAt;
delete service.updatedAt;
return [ return [
'coolify.managed=true', 'coolify.managed=true',
`coolify.version=${version}`, `coolify.version=${version}`,
`coolify.type=service-plausibleanalytics`, `coolify.type=service`,
`coolify.configuration=${base64Encode( `coolify.service.type=${type}`
JSON.stringify({
version,
images,
volume,
...service
})
)}`
]; ];
} }

View File

@ -114,27 +114,55 @@ export const supportedServiceTypesAndVersions = [
name: 'plausibleanalytics', name: 'plausibleanalytics',
fancyName: 'Plausible Analytics', fancyName: 'Plausible Analytics',
baseImage: 'plausible/analytics', baseImage: 'plausible/analytics',
versions: ['latest'] versions: ['latest'],
ports: {
main: 8000
}
},
{
name: 'nocodb',
fancyName: 'NocoDB',
baseImage: 'nocodb/nocodb',
versions: ['latest'],
ports: {
main: 8080
}
},
{
name: 'minio',
fancyName: 'MinIO',
baseImage: 'minio/minio',
versions: ['latest'],
ports: {
main: 9001
}
}, },
{ name: 'nocodb', fancyName: 'NocoDB', baseImage: 'nocodb/nocodb', versions: ['latest'] },
{ name: 'minio', fancyName: 'MinIO', baseImage: 'minio/minio', versions: ['latest'] },
{ {
name: 'vscodeserver', name: 'vscodeserver',
fancyName: 'VSCode Server', fancyName: 'VSCode Server',
baseImage: 'codercom/code-server', baseImage: 'codercom/code-server',
versions: ['latest'] versions: ['latest'],
ports: {
main: 8080
}
}, },
{ {
name: 'wordpress', name: 'wordpress',
fancyName: 'Wordpress', fancyName: 'Wordpress',
baseImage: 'wordpress', baseImage: 'wordpress',
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'] versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
ports: {
main: 80
}
}, },
{ {
name: 'vaultwarden', name: 'vaultwarden',
fancyName: 'Vaultwarden', fancyName: 'Vaultwarden',
baseImage: 'vaultwarden/server', baseImage: 'vaultwarden/server',
versions: ['latest'] versions: ['latest'],
ports: {
main: 80
}
} }
]; ];

View File

@ -509,19 +509,36 @@ export async function configureNetworkCoolifyProxy(engine) {
export async function configureSimpleServiceProxyOn({ id, domain, port }) { export async function configureSimpleServiceProxyOn({ id, domain, port }) {
const haproxy = await haproxyInstance(); const haproxy = await haproxyInstance();
await checkHAProxy(haproxy); await checkHAProxy(haproxy);
let serverConfigured = false;
let backendAvailable: any = null;
try { try {
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json(); backendAvailable = await haproxy
const transactionId = await getNextTransactionId(); .get(`v2/services/haproxy/configuration/backends/${domain}`)
await haproxy .json();
.delete(`v2/services/haproxy/configuration/backends/${domain}`, { const server: any = await haproxy
.get(`v2/services/haproxy/configuration/servers/${id}`, {
searchParams: { searchParams: {
transaction_id: transactionId backend: domain
} }
}) })
.json(); .json();
await completeTransaction(transactionId); if (backendAvailable && server) {
// Very sophisticated way to check if the server is already configured in proxy
if (backendAvailable.data.forwardfor.enabled === 'enabled') {
if (backendAvailable.data.name === domain) {
if (server.data.check === 'enabled') {
if (server.data.address === id) {
if (server.data.port === port) {
serverConfigured = true;
}
}
}
}
}
}
} catch (error) {} } catch (error) {}
try { if (serverConfigured) return;
const transactionId = await getNextTransactionId(); const transactionId = await getNextTransactionId();
await haproxy.post('v2/services/haproxy/configuration/backends', { await haproxy.post('v2/services/haproxy/configuration/backends', {
searchParams: { searchParams: {
@ -546,9 +563,6 @@ export async function configureSimpleServiceProxyOn({ id, domain, port }) {
} }
}); });
await completeTransaction(transactionId); await completeTransaction(transactionId);
} catch (error) {
console.log(error);
}
} }
export async function configureSimpleServiceProxyOff({ domain }) { export async function configureSimpleServiceProxyOff({ domain }) {

View File

@ -1,14 +1,16 @@
import { getDomain } from '$lib/common'; import { getDomain } from '$lib/common';
import { getApplicationById, prisma } from '$lib/database'; import { getApplicationById, prisma, supportedServiceTypesAndVersions } from '$lib/database';
import { dockerInstance } from '$lib/docker'; import { dockerInstance } from '$lib/docker';
import { import {
checkContainer, checkContainer,
configureCoolifyProxyOn, configureCoolifyProxyOn,
configureProxyForApplication, configureProxyForApplication,
configureSimpleServiceProxyOn,
forceSSLOnApplication, forceSSLOnApplication,
reloadHaproxy, reloadHaproxy,
setWwwRedirection, setWwwRedirection,
startCoolifyProxy startCoolifyProxy,
startHttpProxy
} from '$lib/haproxy'; } from '$lib/haproxy';
import * as db from '$lib/database'; import * as db from '$lib/database';
@ -24,6 +26,7 @@ export default async function () {
(container) => container.Labels['coolify.managed'] (container) => container.Labels['coolify.managed']
); );
for (const configuration of configurations) { for (const configuration of configurations) {
if (configuration.Labels['coolify.configuration']) {
const parsedConfiguration = JSON.parse( const parsedConfiguration = JSON.parse(
Buffer.from(configuration.Labels['coolify.configuration'], 'base64').toString() Buffer.from(configuration.Labels['coolify.configuration'], 'base64').toString()
); );
@ -52,7 +55,41 @@ export default async function () {
} }
} }
} }
for (const container of containers) {
const image = container.Image.split(':')[0];
const found = supportedServiceTypesAndVersions.find((a) => a.baseImage === image);
if (found) {
const type = found.name;
const mainPort = found.ports.main;
const id = container.Names[0].replace('/', '');
const service = await db.prisma.service.findUnique({
where: { id },
include: {
destinationDocker: true,
minio: true,
plausibleAnalytics: true,
vscodeserver: true,
wordpress: true
} }
});
const { fqdn } = service;
const domain = getDomain(fqdn);
await configureSimpleServiceProxyOn({ id, domain, port: mainPort });
const publicPort = service[type]?.publicPort;
if (publicPort) {
const containerFound = await checkContainer(
destination.engine,
`haproxy-for-${publicPort}`
);
if (!containerFound) {
await startHttpProxy(destination, id, publicPort, 9000);
}
}
}
}
}
}
const services = await prisma.service.findMany({});
// Check Coolify FQDN and configure proxy if needed // Check Coolify FQDN and configure proxy if needed
const { fqdn } = await db.listSettings(); const { fqdn } = await db.listSettings();
if (fqdn) { if (fqdn) {

View File

@ -102,6 +102,10 @@
} }
} }
async function forceRestartProxy() { async function forceRestartProxy() {
const sure = confirm(
'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
);
if (sure) {
try { try {
restarting = true; restarting = true;
toast.push('Coolify Proxy restarting...'); toast.push('Coolify Proxy restarting...');
@ -115,6 +119,7 @@
}, 5000); }, 5000);
} }
} }
}
</script> </script>
<div class="flex justify-center px-6 pb-8"> <div class="flex justify-center px-6 pb-8">

View File

@ -15,6 +15,7 @@ import {
import getPort from 'get-port'; import getPort from 'get-port';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -63,7 +64,8 @@ export const post: RequestHandler = async (event) => {
environment: config.environmentVariables, environment: config.environmentVariables,
networks: [network], networks: [network],
volumes: [config.volume], volumes: [config.volume],
restart: 'always' restart: 'always',
labels: makeLabelForServices('minio')
} }
}, },
networks: { networks: {

View File

@ -12,6 +12,7 @@ import {
} from '$lib/haproxy'; } from '$lib/haproxy';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -39,7 +40,8 @@ export const post: RequestHandler = async (event) => {
container_name: id, container_name: id,
image: `nocodb/nocodb:${version}`, image: `nocodb/nocodb:${version}`,
networks: [network], networks: [network],
restart: 'always' restart: 'always',
labels: makeLabelForServices('nocodb')
} }
}, },
networks: { networks: {

View File

@ -12,6 +12,7 @@ import {
} from '$lib/haproxy'; } from '$lib/haproxy';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -82,7 +83,6 @@ export const post: RequestHandler = async (event) => {
const network = destinationDockerId && destinationDocker.network; const network = destinationDockerId && destinationDocker.network;
const host = getEngine(destinationDocker.engine); const host = getEngine(destinationDocker.engine);
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
// const labels = await makeLabelForPlausibleAnalytics({ id, })
const { workdir } = await createDirectories({ repository: type, buildId: id }); const { workdir } = await createDirectories({ repository: type, buildId: id });
@ -138,7 +138,8 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
environment: config.plausibleAnalytics.environmentVariables, environment: config.plausibleAnalytics.environmentVariables,
volumes: [config.postgresql.volume], volumes: [config.postgresql.volume],
restart: 'always', restart: 'always',
depends_on: [`${id}-postgresql`, `${id}-clickhouse`] depends_on: [`${id}-postgresql`, `${id}-clickhouse`],
labels: makeLabelForServices('plausibleAnalytics')
}, },
[`${id}-postgresql`]: { [`${id}-postgresql`]: {
container_name: `${id}-postgresql`, container_name: `${id}-postgresql`,

View File

@ -12,6 +12,7 @@ import {
} from '$lib/haproxy'; } from '$lib/haproxy';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { getServiceImage, ErrorHandler } from '$lib/database'; import { getServiceImage, ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -46,7 +47,8 @@ export const post: RequestHandler = async (event) => {
image: config.image, image: config.image,
networks: [network], networks: [network],
volumes: [config.volume], volumes: [config.volume],
restart: 'always' restart: 'always',
labels: makeLabelForServices('vaultWarden')
} }
}, },
networks: { networks: {

View File

@ -12,6 +12,7 @@ import {
} from '$lib/haproxy'; } from '$lib/haproxy';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -54,7 +55,8 @@ export const post: RequestHandler = async (event) => {
environment: config.environmentVariables, environment: config.environmentVariables,
networks: [network], networks: [network],
volumes: [config.volume], volumes: [config.volume],
restart: 'always' restart: 'always',
labels: makeLabelForServices('vscodeServer')
} }
}, },
networks: { networks: {

View File

@ -12,6 +12,7 @@ import {
} from '$lib/haproxy'; } from '$lib/haproxy';
import { getDomain } from '$lib/components/common'; import { getDomain } from '$lib/components/common';
import { ErrorHandler } from '$lib/database'; import { ErrorHandler } from '$lib/database';
import { makeLabelForServices } from '$lib/buildPacks/common';
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const { teamId, status, body } = await getUserDetails(event); const { teamId, status, body } = await getUserDetails(event);
@ -78,7 +79,8 @@ export const post: RequestHandler = async (event) => {
environment: config.wordpress.environmentVariables, environment: config.wordpress.environmentVariables,
networks: [network], networks: [network],
restart: 'always', restart: 'always',
depends_on: [`${id}-mysql`] depends_on: [`${id}-mysql`],
labels: makeLabelForServices('wordpress')
}, },
[`${id}-mysql`]: { [`${id}-mysql`]: {
container_name: `${id}-mysql`, container_name: `${id}-mysql`,