fix: lokale Dump-Datei immer löschen (try/finally)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+51
-48
@@ -77,57 +77,60 @@ async function runBackup(): Promise<void> {
|
|||||||
await dumpToFile(localPath);
|
await dumpToFile(localPath);
|
||||||
console.log(`[backup] Dump geschrieben: ${localPath}`);
|
console.log(`[backup] Dump geschrieben: ${localPath}`);
|
||||||
|
|
||||||
if (!sshUrl) return;
|
try {
|
||||||
|
if (!sshUrl) return;
|
||||||
|
|
||||||
const match = sshUrl.match(/^([^:]+):(.+)$/);
|
const match = sshUrl.match(/^([^:]+):(.+)$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
console.error('[backup] BACKUP_SSH_URL muss das Format user@host:/pfad haben');
|
console.error('[backup] BACKUP_SSH_URL muss das Format user@host:/pfad haben');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [, sshHost, remotePath] = match;
|
const [, sshHost, remotePath] = match;
|
||||||
|
|
||||||
const rawKeyPath = process.env.BACKUP_SSH_KEY_PATH || '';
|
const rawKeyPath = process.env.BACKUP_SSH_KEY_PATH || '';
|
||||||
const keyPath = rawKeyPath.startsWith('~')
|
const keyPath = rawKeyPath.startsWith('~')
|
||||||
? rawKeyPath.replace('~', process.env.HOME || '/root')
|
? rawKeyPath.replace('~', process.env.HOME || '/root')
|
||||||
: rawKeyPath;
|
: rawKeyPath;
|
||||||
|
|
||||||
const sshOpts = [
|
const sshOpts = [
|
||||||
...(keyPath ? ['-i', keyPath] : []),
|
...(keyPath ? ['-i', keyPath] : []),
|
||||||
'-o', 'StrictHostKeyChecking=no',
|
'-o', 'StrictHostKeyChecking=no',
|
||||||
'-o', 'BatchMode=yes',
|
'-o', 'BatchMode=yes',
|
||||||
'-o', 'ConnectTimeout=15',
|
'-o', 'ConnectTimeout=15',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Zielverzeichnis auf Remote anlegen falls nicht vorhanden
|
// Zielverzeichnis auf Remote anlegen falls nicht vorhanden
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const ssh = spawn('ssh', [...sshOpts, sshHost, `mkdir -p ${remotePath}`]);
|
const ssh = spawn('ssh', [...sshOpts, sshHost, `mkdir -p ${remotePath}`]);
|
||||||
ssh.on('error', reject);
|
ssh.on('error', reject);
|
||||||
ssh.on('close', (code) => code === 0 ? resolve() : reject(new Error(`mkdir -p exit ${code}`)));
|
ssh.on('close', (code) => code === 0 ? resolve() : reject(new Error(`mkdir -p exit ${code}`)));
|
||||||
});
|
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
const scp = spawn('scp', [...sshOpts, localPath, `${sshHost}:${remotePath}/${filename}`]);
|
|
||||||
let scpErr = '';
|
|
||||||
scp.stderr.on('data', (d: Buffer) => { scpErr += d.toString(); });
|
|
||||||
scp.on('error', reject);
|
|
||||||
scp.on('close', (code) =>
|
|
||||||
code === 0 ? resolve() : reject(new Error(`scp exit ${code}${scpErr ? ': ' + scpErr.trim() : ''}`))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
unlinkSync(localPath);
|
|
||||||
console.log(`[backup] ${filename} → ${sshHost}:${remotePath}`);
|
|
||||||
|
|
||||||
// Backups älter als 30 Tage auf Remote löschen
|
|
||||||
await new Promise<void>((resolve) => {
|
|
||||||
const ssh = spawn('ssh', [
|
|
||||||
...sshOpts, sshHost,
|
|
||||||
`find ${remotePath} -name 'sternwarte_*.sql.gz' -mtime +30 -delete`,
|
|
||||||
]);
|
|
||||||
ssh.on('error', (e) => { console.error('[backup] Cleanup spawn-Fehler:', e.message); resolve(); });
|
|
||||||
ssh.on('close', (code) => {
|
|
||||||
if (code !== 0) console.error('[backup] Cleanup fehlgeschlagen (exit ' + code + ')');
|
|
||||||
resolve();
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
const scp = spawn('scp', [...sshOpts, localPath, `${sshHost}:${remotePath}/${filename}`]);
|
||||||
|
let scpErr = '';
|
||||||
|
scp.stderr.on('data', (d: Buffer) => { scpErr += d.toString(); });
|
||||||
|
scp.on('error', reject);
|
||||||
|
scp.on('close', (code) =>
|
||||||
|
code === 0 ? resolve() : reject(new Error(`scp exit ${code}${scpErr ? ': ' + scpErr.trim() : ''}`))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[backup] ${filename} → ${sshHost}:${remotePath}`);
|
||||||
|
|
||||||
|
// Backups älter als 30 Tage auf Remote löschen
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const ssh = spawn('ssh', [
|
||||||
|
...sshOpts, sshHost,
|
||||||
|
`find ${remotePath} -name 'sternwarte_*.sql.gz' -mtime +30 -delete`,
|
||||||
|
]);
|
||||||
|
ssh.on('error', (e) => { console.error('[backup] Cleanup spawn-Fehler:', e.message); resolve(); });
|
||||||
|
ssh.on('close', (code) => {
|
||||||
|
if (code !== 0) console.error('[backup] Cleanup fehlgeschlagen (exit ' + code + ')');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
try { unlinkSync(localPath); } catch { /* bereits gelöscht oder nie angelegt */ }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user