0bb384e7-e18c-49c5-b7ef-fe73701ab6ab
This commit is contained in:
1 parent
c4d338ee48
commit
8c34778db3
8 files changed
+121
-52
No files matched your search
@@ -176,6 +176,9 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
||||
// Parse metadata for Dokploy domain ID
|
||||
const meta = instance.metadata ? JSON.parse(instance.metadata) as { dokployDomainId?: string; url?: string } : {}
|
||||
|
||||
let dokployFailed = false
|
||||
let dnsFailed = false
|
||||
|
||||
// 1. Remove Dokploy domain + database + application (idempotent)
|
||||
if (dokploy) {
|
||||
try {
|
||||
@@ -189,6 +192,7 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
||||
data: { instanceId: id, type: 'delete.dokploy.done', step: 'dokploy', result: 'ok', details: JSON.stringify({ steps: result.steps }) },
|
||||
})
|
||||
} catch (e) {
|
||||
dokployFailed = true
|
||||
steps.push(`dokploy.error: ${e instanceof Error ? e.message : 'unknown'}`)
|
||||
await db.instanceEvent.create({
|
||||
data: { instanceId: id, type: 'delete.dokploy.error', step: 'dokploy', result: 'error', details: JSON.stringify({ error: e instanceof Error ? e.message : 'unknown' }) },
|
||||
@@ -198,7 +202,11 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
||||
steps.push('dokploy.skipped (not configured)')
|
||||
}
|
||||
|
||||
// 2. Remove DNS A record (if per-instance, not wildcard)
|
||||
// 2. Remove DNS A record (if per-instance, not wildcard).
|
||||
// IMPORTANT: Dokploy silme başarısız olsa bile DNS'i silmeye çalış —
|
||||
// orphaned DNS record subdomain takeover riski taşır. Ama DNS silme
|
||||
// hata verirse dnsRecordId'yi KORU, instance'ı failed yap ki reconciler
|
||||
// sonra tekrar deneyebilsin.
|
||||
if (dns && instance.dnsRecordId && instance.dnsRecordId !== 'wildcard') {
|
||||
try {
|
||||
await dns.deleteRecord(instance.dnsRecordId)
|
||||
@@ -207,12 +215,50 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
||||
data: { instanceId: id, type: 'delete.dns.removed', step: 'dns', result: 'ok', details: JSON.stringify({ recordId: instance.dnsRecordId }) },
|
||||
})
|
||||
} catch (e) {
|
||||
dnsFailed = true
|
||||
steps.push(`dns.error: ${e instanceof Error ? e.message : 'unknown'}`)
|
||||
await db.instanceEvent.create({
|
||||
data: { instanceId: id, type: 'delete.dns.error', step: 'dns', result: 'error', details: JSON.stringify({ recordId: instance.dnsRecordId, error: e instanceof Error ? e.message : 'unknown' }) },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Mark deleted (keep the row for audit — GoBD)
|
||||
// 3. Decide final state.
|
||||
// - Both succeeded → 'deleted' (clear all IDs + secrets)
|
||||
// - Either failed → 'failed' (keep IDs for reconciler retry)
|
||||
const now = new Date()
|
||||
if (dokployFailed || dnsFailed) {
|
||||
await db.instance.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'failed',
|
||||
lastError: `deletion partial: ${steps.join(', ')}`,
|
||||
lastErrorAt: now,
|
||||
// Keep dokployAppId + dnsRecordId so reconciler can retry.
|
||||
},
|
||||
})
|
||||
await db.instanceEvent.create({
|
||||
data: { instanceId: id, type: 'delete.partial', step: 'done', result: 'error', details: JSON.stringify({ steps, dokployFailed, dnsFailed }) },
|
||||
})
|
||||
await db.auditLog.create({
|
||||
data: {
|
||||
actor: 'admin:ui',
|
||||
action: 'instance.delete.partial',
|
||||
entity: 'Instance',
|
||||
entityId: id,
|
||||
after: JSON.stringify({ subdomain: instance.subdomain, steps, dokployFailed, dnsFailed, message: 'reconciler will retry' }),
|
||||
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||
},
|
||||
})
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 'failed',
|
||||
steps,
|
||||
message: 'Löschung teilweise fehlgeschlagen — Reconciler wird erneut versuchen. Dokploy + Hetzner A record birlikte silinmedi; orphaned resource riski için instance failed durumda.',
|
||||
}, { status: 500 })
|
||||
}
|
||||
|
||||
// 4. Both succeeded → mark deleted (keep row for audit — GoBD)
|
||||
await db.instance.update({
|
||||
where: { id },
|
||||
data: {
|
||||
@@ -226,7 +272,7 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
||||
},
|
||||
})
|
||||
|
||||
// 4. Unlink from license (keep license, just remove instance ref)
|
||||
// 5. Unlink from license (keep license, just remove instance ref)
|
||||
if (instance.licenseId) {
|
||||
await db.license.update({
|
||||
where: { id: instance.licenseId },
|
||||
|
||||
Reference in new issue
Block a user