Files
peardock/server/handlers/plugins.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

96 lines
3.3 KiB
JavaScript

/**
* Docker plugin handlers.
* Gated by ENABLE_PLUGINS=1 (or true).
*/
import { docker } from '../services/docker.js'
import * as validation from '../utils/validation.js'
import logger from '../utils/logger.js'
export function isPluginsEnabled() {
return process.env.ENABLE_PLUGINS === '1' || process.env.ENABLE_PLUGINS === 'true'
}
function assertPlugins() {
if (!isPluginsEnabled()) {
const err = new Error('Plugin APIs disabled. Set ENABLE_PLUGINS=1 to enable.')
err.code = 'FEATURE_DISABLED'
throw err
}
}
export function registerPluginHandlers(session) {
session.respond('listPlugins', async () => {
assertPlugins()
const data = await docker.listPlugins()
return { success: true, type: 'plugins', data }
})
session.respond('inspectPlugin', async (args) => {
assertPlugins()
const data = await docker.getPlugin(args.name || args.id).inspect()
return { success: true, type: 'plugin', data }
})
session.respond('installPlugin', async (args) => {
assertPlugins()
const name = validation.sanitizeString(args.name || args.remote, 255)
if (!name) throw new Error('Plugin name/remote required')
const opts = {}
if (args.alias) opts.name = validation.sanitizeString(args.alias, 128)
// dockerode: docker.pullPlugin or getPlugin().enable after install
let plugin
if (typeof docker.pullPlugin === 'function') {
plugin = await docker.pullPlugin(name, opts)
} else {
plugin = await new Promise((resolve, reject) => {
docker.modem.dial(
{
path: `/plugins/pull?remote=${encodeURIComponent(name)}`,
method: 'POST',
statusCodes: { 200: true, 500: 'fatal' },
isStream: true,
},
(err, stream) => {
if (err) return reject(err)
docker.modem.followProgress(stream, (e, res) => (e ? reject(e) : resolve(res || { name })))
}
)
})
}
return { success: true, message: `Plugin ${name} installed`, data: plugin }
})
session.respond('enablePlugin', async (args) => {
assertPlugins()
const name = args.name || args.id
const timeout = args.timeout != null ? Number(args.timeout) : undefined
await docker.getPlugin(name).enable(timeout != null ? { timeout } : {})
return { success: true, message: `Plugin ${name} enabled` }
})
session.respond('disablePlugin', async (args) => {
assertPlugins()
const name = args.name || args.id
await docker.getPlugin(name).disable({ force: Boolean(args.force) })
return { success: true, message: `Plugin ${name} disabled` }
})
session.respond('removePlugin', async (args) => {
assertPlugins()
const name = args.name || args.id
await docker.getPlugin(name).remove({ force: Boolean(args.force) })
return { success: true, message: `Plugin ${name} removed` }
})
session.respond('configurePlugin', async (args) => {
assertPlugins()
const name = args.name || args.id
const config = args.config || args.Config || []
if (!Array.isArray(config)) throw new Error('config must be an array of KEY=VALUE strings')
await docker.getPlugin(name).configure({ args: config })
return { success: true, message: `Plugin ${name} configured` }
})
logger.debug('Plugin handlers registered', { enabled: isPluginsEnabled() })
}