fix: restore platform backup data
This commit is contained in:
@@ -206,14 +206,12 @@ export class BackupManager {
|
||||
for (const resourceType of resourceTypes) {
|
||||
const dataDir = `${tempDir}/data/${resourceType}`;
|
||||
try {
|
||||
for await (const entry of Deno.readDir(dataDir)) {
|
||||
if (entry.isFile) {
|
||||
items.push({
|
||||
stream: plugins.nodeFs.createReadStream(`${dataDir}/${entry.name}`),
|
||||
name: `data/${resourceType}/${entry.name}`,
|
||||
type: 'data',
|
||||
});
|
||||
}
|
||||
for await (const filePath of this.walkFiles(dataDir)) {
|
||||
items.push({
|
||||
stream: plugins.nodeFs.createReadStream(filePath),
|
||||
name: plugins.path.relative(tempDir, filePath).replaceAll('\\', '/'),
|
||||
type: 'data',
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// Directory may not exist if export produced no files
|
||||
@@ -819,7 +817,7 @@ export class BackupManager {
|
||||
throw new Error('MongoDB service not running');
|
||||
}
|
||||
|
||||
const connectionUri = credentials.connectionUri || credentials.MONGODB_URI;
|
||||
const connectionUri = credentials.connectionUri || credentials.connectionString || credentials.MONGODB_URI;
|
||||
if (!connectionUri) {
|
||||
throw new Error('MongoDB connection URI not found in credentials');
|
||||
}
|
||||
@@ -836,19 +834,8 @@ export class BackupManager {
|
||||
throw new Error(`mongodump failed: ${result.stderr}`);
|
||||
}
|
||||
|
||||
const container = await this.oneboxRef.docker.getContainerById(mongoService.containerId);
|
||||
if (!container) {
|
||||
throw new Error('MongoDB container not found');
|
||||
}
|
||||
|
||||
const copyResult = await this.oneboxRef.docker.execInContainer(mongoService.containerId, [
|
||||
'cat',
|
||||
archivePath,
|
||||
]);
|
||||
|
||||
const localPath = `${dataDir}/${resource.resourceName}.archive`;
|
||||
const encoder = new TextEncoder();
|
||||
await Deno.writeFile(localPath, encoder.encode(copyResult.stdout));
|
||||
await this.copyFromContainer(mongoService.containerId, archivePath, localPath);
|
||||
|
||||
await this.oneboxRef.docker.execInContainer(mongoService.containerId, ['rm', archivePath]);
|
||||
|
||||
@@ -868,7 +855,7 @@ export class BackupManager {
|
||||
const bucketDir = `${dataDir}/${resource.resourceName}`;
|
||||
await Deno.mkdir(bucketDir, { recursive: true });
|
||||
|
||||
const s3Info = this.getS3ConnectionInfo(credentials);
|
||||
const s3Info = await this.getReachableS3ConnectionInfo(credentials, resource.platformServiceId);
|
||||
const s3Client = this.createS3Client(s3Info);
|
||||
let objectCount = 0;
|
||||
let continuationToken: string | undefined;
|
||||
@@ -1137,6 +1124,36 @@ export class BackupManager {
|
||||
return imageName;
|
||||
}
|
||||
|
||||
private async copyFromContainer(
|
||||
containerId: string,
|
||||
containerPath: string,
|
||||
outputPath: string,
|
||||
): Promise<void> {
|
||||
await this.runDockerCp([`${containerId}:${containerPath}`, outputPath], 'docker cp from container failed');
|
||||
}
|
||||
|
||||
private async copyToContainer(
|
||||
inputPath: string,
|
||||
containerId: string,
|
||||
containerPath: string,
|
||||
): Promise<void> {
|
||||
await this.runDockerCp([inputPath, `${containerId}:${containerPath}`], 'docker cp to container failed');
|
||||
}
|
||||
|
||||
private async runDockerCp(args: string[], errorMessage: string): Promise<void> {
|
||||
const command = new Deno.Command('docker', {
|
||||
args: ['cp', ...args],
|
||||
stdout: 'piped',
|
||||
stderr: 'piped',
|
||||
});
|
||||
const result = await command.output();
|
||||
|
||||
if (!result.success) {
|
||||
const stderr = new TextDecoder().decode(result.stderr).trim();
|
||||
throw new Error(`${errorMessage}: ${stderr}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore platform resources for a service
|
||||
*/
|
||||
@@ -1241,22 +1258,14 @@ export class BackupManager {
|
||||
}
|
||||
|
||||
const archivePath = `${dataDir}/${backupResourceName}.archive`;
|
||||
const connectionUri = credentials.connectionUri || credentials.MONGODB_URI;
|
||||
const connectionUri = credentials.connectionUri || credentials.connectionString || credentials.MONGODB_URI;
|
||||
|
||||
if (!connectionUri) {
|
||||
throw new Error('MongoDB connection URI not found');
|
||||
}
|
||||
|
||||
const archiveData = await Deno.readFile(archivePath);
|
||||
const containerArchivePath = `/tmp/${resource.resourceName}.archive`;
|
||||
|
||||
const base64Data = btoa(String.fromCharCode(...archiveData));
|
||||
|
||||
await this.oneboxRef.docker.execInContainer(mongoService.containerId, [
|
||||
'bash',
|
||||
'-c',
|
||||
`echo '${base64Data}' | base64 -d > ${containerArchivePath}`,
|
||||
]);
|
||||
await this.copyToContainer(archivePath, mongoService.containerId, containerArchivePath);
|
||||
|
||||
const result = await this.oneboxRef.docker.execInContainer(mongoService.containerId, [
|
||||
'mongorestore',
|
||||
@@ -1288,7 +1297,7 @@ export class BackupManager {
|
||||
|
||||
const bucketDir = `${dataDir}/${backupResourceName}`;
|
||||
|
||||
const s3Info = this.getS3ConnectionInfo(credentials);
|
||||
const s3Info = await this.getReachableS3ConnectionInfo(credentials, resource.platformServiceId);
|
||||
const s3Client = this.createS3Client(s3Info);
|
||||
|
||||
let uploadedCount = 0;
|
||||
@@ -1619,6 +1628,39 @@ export class BackupManager {
|
||||
};
|
||||
}
|
||||
|
||||
private async getReachableS3ConnectionInfo(
|
||||
credentials: Record<string, string>,
|
||||
platformServiceId: number,
|
||||
): Promise<IS3ConnectionInfo> {
|
||||
const s3Info = this.getS3ConnectionInfo(credentials);
|
||||
|
||||
let endpointUrl: URL;
|
||||
try {
|
||||
endpointUrl = new URL(s3Info.endpoint);
|
||||
} catch {
|
||||
return s3Info;
|
||||
}
|
||||
|
||||
if (endpointUrl.hostname !== 'onebox-minio') {
|
||||
return s3Info;
|
||||
}
|
||||
|
||||
const platformService = this.oneboxRef.database.getPlatformServiceById(platformServiceId);
|
||||
const hostPort = platformService?.containerId
|
||||
? await this.oneboxRef.docker.getContainerHostPort(platformService.containerId, 9000)
|
||||
: null;
|
||||
if (!hostPort) {
|
||||
return s3Info;
|
||||
}
|
||||
|
||||
endpointUrl.hostname = '127.0.0.1';
|
||||
endpointUrl.port = String(hostPort);
|
||||
return {
|
||||
...s3Info,
|
||||
endpoint: endpointUrl.toString().replace(/\/$/, ''),
|
||||
};
|
||||
}
|
||||
|
||||
private createS3Client(s3Info: IS3ConnectionInfo) {
|
||||
return new plugins.awsS3.S3Client({
|
||||
endpoint: s3Info.endpoint,
|
||||
|
||||
Reference in New Issue
Block a user