test enhancements
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* Container configuration builder utilities
|
||||
* Extracted from deployContainer to improve modularity
|
||||
*/
|
||||
|
||||
import * as validation from './validation.js';
|
||||
|
||||
/**
|
||||
* Build basic container configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - Container configuration
|
||||
*/
|
||||
export function buildBasicConfig(args) {
|
||||
const containerConfig = {
|
||||
name: args.containerName,
|
||||
Image: args.image,
|
||||
};
|
||||
|
||||
// Basic settings
|
||||
if (args.command) {
|
||||
containerConfig.Cmd = args.command.split(' ');
|
||||
}
|
||||
if (args.entrypoint) {
|
||||
containerConfig.Entrypoint = args.entrypoint.split(' ');
|
||||
}
|
||||
if (args.workingDir) {
|
||||
containerConfig.WorkingDir = args.workingDir;
|
||||
}
|
||||
|
||||
return containerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build environment variables configuration
|
||||
* @param {Array} envVars - Environment variables array
|
||||
* @returns {Array} - Formatted environment variables
|
||||
*/
|
||||
export function buildEnvConfig(envVars) {
|
||||
if (!envVars || !Array.isArray(envVars)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return envVars
|
||||
.filter(e => e.name && e.value !== undefined)
|
||||
.map(e => {
|
||||
const name = validation.sanitizeEnvVarName(e.name);
|
||||
const value = validation.sanitizeEnvVarValue(e.value);
|
||||
return name && value !== null ? `${name}=${value}` : null;
|
||||
})
|
||||
.filter(e => e !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build labels configuration
|
||||
* @param {Object} labels - Labels object
|
||||
* @returns {Object} - Sanitized labels
|
||||
*/
|
||||
export function buildLabelsConfig(labels) {
|
||||
if (!labels || typeof labels !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
const sanitizedLabels = {};
|
||||
for (const [key, value] of Object.entries(labels)) {
|
||||
const sanitizedKey = validation.sanitizeLabelKey(key);
|
||||
const sanitizedValue = validation.sanitizeLabelValue(value);
|
||||
if (sanitizedKey && sanitizedValue !== null) {
|
||||
sanitizedLabels[sanitizedKey] = sanitizedValue;
|
||||
}
|
||||
}
|
||||
|
||||
return sanitizedLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build networking configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - HostConfig networking settings
|
||||
*/
|
||||
export function buildNetworkingConfig(args) {
|
||||
const hostConfig = {
|
||||
NetworkMode: args.networkMode || 'bridge',
|
||||
};
|
||||
|
||||
// Port bindings
|
||||
if (args.ports && Array.isArray(args.ports)) {
|
||||
hostConfig.PortBindings = {};
|
||||
args.ports.forEach((portStr) => {
|
||||
const sanitizedPort = validation.sanitizeString(portStr, 50);
|
||||
if (validation.isValidPortMapping(sanitizedPort)) {
|
||||
if (sanitizedPort.includes(':')) {
|
||||
const [hostPort, rest] = sanitizedPort.split(':');
|
||||
const [containerPort, protocol] = rest.split('/');
|
||||
hostConfig.PortBindings[`${containerPort}/${protocol || 'tcp'}`] = [{ HostPort: hostPort }];
|
||||
} else {
|
||||
const [containerPort, protocol] = sanitizedPort.split('/');
|
||||
hostConfig.PortBindings[`${containerPort}/${protocol || 'tcp'}`] = [{ HostPort: containerPort }];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DNS
|
||||
if (args.dns && Array.isArray(args.dns)) {
|
||||
hostConfig.Dns = args.dns
|
||||
.map(dns => validation.sanitizeString(dns, 50))
|
||||
.filter(dns => validation.isValidDnsServer(dns));
|
||||
}
|
||||
|
||||
// Extra hosts
|
||||
if (args.extraHosts && Array.isArray(args.extraHosts)) {
|
||||
hostConfig.ExtraHosts = args.extraHosts
|
||||
.map(host => validation.sanitizeString(host, 200))
|
||||
.filter(host => host.includes(':'));
|
||||
}
|
||||
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build volumes configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - HostConfig volumes settings
|
||||
*/
|
||||
export function buildVolumesConfig(args) {
|
||||
const hostConfig = {};
|
||||
|
||||
// Volumes
|
||||
if (args.volumes && Array.isArray(args.volumes)) {
|
||||
hostConfig.Binds = args.volumes
|
||||
.map(v => validation.sanitizeString(v, 500))
|
||||
.filter(v => v && validation.isValidVolumeMount(v));
|
||||
}
|
||||
|
||||
// Tmpfs
|
||||
if (args.tmpfs && Array.isArray(args.tmpfs)) {
|
||||
hostConfig.Tmpfs = {};
|
||||
args.tmpfs.forEach(tmpfsStr => {
|
||||
const sanitized = validation.sanitizeString(tmpfsStr, 100);
|
||||
const [path, ...opts] = sanitized.split(':');
|
||||
if (path) {
|
||||
hostConfig.Tmpfs[path] = opts.join(':') || '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build resources configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - HostConfig resources settings
|
||||
*/
|
||||
export function buildResourcesConfig(args) {
|
||||
const hostConfig = {};
|
||||
|
||||
// CPU limits
|
||||
if (args.cpuLimit) {
|
||||
hostConfig.NanoCpus = args.cpuLimit * 1000000000; // Convert to nanoseconds
|
||||
}
|
||||
if (args.cpuReservation) {
|
||||
hostConfig.CpuQuota = args.cpuReservation * 1000000000;
|
||||
}
|
||||
if (args.cpuShares) {
|
||||
hostConfig.CpuShares = args.cpuShares;
|
||||
}
|
||||
|
||||
// Memory limits
|
||||
if (args.memoryLimit) {
|
||||
hostConfig.Memory = args.memoryLimit * 1024 * 1024; // Convert MB to bytes
|
||||
}
|
||||
if (args.memoryReservation) {
|
||||
hostConfig.MemoryReservation = args.memoryReservation * 1024 * 1024;
|
||||
}
|
||||
if (args.memorySwap !== undefined && args.memorySwap !== null) {
|
||||
hostConfig.MemorySwap = args.memorySwap === -1 ? -1 : args.memorySwap * 1024 * 1024;
|
||||
}
|
||||
|
||||
// Devices
|
||||
if (args.devices && Array.isArray(args.devices)) {
|
||||
hostConfig.Devices = args.devices
|
||||
.map(deviceStr => validation.sanitizeString(deviceStr, 200))
|
||||
.map(deviceStr => {
|
||||
const parts = deviceStr.split(':');
|
||||
return {
|
||||
PathOnHost: parts[0],
|
||||
PathInContainer: parts[1] || parts[0],
|
||||
CgroupPermissions: parts[2] || 'rwm'
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build security configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - HostConfig security settings
|
||||
*/
|
||||
export function buildSecurityConfig(args) {
|
||||
const hostConfig = {};
|
||||
|
||||
// Privileged
|
||||
if (args.privileged === true) {
|
||||
hostConfig.Privileged = true;
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
if (args.capabilities && Array.isArray(args.capabilities)) {
|
||||
hostConfig.CapAdd = args.capabilities
|
||||
.map(cap => validation.sanitizeString(cap, 50).toUpperCase())
|
||||
.filter(cap => /^[A-Z_]+$/.test(cap));
|
||||
}
|
||||
|
||||
// Security options
|
||||
if (args.securityOpts && Array.isArray(args.securityOpts)) {
|
||||
hostConfig.SecurityOpt = args.securityOpts
|
||||
.map(opt => validation.sanitizeString(opt, 200));
|
||||
}
|
||||
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build runtime configuration
|
||||
* @param {Object} args - Deployment arguments
|
||||
* @returns {Object} - HostConfig runtime settings
|
||||
*/
|
||||
export function buildRuntimeConfig(args) {
|
||||
const hostConfig = {};
|
||||
|
||||
// Restart policy
|
||||
if (args.restartPolicy) {
|
||||
hostConfig.RestartPolicy = {
|
||||
Name: args.restartPolicy,
|
||||
MaximumRetryCount: args.restartMaxRetries || 0
|
||||
};
|
||||
}
|
||||
|
||||
// Auto remove
|
||||
if (args.autoRemove === true) {
|
||||
hostConfig.AutoRemove = true;
|
||||
}
|
||||
|
||||
// Init process
|
||||
if (args.init === true) {
|
||||
hostConfig.Init = true;
|
||||
}
|
||||
|
||||
// Sysctls
|
||||
if (args.sysctls && typeof args.sysctls === 'object') {
|
||||
hostConfig.Sysctls = {};
|
||||
for (const [key, value] of Object.entries(args.sysctls)) {
|
||||
const sanitizedKey = validation.sanitizeString(key, 100);
|
||||
const sanitizedValue = validation.sanitizeString(String(value), 100);
|
||||
if (sanitizedKey && sanitizedValue) {
|
||||
hostConfig.Sysctls[sanitizedKey] = sanitizedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ulimits
|
||||
if (args.ulimits && Array.isArray(args.ulimits)) {
|
||||
hostConfig.Ulimits = args.ulimits
|
||||
.map(ulimit => {
|
||||
if (typeof ulimit === 'object' && ulimit.Name) {
|
||||
return {
|
||||
Name: validation.sanitizeString(ulimit.Name, 50),
|
||||
Soft: validation.validateNumber(ulimit.Soft, 0, Infinity),
|
||||
Hard: validation.validateNumber(ulimit.Hard, 0, Infinity)
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(ulimit => ulimit !== null);
|
||||
}
|
||||
|
||||
// OOM kill disable
|
||||
if (args.oomKillDisable === true) {
|
||||
hostConfig.OomKillDisable = true;
|
||||
}
|
||||
|
||||
// PIDs limit
|
||||
if (args.pidsLimit !== undefined && args.pidsLimit !== null) {
|
||||
hostConfig.PidsLimit = args.pidsLimit === -1 ? 0 : args.pidsLimit;
|
||||
}
|
||||
|
||||
// Shared memory size
|
||||
if (args.shmSize) {
|
||||
hostConfig.ShmSize = args.shmSize * 1024 * 1024; // Convert MB to bytes
|
||||
}
|
||||
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user