feat(pilot): make Docker Compose the canonical pilot enrollment payload (#1121)

* feat(pilot): make Docker Compose the canonical pilot enrollment payload

The Add Node dialog for a pilot-agent now returns a Compose snippet
instead of a single-line docker run command, and the enrollment dialog
walks the operator through a save-and-up flow. The compose project name
and container name align with what SelfUpdateService looks up at boot,
so a Compose-deployed pilot can be updated remotely through the Fleet
view without intervention on the remote host.

Docs (pilot-agent, remote-updates) were rewritten to match.

* test(e2e): align pilot enrollment spec with Compose payload

The spec was written against the docker-run payload; it now asserts the
Compose YAML the dialog renders.
This commit is contained in:
Anso
2026-05-20 02:05:21 -04:00
committed by GitHub
parent 0117556bea
commit 3ad6ea9c5d
6 changed files with 190 additions and 74 deletions
+25 -11
View File
@@ -22,7 +22,7 @@ import { getErrorMessage } from '../utils/errors';
const NODE_SCOPE_MESSAGE = 'API tokens cannot manage nodes.';
const REMOTE_META_CACHE_TTL = 3 * 60 * 1000;
function mintPilotEnrollment(nodeId: number, req: Request): { token: string; expiresAt: number; dockerRun: string } {
function mintPilotEnrollment(nodeId: number, req: Request): { token: string; expiresAt: number; composeYaml: string } {
const db = DatabaseService.getInstance();
const jwtSecret = db.getGlobalSettings().auth_jwt_secret;
if (!jwtSecret) throw new Error('JWT secret not configured');
@@ -44,17 +44,31 @@ function mintPilotEnrollment(nodeId: number, req: Request): { token: string; exp
const host = req.get('host') || 'localhost:1852';
const primaryUrl = `${protocol}://${host}`;
const dockerRun =
`docker run -d --restart=unless-stopped --name sencho-agent ` +
`-v /var/run/docker.sock:/var/run/docker.sock ` +
`-v sencho-agent-data:/app/data ` +
`-v /opt/docker/sencho:/app/compose ` +
`-e SENCHO_MODE=pilot ` +
`-e SENCHO_PRIMARY_URL=${primaryUrl} ` +
`-e SENCHO_ENROLL_TOKEN=${token} ` +
`saelix/sencho:latest`;
// Top-level `name` plus `container_name` make the agent container's HOSTNAME
// equal to `sencho-agent`, which is how SelfUpdateService locates its own
// compose context to enable remote self-update.
const composeYaml = [
`name: sencho-agent`,
`services:`,
` agent:`,
` image: saelix/sencho:latest`,
` container_name: sencho-agent`,
` restart: unless-stopped`,
` volumes:`,
` - /var/run/docker.sock:/var/run/docker.sock`,
` - sencho-agent-data:/app/data`,
` - /opt/docker/sencho:/app/compose`,
` environment:`,
` SENCHO_MODE: pilot`,
` SENCHO_PRIMARY_URL: ${primaryUrl}`,
` SENCHO_ENROLL_TOKEN: ${token}`,
``,
`volumes:`,
` sencho-agent-data:`,
``,
].join('\n');
return { token, expiresAt, dockerRun };
return { token, expiresAt, composeYaml };
}
export const nodesRouter = Router();