mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-28 18:45:22 +02:00
- Created a new SQL type for 'libsql' and established a corresponding table with necessary fields and constraints. - Updated existing tables (backup, mount, volume_backup) to include foreign key references to 'libsql'. - Enhanced the libsql schema in the application to support additional fields such as stopGracePeriodSwarm and endpointSpecSwarm. - Adjusted form handling and validation to accommodate the new libsql service type, improving overall integration and functionality.
164 lines
5.3 KiB
TypeScript
164 lines
5.3 KiB
TypeScript
import path from "node:path";
|
|
import { paths } from "@dokploy/server/constants";
|
|
import { findComposeById } from "@dokploy/server/services/compose";
|
|
import type { findVolumeBackupById } from "@dokploy/server/services/volume-backups";
|
|
import { getS3Credentials, normalizeS3Path } from "../backups/utils";
|
|
|
|
export const getVolumeServiceAppName = (
|
|
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
|
|
): string => {
|
|
if (volumeBackup.compose?.appName) {
|
|
return volumeBackup.serviceName
|
|
? `${volumeBackup.compose.appName}_${volumeBackup.serviceName}`
|
|
: volumeBackup.compose.appName;
|
|
}
|
|
const serviceAppName =
|
|
volumeBackup.application?.appName ||
|
|
volumeBackup.postgres?.appName ||
|
|
volumeBackup.mysql?.appName ||
|
|
volumeBackup.mariadb?.appName ||
|
|
volumeBackup.mongo?.appName ||
|
|
volumeBackup.redis?.appName ||
|
|
volumeBackup.libsql?.appName;
|
|
return serviceAppName || volumeBackup.appName;
|
|
};
|
|
|
|
export const backupVolume = async (
|
|
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
|
|
) => {
|
|
const { serviceType, volumeName, turnOff, prefix } = volumeBackup;
|
|
const serverId =
|
|
volumeBackup.application?.serverId || volumeBackup.compose?.serverId;
|
|
const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId);
|
|
const destination = volumeBackup.destination;
|
|
const s3AppName = getVolumeServiceAppName(volumeBackup);
|
|
const backupFileName = `${volumeName}-${new Date().toISOString()}.tar`;
|
|
const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix || "")}${backupFileName}`;
|
|
const rcloneFlags = getS3Credentials(volumeBackup.destination);
|
|
const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`;
|
|
const volumeBackupPath = path.join(VOLUME_BACKUPS_PATH, volumeBackup.appName);
|
|
|
|
const rcloneCommand = `rclone copyto ${rcloneFlags.join(" ")} "${volumeBackupPath}/${backupFileName}" "${rcloneDestination}"`;
|
|
|
|
const backupCommand = `
|
|
set -e
|
|
echo "Volume name: ${volumeName}"
|
|
echo "Backup file name: ${backupFileName}"
|
|
echo "Turning off volume backup: ${turnOff ? "Yes" : "No"}"
|
|
echo "Starting volume backup"
|
|
echo "Dir: ${volumeBackupPath}"
|
|
docker run --rm \
|
|
-v ${volumeName}:/volume_data \
|
|
-v ${volumeBackupPath}:/backup \
|
|
ubuntu \
|
|
bash -c "cd /volume_data && tar cvf /backup/${backupFileName} ."
|
|
echo "Volume backup done ✅"
|
|
`;
|
|
|
|
const uploadCommand = `
|
|
echo "Starting upload to S3..."
|
|
${rcloneCommand}
|
|
echo "Upload to S3 done ✅"
|
|
echo "Cleaning up local backup file..."
|
|
rm "${volumeBackupPath}/${backupFileName}"
|
|
echo "Local backup file cleaned up ✅"
|
|
`;
|
|
|
|
if (!turnOff) {
|
|
return `
|
|
${backupCommand}
|
|
${uploadCommand}
|
|
`;
|
|
}
|
|
|
|
const serviceLockId =
|
|
serviceType === "application"
|
|
? volumeBackup.application?.appName
|
|
: `${volumeBackup.compose?.appName}_${volumeBackup.serviceName}`;
|
|
|
|
const lockPath = `${VOLUME_BACKUP_LOCK_PATH}-${serviceLockId}`;
|
|
|
|
const lockWrapper = (body: string) => `
|
|
set -e
|
|
|
|
LOCK_PATH="${lockPath}"
|
|
|
|
echo "Waiting for volume backup lock: $LOCK_PATH"
|
|
|
|
if command -v flock >/dev/null 2>&1; then
|
|
exec 9>"$LOCK_PATH"
|
|
flock 9
|
|
else
|
|
LOCK_DIR="$LOCK_PATH.dir"
|
|
while ! mkdir "$LOCK_DIR" 2>/dev/null; do
|
|
echo "Waiting for volume backup lock: $LOCK_PATH"
|
|
sleep 5
|
|
done
|
|
trap 'rm -rf "$LOCK_DIR"' EXIT
|
|
fi
|
|
|
|
echo "Volume backup lock acquired"
|
|
|
|
${body}
|
|
|
|
echo "Volume backup lock released"
|
|
`;
|
|
|
|
console.log(
|
|
lockWrapper(`
|
|
echo "Volume backup lock acquired"
|
|
echo "Volume backup lock released"
|
|
`),
|
|
);
|
|
|
|
if (serviceType === "application") {
|
|
return lockWrapper(`
|
|
echo "Stopping application to 0 replicas"
|
|
ACTUAL_REPLICAS=$(docker service inspect ${volumeBackup.application?.appName} --format "{{.Spec.Mode.Replicated.Replicas}}")
|
|
echo "Actual replicas: $ACTUAL_REPLICAS"
|
|
docker service update --replicas=0 ${volumeBackup.application?.appName}
|
|
${backupCommand}
|
|
echo "Starting application to $ACTUAL_REPLICAS replicas"
|
|
docker service update --replicas=$ACTUAL_REPLICAS --with-registry-auth ${volumeBackup.application?.appName}
|
|
${uploadCommand}
|
|
`);
|
|
}
|
|
if (serviceType === "compose") {
|
|
const compose = await findComposeById(
|
|
volumeBackup.compose?.composeId || "",
|
|
);
|
|
let stopCommand = "";
|
|
let startCommand = "";
|
|
|
|
if (compose.composeType === "stack") {
|
|
stopCommand = `
|
|
echo "Stopping compose to 0 replicas"
|
|
echo "Service name: ${compose.appName}_${volumeBackup.serviceName}"
|
|
ACTUAL_REPLICAS=$(docker service inspect ${compose.appName}_${volumeBackup.serviceName} --format "{{.Spec.Mode.Replicated.Replicas}}")
|
|
echo "Actual replicas: $ACTUAL_REPLICAS"
|
|
docker service update --replicas=0 ${compose.appName}_${volumeBackup.serviceName}`;
|
|
|
|
startCommand = `
|
|
echo "Starting compose to $ACTUAL_REPLICAS replicas"
|
|
docker service update --replicas=$ACTUAL_REPLICAS --with-registry-auth ${compose.appName}_${volumeBackup.serviceName}`;
|
|
} else {
|
|
stopCommand = `
|
|
echo "Stopping compose container"
|
|
ID=$(docker ps -q --filter "label=com.docker.compose.project=${compose.appName}" --filter "label=com.docker.compose.service=${volumeBackup.serviceName}")
|
|
docker stop $ID`;
|
|
|
|
startCommand = `
|
|
echo "Starting compose container"
|
|
docker start $ID
|
|
echo "Compose container started"
|
|
`;
|
|
}
|
|
return lockWrapper(`
|
|
${stopCommand}
|
|
${backupCommand}
|
|
${startCommand}
|
|
${uploadCommand}
|
|
`);
|
|
}
|
|
};
|