mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge branch 'canary' into vicke4/canary
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { IS_CLOUD, paths } from "@dokploy/server/constants";
|
||||
import { updateAdmin } from "@dokploy/server/services/admin";
|
||||
import { type RotatingFileStream, createStream } from "rotating-file-stream";
|
||||
import { db } from "../../db";
|
||||
import { execAsync } from "../process/execAsync";
|
||||
import { findAdmin } from "@dokploy/server/services/admin";
|
||||
import { updateUser } from "@dokploy/server/services/user";
|
||||
|
||||
class LogRotationManager {
|
||||
private static instance: LogRotationManager;
|
||||
@@ -30,17 +30,16 @@ class LogRotationManager {
|
||||
}
|
||||
|
||||
private async getStateFromDB(): Promise<boolean> {
|
||||
const setting = await db.query.admins.findFirst({});
|
||||
return setting?.enableLogRotation ?? false;
|
||||
const admin = await findAdmin();
|
||||
return admin?.user.enableLogRotation ?? false;
|
||||
}
|
||||
|
||||
private async setStateInDB(active: boolean): Promise<void> {
|
||||
const admin = await db.query.admins.findFirst({});
|
||||
|
||||
const admin = await findAdmin();
|
||||
if (!admin) {
|
||||
return;
|
||||
}
|
||||
await updateAdmin(admin?.authId, {
|
||||
await updateUser(admin.user.id, {
|
||||
enableLogRotation: active,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { findAdmin } from "@dokploy/server/services/admin";
|
||||
import { getAllServers } from "@dokploy/server/services/server";
|
||||
import { scheduleJob } from "node-schedule";
|
||||
import { db } from "../../db/index";
|
||||
@@ -12,13 +11,14 @@ import { runMariadbBackup } from "./mariadb";
|
||||
import { runMongoBackup } from "./mongo";
|
||||
import { runMySqlBackup } from "./mysql";
|
||||
import { runPostgresBackup } from "./postgres";
|
||||
import { findAdmin } from "../../services/admin";
|
||||
|
||||
export const initCronJobs = async () => {
|
||||
console.log("Setting up cron jobs....");
|
||||
|
||||
const admin = await findAdmin();
|
||||
|
||||
if (admin?.enableDockerCleanup) {
|
||||
if (admin?.user.enableDockerCleanup) {
|
||||
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
||||
console.log(
|
||||
`Docker Cleanup ${new Date().toLocaleString()}] Running docker cleanup`,
|
||||
@@ -26,7 +26,7 @@ export const initCronJobs = async () => {
|
||||
await cleanUpUnusedImages();
|
||||
await cleanUpDockerBuilder();
|
||||
await cleanUpSystemPrune();
|
||||
await sendDockerCleanupNotifications(admin.adminId);
|
||||
await sendDockerCleanupNotifications(admin.user.id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export const initCronJobs = async () => {
|
||||
await cleanUpDockerBuilder(serverId);
|
||||
await cleanUpSystemPrune(serverId);
|
||||
await sendDockerCleanupNotifications(
|
||||
admin.adminId,
|
||||
admin.user.id,
|
||||
`Docker cleanup for Server ${name} (${serverId})`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ export const runMariadbBackup = async (
|
||||
projectName: project.name,
|
||||
databaseType: "mariadb",
|
||||
type: "success",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -60,7 +60,7 @@ export const runMariadbBackup = async (
|
||||
type: "error",
|
||||
// @ts-ignore
|
||||
errorMessage: error?.message || "Error message not provided",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
|
||||
projectName: project.name,
|
||||
databaseType: "mongodb",
|
||||
type: "success",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -57,7 +57,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
|
||||
type: "error",
|
||||
// @ts-ignore
|
||||
errorMessage: error?.message || "Error message not provided",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { unlink } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
||||
import type { MySql } from "@dokploy/server/services/mysql";
|
||||
@@ -46,7 +45,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
|
||||
projectName: project.name,
|
||||
databaseType: "mysql",
|
||||
type: "success",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
@@ -57,7 +56,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
|
||||
type: "error",
|
||||
// @ts-ignore
|
||||
errorMessage: error?.message || "Error message not provided",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export const runPostgresBackup = async (
|
||||
projectName: project.name,
|
||||
databaseType: "postgres",
|
||||
type: "success",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
} catch (error) {
|
||||
await sendDatabaseBackupNotifications({
|
||||
@@ -59,7 +59,7 @@ export const runPostgresBackup = async (
|
||||
type: "error",
|
||||
// @ts-ignore
|
||||
errorMessage: error?.message || "Error message not provided",
|
||||
adminId: project.adminId,
|
||||
organizationId: project.organizationId,
|
||||
});
|
||||
|
||||
throw error;
|
||||
|
||||
@@ -28,7 +28,7 @@ export const removeScheduleBackup = (backupId: string) => {
|
||||
};
|
||||
|
||||
export const getS3Credentials = (destination: Destination) => {
|
||||
const { accessKey, secretAccessKey, bucket, region, endpoint, provider } =
|
||||
const { accessKey, secretAccessKey, region, endpoint, provider } =
|
||||
destination;
|
||||
const rcloneFlags = [
|
||||
`--s3-access-key-id=${accessKey}`,
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
createWriteStream,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
@@ -99,8 +98,7 @@ export const getBuildComposeCommand = async (
|
||||
logPath: string,
|
||||
) => {
|
||||
const { COMPOSE_PATH } = paths(true);
|
||||
const { sourceType, appName, mounts, composeType, domains, composePath } =
|
||||
compose;
|
||||
const { sourceType, appName, mounts, composeType, domains } = compose;
|
||||
const command = createCommand(compose);
|
||||
const envCommand = getCreateEnvFileCommand(compose);
|
||||
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
|
||||
|
||||
@@ -197,7 +197,7 @@ export const mechanizeDockerContainer = async (
|
||||
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ export const getNixpacksCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { env, appName, publishDirectory, serverId } = application;
|
||||
const { env, appName, publishDirectory } = application;
|
||||
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const buildContainerId = `${appName}-${nanoid(10)}`;
|
||||
|
||||
@@ -98,7 +98,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
||||
version: Number.parseInt(inspect.Version.Index),
|
||||
...settings,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,7 +152,7 @@ ${command ?? "wait $MONGOD_PID"}`;
|
||||
version: Number.parseInt(inspect.Version.Index),
|
||||
...settings,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,7 +104,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
||||
version: Number.parseInt(inspect.Version.Index),
|
||||
...settings,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,7 +95,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
||||
version: Number.parseInt(inspect.Version.Index),
|
||||
...settings,
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ export const loadDockerComposeRemote = async (
|
||||
if (!stdout) return null;
|
||||
const parsedConfig = load(stdout) as ComposeSpecification;
|
||||
return parsedConfig;
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -100,7 +100,7 @@ export const containerExists = async (containerName: string) => {
|
||||
try {
|
||||
await container.inspect();
|
||||
return true;
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -240,7 +240,7 @@ export const startServiceRemote = async (serverId: string, appName: string) => {
|
||||
export const removeService = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
deleteVolumes = false,
|
||||
_deleteVolumes = false,
|
||||
) => {
|
||||
try {
|
||||
const command = `docker service rm ${appName}`;
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function checkGPUStatus(serverId?: string): Promise<GPUInfo> {
|
||||
...gpuInfo,
|
||||
...cudaInfo,
|
||||
};
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
return {
|
||||
driverInstalled: false,
|
||||
driverVersion: undefined,
|
||||
@@ -315,7 +315,7 @@ const setupLocalServer = async (daemonConfig: any) => {
|
||||
|
||||
try {
|
||||
await execAsync(setupCommands);
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
throw new Error(
|
||||
"Failed to configure GPU support. Please ensure you have sudo privileges and try again.",
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ interface Props {
|
||||
applicationType: string;
|
||||
errorMessage: string;
|
||||
buildLink: string;
|
||||
adminId: string;
|
||||
organizationId: string;
|
||||
}
|
||||
|
||||
export const sendBuildErrorNotifications = async ({
|
||||
@@ -27,14 +27,14 @@ export const sendBuildErrorNotifications = async ({
|
||||
applicationType,
|
||||
errorMessage,
|
||||
buildLink,
|
||||
adminId,
|
||||
organizationId,
|
||||
}: Props) => {
|
||||
const date = new Date();
|
||||
const unixDate = ~~(Number(date) / 1000);
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
eq(notifications.appBuildError, true),
|
||||
eq(notifications.adminId, adminId),
|
||||
eq(notifications.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
|
||||
@@ -18,7 +18,7 @@ interface Props {
|
||||
applicationName: string;
|
||||
applicationType: string;
|
||||
buildLink: string;
|
||||
adminId: string;
|
||||
organizationId: string;
|
||||
domains: Domain[];
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export const sendBuildSuccessNotifications = async ({
|
||||
applicationName,
|
||||
applicationType,
|
||||
buildLink,
|
||||
adminId,
|
||||
organizationId,
|
||||
domains,
|
||||
}: Props) => {
|
||||
const date = new Date();
|
||||
@@ -35,7 +35,7 @@ export const sendBuildSuccessNotifications = async ({
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
eq(notifications.appDeploy, true),
|
||||
eq(notifications.adminId, adminId),
|
||||
eq(notifications.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { error } from "node:console";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import { notifications } from "@dokploy/server/db/schema";
|
||||
import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup";
|
||||
@@ -19,13 +18,13 @@ export const sendDatabaseBackupNotifications = async ({
|
||||
databaseType,
|
||||
type,
|
||||
errorMessage,
|
||||
adminId,
|
||||
organizationId,
|
||||
}: {
|
||||
projectName: string;
|
||||
applicationName: string;
|
||||
databaseType: "postgres" | "mysql" | "mongodb" | "mariadb";
|
||||
type: "error" | "success";
|
||||
adminId: string;
|
||||
organizationId: string;
|
||||
errorMessage?: string;
|
||||
}) => {
|
||||
const date = new Date();
|
||||
@@ -33,7 +32,7 @@ export const sendDatabaseBackupNotifications = async ({
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
eq(notifications.databaseBackup, true),
|
||||
eq(notifications.adminId, adminId),
|
||||
eq(notifications.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "./utils";
|
||||
|
||||
export const sendDockerCleanupNotifications = async (
|
||||
adminId: string,
|
||||
organizationId: string,
|
||||
message = "Docker cleanup for dokploy",
|
||||
) => {
|
||||
const date = new Date();
|
||||
@@ -21,7 +21,7 @@ export const sendDockerCleanupNotifications = async (
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
eq(notifications.dockerCleanup, true),
|
||||
eq(notifications.adminId, adminId),
|
||||
eq(notifications.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
|
||||
@@ -18,7 +18,7 @@ interface ServerThresholdPayload {
|
||||
}
|
||||
|
||||
export const sendServerThresholdNotifications = async (
|
||||
adminId: string,
|
||||
organizationId: string,
|
||||
payload: ServerThresholdPayload,
|
||||
) => {
|
||||
const date = new Date(payload.Timestamp);
|
||||
@@ -27,7 +27,7 @@ export const sendServerThresholdNotifications = async (
|
||||
const notificationList = await db.query.notifications.findMany({
|
||||
where: and(
|
||||
eq(notifications.serverThreshold, true),
|
||||
eq(notifications.adminId, adminId),
|
||||
eq(notifications.organizationId, organizationId),
|
||||
),
|
||||
with: {
|
||||
email: true,
|
||||
|
||||
@@ -27,7 +27,7 @@ export const execAsyncRemote = async (
|
||||
throw err;
|
||||
}
|
||||
stream
|
||||
.on("close", (code: number, signal: string) => {
|
||||
.on("close", (code: number, _signal: string) => {
|
||||
conn.end();
|
||||
if (code === 0) {
|
||||
resolve({ stdout, stderr });
|
||||
|
||||
@@ -176,7 +176,6 @@ export const getBitbucketCloneCommand = async (
|
||||
bitbucketBranch,
|
||||
bitbucketId,
|
||||
serverId,
|
||||
bitbucket,
|
||||
} = entity;
|
||||
|
||||
if (!serverId) {
|
||||
|
||||
@@ -320,7 +320,7 @@ export const cloneGitRawRepository = async (entity: {
|
||||
outputPath,
|
||||
"--progress",
|
||||
],
|
||||
(data) => {},
|
||||
(_data) => {},
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -162,8 +162,6 @@ export const getGitlabCloneCommand = async (
|
||||
) => {
|
||||
const {
|
||||
appName,
|
||||
gitlabRepository,
|
||||
gitlabOwner,
|
||||
gitlabPathNamespace,
|
||||
gitlabBranch,
|
||||
gitlabId,
|
||||
@@ -268,7 +266,7 @@ export const getGitlabRepositories = async (gitlabId?: string) => {
|
||||
if (groupName) {
|
||||
return full_path.toLowerCase().includes(groupName) && kind === "group";
|
||||
}
|
||||
return kind === "user";
|
||||
return kind === "member";
|
||||
});
|
||||
const mappedRepositories = filteredRepos.map((repo: any) => {
|
||||
return {
|
||||
@@ -328,14 +326,7 @@ export const getGitlabBranches = async (input: {
|
||||
};
|
||||
|
||||
export const cloneRawGitlabRepository = async (entity: Compose) => {
|
||||
const {
|
||||
appName,
|
||||
gitlabRepository,
|
||||
gitlabOwner,
|
||||
gitlabBranch,
|
||||
gitlabId,
|
||||
gitlabPathNamespace,
|
||||
} = entity;
|
||||
const { appName, gitlabBranch, gitlabId, gitlabPathNamespace } = entity;
|
||||
|
||||
if (!gitlabId) {
|
||||
throw new TRPCError({
|
||||
@@ -442,7 +433,7 @@ export const testGitlabConnection = async (
|
||||
if (groupName) {
|
||||
return full_path.toLowerCase().includes(groupName) && kind === "group";
|
||||
}
|
||||
return kind === "user";
|
||||
return kind === "member";
|
||||
});
|
||||
|
||||
return filteredRepos.length;
|
||||
|
||||
@@ -67,7 +67,7 @@ export const removeTraefikConfig = async (
|
||||
if (fs.existsSync(configPath)) {
|
||||
await fs.promises.unlink(configPath);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (_error) {}
|
||||
};
|
||||
|
||||
export const removeTraefikConfigRemote = async (
|
||||
@@ -78,7 +78,7 @@ export const removeTraefikConfigRemote = async (
|
||||
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
||||
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
||||
await execAsyncRemote(serverId, `rm ${configPath}`);
|
||||
} catch (error) {}
|
||||
} catch (_error) {}
|
||||
};
|
||||
|
||||
export const loadOrCreateConfig = (appName: string): FileConfig => {
|
||||
@@ -110,7 +110,7 @@ export const loadOrCreateConfigRemote = async (
|
||||
http: { routers: {}, services: {} },
|
||||
};
|
||||
return parsedConfig;
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return fileConfig;
|
||||
}
|
||||
};
|
||||
@@ -132,7 +132,7 @@ export const readRemoteConfig = async (serverId: string, appName: string) => {
|
||||
const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`);
|
||||
if (!stdout) return null;
|
||||
return stdout;
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -122,13 +122,25 @@ export const createRouterConfig = async (
|
||||
if ((entryPoint === "websecure" && https) || !https) {
|
||||
// redirects
|
||||
for (const redirect of redirects) {
|
||||
const middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
|
||||
let middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
|
||||
if (domain.domainType === "preview") {
|
||||
middlewareName = `redirect-${appName.replace(
|
||||
/^preview-(.+)-[^-]+$/,
|
||||
"$1",
|
||||
)}-${redirect.uniqueConfigKey}`;
|
||||
}
|
||||
routerConfig.middlewares?.push(middlewareName);
|
||||
}
|
||||
|
||||
// security
|
||||
if (security.length > 0) {
|
||||
const middlewareName = `auth-${appName}`;
|
||||
let middlewareName = `auth-${appName}`;
|
||||
if (domain.domainType === "preview") {
|
||||
middlewareName = `auth-${appName.replace(
|
||||
/^preview-(.+)-[^-]+$/,
|
||||
"$1",
|
||||
)}`;
|
||||
}
|
||||
routerConfig.middlewares?.push(middlewareName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export const loadRemoteMiddlewares = async (serverId: string) => {
|
||||
}
|
||||
const config = load(stdout) as FileConfig;
|
||||
return config;
|
||||
} catch (error) {
|
||||
} catch (_) {
|
||||
throw new Error(`File not found: ${configPath}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { paths } from "@dokploy/server/constants";
|
||||
import type { Admin } from "@dokploy/server/services/admin";
|
||||
import type { User } from "@dokploy/server/services/user";
|
||||
import { dump, load } from "js-yaml";
|
||||
import { loadOrCreateConfig, writeTraefikConfig } from "./application";
|
||||
import type { FileConfig } from "./file-types";
|
||||
import type { MainTraefikConfig } from "./types";
|
||||
|
||||
export const updateServerTraefik = (
|
||||
admin: Admin | null,
|
||||
user: User | null,
|
||||
newHost: string | null,
|
||||
) => {
|
||||
const appName = "dokploy";
|
||||
@@ -22,7 +22,7 @@ export const updateServerTraefik = (
|
||||
if (currentRouterConfig && newHost) {
|
||||
currentRouterConfig.rule = `Host(\`${newHost}\`)`;
|
||||
|
||||
if (admin?.certificateType === "letsencrypt") {
|
||||
if (user?.certificateType === "letsencrypt") {
|
||||
config.http.routers[`${appName}-router-app-secure`] = {
|
||||
...currentRouterConfig,
|
||||
entryPoints: ["websecure"],
|
||||
|
||||
Reference in New Issue
Block a user