Files
peardock/server/handlers/networks.js
T
snxraven 53c8040020 Ship Track B UI: smart defaults, ops shell, deploy stepper
Add host snapshot and network IPAM suggestions, image-driven form
hydration, command palette, Host/Events/Settings views, offline banner,
job drawer for deploy steps, and typed RPC errors. Mark roadmap complete.
2026-07-10 21:17:04 -04:00

113 lines
3.7 KiB
JavaScript

/**
* Network RPC handlers.
*/
import { docker } from '../services/docker.js'
import * as validation from '../utils/validation.js'
export function registerNetworkHandlers(session) {
session.respond('listNetworks', async () => {
const networks = await docker.listNetworks()
const containers = await docker.listContainers({ all: true })
const networkUsage = {}
for (const container of containers) {
const nets = container.NetworkSettings?.Networks
if (!nets) continue
for (const networkName of Object.keys(nets)) {
if (!networkUsage[networkName]) networkUsage[networkName] = []
networkUsage[networkName].push({
id: container.Id,
name: container.Names[0]?.replace(/^\//, '') || container.Id.substring(0, 12),
state: container.State,
})
}
}
return {
type: 'networks',
data: networks.map((network) => ({
...network,
usage: networkUsage[network.Name] || [],
})),
}
})
session.respond('createNetwork', async (args) => {
const name = validation.sanitizeString(args.name, 128)
if (!name) throw new Error('Network name required')
const networkConfig = {
Name: name,
Driver: args.driver || 'bridge',
CheckDuplicate: true,
Internal: Boolean(args.internal),
Attachable: args.attachable !== false,
EnableIPv6: Boolean(args.enableIPv6 || args.ipv6),
Labels: args.labels && typeof args.labels === 'object' ? args.labels : undefined,
}
// Auto-fill IPAM when client asks (or subnet provided)
let subnet = args.subnet
let gateway = args.gateway
if ((!subnet || args.autoIPAM) && networkConfig.Driver === 'bridge') {
const { suggestNetworkIPAM } = await import('../utils/suggestions.js')
const sug = await suggestNetworkIPAM()
if (!subnet && sug.subnet) {
subnet = sug.subnet
gateway = gateway || sug.gateway
}
}
if (subnet || gateway || args.ipRange) {
networkConfig.IPAM = {
Config: [
{
...(subnet ? { Subnet: subnet } : {}),
...(gateway ? { Gateway: gateway } : {}),
...(args.ipRange ? { IPRange: args.ipRange } : {}),
},
],
}
}
if (args.options && typeof args.options === 'object') {
networkConfig.Options = args.options
}
const network = await docker.createNetwork(networkConfig)
return {
success: true,
message: `Network "${name}" created successfully`,
data: network.id,
applied: { name, driver: networkConfig.Driver, subnet, gateway },
}
})
session.respond('removeNetwork', async (args) => {
await docker.getNetwork(args.id).remove()
return { success: true, message: `Network ${args.id} removed` }
})
session.respond('inspectNetwork', async (args) => {
const networkData = await docker.getNetwork(args.id).inspect()
return { type: 'networkConfig', data: networkData }
})
session.respond('connectNetwork', async (args) => {
await docker.getNetwork(args.networkId).connect({ Container: args.containerId })
return { success: true, message: 'Container connected to network' }
})
session.respond('disconnectNetwork', async (args) => {
await docker
.getNetwork(args.networkId)
.disconnect({ Container: args.containerId, Force: args.force || false })
return { success: true, message: 'Container disconnected from network' }
})
session.respond('pruneNetworks', async (args) => {
const opts = {}
if (args.filters) opts.filters = args.filters
const result = await docker.pruneNetworks(opts)
return {
success: true,
type: 'pruneNetworks',
message: 'Unused networks pruned',
data: result,
}
})
}