feat: add deployable option to randomize and prevent colission in duplicate templates

This commit is contained in:
Mauricio Siu
2025-02-03 00:57:18 -06:00
parent 97b77e526d
commit 6f2148c060
13 changed files with 4872 additions and 6 deletions

View File

@@ -69,6 +69,7 @@ export const compose = pgTable("compose", {
composePath: text("composePath").notNull().default("./docker-compose.yml"),
suffix: text("suffix").notNull().default(""),
randomize: boolean("randomize").notNull().default(false),
deployable: boolean("deployable").notNull().default(false),
composeStatus: applicationStatus("composeStatus").notNull().default("idle"),
projectId: text("projectId")
.notNull()

View File

@@ -73,6 +73,7 @@ export * from "./utils/builders/utils";
export * from "./utils/cluster/upload";
export * from "./utils/docker/compose";
export * from "./utils/docker/collision";
export * from "./utils/docker/domain";
export * from "./utils/docker/utils";
export * from "./utils/docker/types";

View File

@@ -34,6 +34,9 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
await writeDomainsToCompose(compose, domains);
createEnvFile(compose);
await execAsync(
`docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`,
);
const logContent = `
App Name: ${appName}
Build Compose 🐳
@@ -73,6 +76,10 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
},
);
await execAsync(
`docker network connect tes-umami-e842bc $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`,
);
writeStream.write("Docker Compose Deployed: ✅");
} catch (error) {
writeStream.write(`Error ❌ ${(error as Error).message}`);

View File

@@ -0,0 +1,51 @@
import { findComposeById } from "@dokploy/server/services/compose";
import { addAppNameToAllContainerNames } from "./collision/container-name";
import { addAppNameToAllServiceNames } from "./collision/root-network";
import { addSuffixToAllVolumes } from "./compose/volume";
import type { ComposeSpecification } from "./types";
import { dump, load } from "js-yaml";
import { generateRandomHash } from "./compose";
export const addAppNameToPreventCollision = (
composeData: ComposeSpecification,
appName: string,
): ComposeSpecification => {
let updatedComposeData = { ...composeData };
updatedComposeData = addAppNameToAllContainerNames(
updatedComposeData,
appName,
);
updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName);
updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName);
return updatedComposeData;
};
export const randomizeDeployableComposeFile = async (
composeId: string,
suffix?: string,
) => {
const compose = await findComposeById(composeId);
const composeFile = compose.composeFile;
const composeData = load(composeFile) as ComposeSpecification;
const randomSuffix = suffix || compose.appName || generateRandomHash();
const newComposeFile = addAppNameToPreventCollision(
composeData,
randomSuffix,
);
return dump(newComposeFile);
};
export const randomizeDeployableSpecificationFile = (
composeSpec: ComposeSpecification,
suffix?: string,
) => {
if (!suffix) {
return composeSpec;
}
const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix);
return newComposeFile;
};

View File

@@ -0,0 +1,26 @@
import type { ComposeSpecification, DefinitionsService } from "../types";
import _ from "lodash";
export const addAppNameToContainerNames = (
services: { [key: string]: DefinitionsService },
appName: string,
): { [key: string]: DefinitionsService } => {
return _.mapValues(services, (service, serviceName) => {
service.container_name = `${appName}-${serviceName}`;
return service;
});
};
export const addAppNameToAllContainerNames = (
composeData: ComposeSpecification,
appName: string,
): ComposeSpecification => {
const updatedComposeData = { ...composeData };
if (updatedComposeData.services) {
updatedComposeData.services = addAppNameToContainerNames(
updatedComposeData.services,
appName,
);
}
return updatedComposeData;
};

View File

@@ -0,0 +1,62 @@
import type { ComposeSpecification, DefinitionsService } from "../types";
import _ from "lodash";
export const addAppNameToRootNetwork = (
composeData: ComposeSpecification,
appName: string,
): ComposeSpecification => {
const updatedComposeData = { ...composeData };
// Initialize networks if it doesn't exist
if (!updatedComposeData.networks) {
updatedComposeData.networks = {};
}
// Add the new network with the app name
updatedComposeData.networks[appName] = {
name: appName,
external: true,
};
return updatedComposeData;
};
export const addAppNameToServiceNetworks = (
services: { [key: string]: DefinitionsService },
appName: string,
): { [key: string]: DefinitionsService } => {
return _.mapValues(services, (service) => {
if (!service.networks) {
service.networks = [appName];
return service;
}
if (Array.isArray(service.networks)) {
if (!service.networks.includes(appName)) {
service.networks.push(appName);
}
} else {
service.networks[appName] = {};
}
return service;
});
};
export const addAppNameToAllServiceNames = (
composeData: ComposeSpecification,
appName: string,
): ComposeSpecification => {
let updatedComposeData = { ...composeData };
updatedComposeData = addAppNameToRootNetwork(updatedComposeData, appName);
if (updatedComposeData.services) {
updatedComposeData.services = addAppNameToServiceNetworks(
updatedComposeData.services,
appName,
);
}
return updatedComposeData;
};

View File

@@ -33,6 +33,7 @@ import type {
PropertiesNetworks,
} from "./types";
import { encodeBase64 } from "./utils";
import { randomizeDeployableSpecificationFile } from "./collision";
export const cloneCompose = async (compose: Compose) => {
if (compose.sourceType === "github") {
@@ -190,7 +191,13 @@ export const addDomainToCompose = async (
return null;
}
if (compose.randomize) {
if (compose.deployable) {
const randomized = randomizeDeployableSpecificationFile(
result,
compose.suffix || compose.appName,
);
result = randomized;
} else if (compose.randomize) {
const randomized = randomizeSpecificationFile(result, compose.suffix);
result = randomized;
}
@@ -240,14 +247,18 @@ export const addDomainToCompose = async (
labels.push(...httpLabels);
}
// Add the dokploy-network to the service
result.services[serviceName].networks = addDokployNetworkToService(
result.services[serviceName].networks,
);
if (!compose.deployable) {
// Add the dokploy-network to the service
result.services[serviceName].networks = addDokployNetworkToService(
result.services[serviceName].networks,
);
}
}
// Add dokploy-network to the root of the compose file
result.networks = addDokployNetworkToRoot(result.networks);
if (!compose.deployable) {
result.networks = addDokployNetworkToRoot(result.networks);
}
return result;
};