Files
peardock/server/handlers/stacks.js
T
snxraven 0ee9b67834 Complete production roadmap: vault, peers, swarm, streams, ops
Ship remaining roadmap items: encrypted registry vault, peer invite/revoke,
Swarm/plugins behind flags, binary streams, engine create validation, deploy
rollback, schema validation, fleet/access UI, metrics, fuzz/load/soak tests,
systemd packaging, and release tooling. Mark ROADMAP fully complete.
2026-07-10 20:50:55 -04:00

74 lines
2.5 KiB
JavaScript

/**
* Docker Compose stack RPC handlers.
*/
import * as composeManager from '../utils/composeManager.js'
import * as validation from '../utils/validation.js'
import { docker } from '../services/docker.js'
import { broadcastContainers } from './containers.js'
export function registerStackHandlers(session) {
session.respond('deployStack', async (args) => {
const { composeContent, stackName } = args
if (!composeContent || !stackName) {
throw new Error('Compose content and stack name required')
}
const sanitizedStackName = validation.sanitizeString(stackName, 63)
if (!validation.isValidContainerName(sanitizedStackName)) {
throw new Error('Invalid stack name')
}
// Validate YAML early for clear errors
composeManager.validateComposeFile(composeContent)
const profiles = Array.isArray(args.profiles)
? args.profiles.map(String)
: typeof args.profiles === 'string'
? args.profiles.split(',').map((s) => s.trim()).filter(Boolean)
: []
const result = await composeManager.deployComposeStack(
docker,
composeContent,
sanitizedStackName,
{
overrideContent: args.overrideContent || args.override || null,
envFileContent: args.envFileContent || args.envFile || null,
profiles,
env: args.env && typeof args.env === 'object' ? args.env : {},
build: Boolean(args.build),
// Default true: tear down containers created in a failed partial deploy
rollback: args.rollback !== false,
}
)
await broadcastContainers()
return { success: true, ...result }
})
session.respond('listStacks', async () => {
const stacks = await composeManager.listStacks(docker)
return { type: 'stacks', data: stacks }
})
session.respond('removeStack', async (args) => {
const result = await composeManager.removeComposeStack(docker, args.stackName)
await broadcastContainers()
return { success: true, ...result }
})
session.respond('stackPs', async (args) => {
if (!args.stackName) throw new Error('stackName required')
return composeManager.stackPs(docker, args.stackName)
})
session.respond('stackLogs', async (args) => {
if (!args.stackName) throw new Error('stackName required')
return composeManager.stackLogs(docker, args.stackName, {
tail: args.tail,
})
})
session.respond('stackPull', async (args) => {
if (!args.stackName) throw new Error('stackName required')
return composeManager.stackPull(docker, args.stackName, {
composeContent: args.composeContent,
})
})
}