forked from snxraven/peardock
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.
96 lines
3.3 KiB
JavaScript
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() })
|
|
}
|