more progress

This commit is contained in:
Raven Scott
2024-12-02 03:29:59 -05:00
parent 2839fd7a7d
commit 71992f004c
5 changed files with 442 additions and 280 deletions

View File

@ -225,104 +225,118 @@ swarm.on('connection', (peer) => {
response = { success: true, message: `Container ${parsedData.args.id} removed` };
break;
case 'deployContainer':
console.log('[INFO] Handling "deployContainer" command');
const { image: imageToDeploy, ports = [], volumes = [], env = [] } = parsedData.args;
try {
// Validate and sanitize image
if (!imageToDeploy || typeof imageToDeploy !== 'string') {
throw new Error('Invalid or missing Docker image.');
case 'deployContainer':
console.log('[INFO] Handling "deployContainer" command');
const { containerName, image: imageToDeploy, ports = [], volumes = [], env = [] } = parsedData.args;
try {
// Validate and sanitize container name
if (!containerName || typeof containerName !== 'string') {
throw new Error('Invalid or missing container name.');
}
// Ensure the name is alphanumeric with optional dashes/underscores
if (!/^[a-zA-Z0-9-_]+$/.test(containerName)) {
throw new Error('Container name must be alphanumeric and may include dashes or underscores.');
}
// Validate and sanitize image
if (!imageToDeploy || typeof imageToDeploy !== 'string') {
throw new Error('Invalid or missing Docker image.');
}
// Validate and sanitize ports
const validPorts = ports.filter((port) => {
if (typeof port === 'string' && /^\d+\/(tcp|udp)$/.test(port)) {
return true;
} else {
console.warn(`[WARN] Invalid port entry skipped: ${port}`);
return false;
}
});
// Validate and sanitize volumes
const validVolumes = volumes.filter((volume) => {
if (typeof volume === 'string' && volume.includes(':')) {
return true;
} else {
console.warn(`[WARN] Invalid volume entry skipped: ${volume}`);
return false;
}
});
// Validate and sanitize environment variables
const validEnv = env
.map(({ name, value }) => {
if (name && value) {
return `${name}=${value}`;
} else {
console.warn(`[WARN] Invalid environment variable skipped: name=${name}, value=${value}`);
return null;
}
})
.filter(Boolean);
console.log(`[INFO] Pulling Docker image "${imageToDeploy}"`);
// Pull the Docker image
const pullStream = await docker.pull(imageToDeploy);
await new Promise((resolve, reject) => {
docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve()));
});
console.log(`[INFO] Image "${imageToDeploy}" pulled successfully`);
// Configure container creation settings
const hostConfig = {
PortBindings: {},
Binds: validVolumes, // Use validated volumes in Docker's expected format
NetworkMode: 'bridge', // Set the network mode to bridge
};
validPorts.forEach((port) => {
const [containerPort, protocol] = port.split('/');
hostConfig.PortBindings[`${containerPort}/${protocol}`] = [{ HostPort: containerPort }];
});
// Create and start the container with a custom name
console.log('[INFO] Creating the container...');
const container = await docker.createContainer({
name: containerName, // Include the container name
Image: imageToDeploy,
Env: validEnv,
HostConfig: hostConfig,
});
console.log('[INFO] Starting the container...');
await container.start();
console.log(`[INFO] Container "${containerName}" deployed successfully from image "${imageToDeploy}"`);
// Respond with success message
peer.write(
JSON.stringify({
success: true,
message: `Container "${containerName}" deployed successfully from image "${imageToDeploy}"`,
})
);
// Update all peers with the latest container list
const containers = await docker.listContainers({ all: true });
const update = { type: 'containers', data: containers };
for (const connectedPeer of connectedPeers) {
connectedPeer.write(JSON.stringify(update));
}
} catch (err) {
console.error(`[ERROR] Failed to deploy container: ${err.message}`);
peer.write(
JSON.stringify({
error: `Failed to deploy container: ${err.message}`,
})
);
}
// Validate and sanitize ports
const validPorts = ports.filter((port) => {
if (typeof port === 'string' && /^\d+\/(tcp|udp)$/.test(port)) {
return true;
} else {
console.warn(`[WARN] Invalid port entry skipped: ${port}`);
return false;
}
});
// Validate and sanitize volumes
const validVolumes = volumes.filter((volume) => {
if (typeof volume === 'string' && volume.includes(':')) {
return true;
} else {
console.warn(`[WARN] Invalid volume entry skipped: ${volume}`);
return false;
}
});
// Validate and sanitize environment variables
const validEnv = env.map(({ name, value }) => {
if (name && value) {
return `${name}=${value}`;
} else {
console.warn(`[WARN] Invalid environment variable skipped: name=${name}, value=${value}`);
return null;
}
}).filter(Boolean);
console.log(`[INFO] Pulling Docker image "${imageToDeploy}"`);
// Pull the Docker image
const pullStream = await docker.pull(imageToDeploy);
await new Promise((resolve, reject) => {
docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve()));
});
console.log(`[INFO] Image "${imageToDeploy}" pulled successfully`);
// Configure container creation settings
const hostConfig = {
PortBindings: {},
Binds: validVolumes, // Use validated volumes in Docker's expected format
NetworkMode: 'bridge', // Set the network mode to bridge
};
validPorts.forEach((port) => {
const [containerPort, protocol] = port.split('/');
hostConfig.PortBindings[`${containerPort}/${protocol}`] = [{ HostPort: containerPort }];
});
// Create and start the container
console.log('[INFO] Creating the container...');
const container = await docker.createContainer({
Image: imageToDeploy,
Env: validEnv,
HostConfig: hostConfig,
});
console.log('[INFO] Starting the container...');
await container.start();
console.log(`[INFO] Container deployed successfully from image "${imageToDeploy}"`);
// Respond with success message
peer.write(
JSON.stringify({
success: true,
message: `Container deployed successfully from image "${imageToDeploy}"`,
})
);
// Update all peers with the latest container list
const containers = await docker.listContainers({ all: true });
const update = { type: 'containers', data: containers };
for (const connectedPeer of connectedPeers) {
connectedPeer.write(JSON.stringify(update));
}
} catch (err) {
console.error(`[ERROR] Failed to deploy container: ${err.message}`);
peer.write(
JSON.stringify({
error: `Failed to deploy container: ${err.message}`,
})
);
}
break;
break;
case 'startTerminal':