install: preflight + teardown tooling + CCP tunnel cleanup on delete
Fixes surfaced by three rounds of fresh-install testing on marcelle: - config.sh: add host-port preflight check (ss -tln) to catch cockpit-on-9090 style collisions before compose up; add --skip-port-check escape hatch; add --install-watcher / --no-install-watcher / --install-backup-timer / --no-install-backup-timer flags; -y --enable-all now installs both systemd units by default (previously silently skipped); print resolved admin email in Configuration Complete block. - scripts/validate-env.sh: new section 5b "Host Port Availability" using ss-based detection, with process-name surfacing when run as root. - scripts/pangolin-teardown.sh: new wrapper. Reads credentials from .env or takes --api-url/--api-key/--org-id flags. Dry-run by default; --yes to execute. Deletes resources before sites (avoids orphans). --keep-site-ids for safety. - scripts/build-release.sh: include validate-env.sh and pangolin-teardown.sh in release tarball whitelist. - CCP instances.service.ts: deleteInstance() now calls teardownTunnel() before composeDown when pangolinSiteId is set. Previously an admin clicking "Delete Instance" orphaned the Pangolin site + all its resources. Best-effort with try/catch matching the existing Docker-cleanup tolerance pattern. - CLAUDE.md: sync drift — 44 → 50 migrations, 186 → 192 models, 40 → 44 modules. Bunker Admin
This commit is contained in:
@@ -12,6 +12,7 @@ import { getDriverForInstance, AgentUnreachableError } from '../../services/exec
|
||||
import { provision } from './provisioner';
|
||||
import { CreateInstanceInput, UpdateInstanceInput, RegisterInstanceInput, ReconfigureInstanceInput, ConfigureTunnelInput } from './instances.schemas';
|
||||
import { buildTemplateContext, renderAllTemplates, clearTemplateCache } from '../../services/template-engine';
|
||||
import { teardownTunnel } from '../../services/tunnel.service';
|
||||
import { logger } from '../../utils/logger';
|
||||
import path from 'path';
|
||||
|
||||
@@ -283,6 +284,18 @@ export async function deleteInstance(id: string, userId: string, ipAddress?: str
|
||||
data: { status: InstanceStatus.DESTROYING, statusMessage: 'Shutting down containers...' },
|
||||
});
|
||||
|
||||
// Tear down Pangolin site + resources first. If we crashed after composeDown
|
||||
// but before this, the Pangolin entities would leak for the lifetime of the org.
|
||||
// Best effort — matches the Docker-cleanup tolerance below.
|
||||
if (instance.pangolinSiteId) {
|
||||
try {
|
||||
await teardownTunnel(id, userId, ipAddress ?? null);
|
||||
logger.info(`[instances] ${instance.slug}: Pangolin tunnel torn down`);
|
||||
} catch (err) {
|
||||
logger.warn(`[instances] ${instance.slug}: Pangolin teardown warning: ${(err as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop containers and remove volumes
|
||||
try {
|
||||
const driver = await getDriverForInstance(instance);
|
||||
|
||||
Reference in New Issue
Block a user