fix(apps): always attempt K8s cleanup on delete, cluster service fixes
- Delete endpoint no longer requires clusterId && latestImageTag - Clusters: getDefault fallback logic, reassign apps on delete - Unit tests for cluster default/delete logic
This commit is contained in:
@@ -62,7 +62,7 @@ export class ApplicationsController {
|
||||
}
|
||||
|
||||
@Post(':id/db-upload')
|
||||
@ApiOperation({ summary: 'Upload and restore a SQL dump into the application database' })
|
||||
@ApiOperation({ summary: 'Upload a SQL dump file for later restore during deployment' })
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@UseInterceptors(FileInterceptor('file', {
|
||||
limits: { fileSize: 500 * 1024 * 1024 }, // 500MB for DB dumps
|
||||
@@ -84,12 +84,13 @@ export class ApplicationsController {
|
||||
}
|
||||
|
||||
this.logger.log(`DB dump upload for ${app.name} — ${(file.size / 1024).toFixed(1)} KB`);
|
||||
const result = await this.kubernetesService.restoreDatabaseDump(app, file.buffer);
|
||||
|
||||
// Save to disk (restore happens after deploy when namespace exists)
|
||||
await this.applicationsService.uploadDbDump(id, isStaff ? app.userId : req.user.id, file);
|
||||
|
||||
return {
|
||||
success: result.success,
|
||||
message: result.success ? 'Database restored successfully' : 'Database restore failed',
|
||||
logs: result.logs,
|
||||
success: true,
|
||||
message: 'Database dump uploaded. It will be restored automatically after deployment.',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -225,12 +226,10 @@ export class ApplicationsController {
|
||||
// 1. Get the app first
|
||||
const app = await this.applicationsService.findOne(id, isStaff ? undefined : req.user.id);
|
||||
|
||||
// 2. Delete K8s resources (deployment, service, ingress, db, secrets)
|
||||
// 2. Delete K8s resources (deployment, service, ingress, db, secrets, PVCs)
|
||||
try {
|
||||
if (app.clusterId && app.latestImageTag) {
|
||||
await this.kubernetesService.deleteApplication(app);
|
||||
this.logger.log(`Deleted K8s resources for ${app.name}`);
|
||||
}
|
||||
await this.kubernetesService.deleteApplication(app);
|
||||
this.logger.log(`Deleted K8s resources for ${app.name}`);
|
||||
} catch (e: any) {
|
||||
this.logger.warn(`K8s cleanup failed for ${app.name}: ${e.message}`);
|
||||
}
|
||||
|
||||
@@ -188,4 +188,28 @@ export class ApplicationsService {
|
||||
this.logger.log(`Uploaded code for ${app.name} → ${zipPath} (${(file.size / 1024).toFixed(1)} KB)`);
|
||||
return saved;
|
||||
}
|
||||
|
||||
async uploadDbDump(id: string, userId: string, file: Express.Multer.File): Promise<Application> {
|
||||
if (!file) {
|
||||
throw new BadRequestException('No file uploaded');
|
||||
}
|
||||
|
||||
const app = await this.findOne(id, userId);
|
||||
const uploadDir = this.configService.get<string>('platform.uploadDir') || './uploads';
|
||||
const appDir = path.join(uploadDir, app.userId, app.id);
|
||||
|
||||
// Ensure directory exists
|
||||
fs.mkdirSync(appDir, { recursive: true });
|
||||
|
||||
// Save the SQL dump file
|
||||
const dumpPath = path.join(appDir, 'dump.sql');
|
||||
fs.writeFileSync(dumpPath, file.buffer);
|
||||
|
||||
// Update app with dump path
|
||||
app.dbDumpPath = dumpPath;
|
||||
const saved = await this.appsRepository.save(app);
|
||||
|
||||
this.logger.log(`Uploaded DB dump for ${app.name} → ${dumpPath} (${(file.size / 1024).toFixed(1)} KB)`);
|
||||
return saved;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user