123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764 |
- 'use strict';
- // @ts-check
- // ==================================================================================
- // docker.js
- // ----------------------------------------------------------------------------------
- // Description: System Information - library
- // for Node.js
- // Copyright: (c) 2014 - 2022
- // Author: Sebastian Hildebrandt
- // ----------------------------------------------------------------------------------
- // License: MIT
- // ==================================================================================
- // 13. Docker
- // ----------------------------------------------------------------------------------
- const util = require('./util');
- const DockerSocket = require('./dockerSocket');
- let _platform = process.platform;
- const _windows = (_platform === 'win32');
- let _docker_container_stats = {};
- let _docker_socket;
- let _docker_last_read = 0;
- // --------------------------
- // get containers (parameter all: get also inactive/exited containers)
- function dockerInfo(callback) {
- return new Promise((resolve) => {
- process.nextTick(() => {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- const result = {};
- _docker_socket.getInfo(data => {
- result.id = data.ID;
- result.containers = data.Containers;
- result.containersRunning = data.ContainersRunning;
- result.containersPaused = data.ContainersPaused;
- result.containersStopped = data.ContainersStopped;
- result.images = data.Images;
- result.driver = data.Driver;
- result.memoryLimit = data.MemoryLimit;
- result.swapLimit = data.SwapLimit;
- result.kernelMemory = data.KernelMemory;
- result.cpuCfsPeriod = data.CpuCfsPeriod;
- result.cpuCfsQuota = data.CpuCfsQuota;
- result.cpuShares = data.CPUShares;
- result.cpuSet = data.CPUSet;
- result.ipv4Forwarding = data.IPv4Forwarding;
- result.bridgeNfIptables = data.BridgeNfIptables;
- result.bridgeNfIp6tables = data.BridgeNfIp6tables;
- result.debug = data.Debug;
- result.nfd = data.NFd;
- result.oomKillDisable = data.OomKillDisable;
- result.ngoroutines = data.NGoroutines;
- result.systemTime = data.SystemTime;
- result.loggingDriver = data.LoggingDriver;
- result.cgroupDriver = data.CgroupDriver;
- result.nEventsListener = data.NEventsListener;
- result.kernelVersion = data.KernelVersion;
- result.operatingSystem = data.OperatingSystem;
- result.osType = data.OSType;
- result.architecture = data.Architecture;
- result.ncpu = data.NCPU;
- result.memTotal = data.MemTotal;
- result.dockerRootDir = data.DockerRootDir;
- result.httpProxy = data.HttpProxy;
- result.httpsProxy = data.HttpsProxy;
- result.noProxy = data.NoProxy;
- result.name = data.Name;
- result.labels = data.Labels;
- result.experimentalBuild = data.ExperimentalBuild;
- result.serverVersion = data.ServerVersion;
- result.clusterStore = data.ClusterStore;
- result.clusterAdvertise = data.ClusterAdvertise;
- result.defaultRuntime = data.DefaultRuntime;
- result.liveRestoreEnabled = data.LiveRestoreEnabled;
- result.isolation = data.Isolation;
- result.initBinary = data.InitBinary;
- result.productLicense = data.ProductLicense;
- if (callback) { callback(result); }
- resolve(result);
- });
- });
- });
- }
- exports.dockerInfo = dockerInfo;
- function dockerImages(all, callback) {
- // fallback - if only callback is given
- if (util.isFunction(all) && !callback) {
- callback = all;
- all = false;
- }
- if (typeof all === 'string' && all === 'true') {
- all = true;
- }
- if (typeof all !== 'boolean' && all !== undefined) {
- all = false;
- }
- all = all || false;
- let result = [];
- return new Promise((resolve) => {
- process.nextTick(() => {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- const workload = [];
- _docker_socket.listImages(all, data => {
- let dockerImages = {};
- try {
- dockerImages = data;
- if (dockerImages && Object.prototype.toString.call(dockerImages) === '[object Array]' && dockerImages.length > 0) {
- dockerImages.forEach(function (element) {
- if (element.Names && Object.prototype.toString.call(element.Names) === '[object Array]' && element.Names.length > 0) {
- element.Name = element.Names[0].replace(/^\/|\/$/g, '');
- }
- workload.push(dockerImagesInspect(element.Id.trim(), element));
- });
- if (workload.length) {
- Promise.all(
- workload
- ).then(data => {
- if (callback) { callback(data); }
- resolve(data);
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- } catch (err) {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- });
- });
- }
- // --------------------------
- // container inspect (for one container)
- function dockerImagesInspect(imageID, payload) {
- return new Promise((resolve) => {
- process.nextTick(() => {
- imageID = imageID || '';
- if (typeof imageID !== 'string') {
- return resolve();
- }
- const imageIDSanitized = (util.isPrototypePolluted() ? '' : util.sanitizeShellString(imageID, true)).trim();
- if (imageIDSanitized) {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- _docker_socket.inspectImage(imageIDSanitized.trim(), data => {
- try {
- resolve({
- id: payload.Id,
- container: data.Container,
- comment: data.Comment,
- os: data.Os,
- architecture: data.Architecture,
- parent: data.Parent,
- dockerVersion: data.DockerVersion,
- size: data.Size,
- sharedSize: payload.SharedSize,
- virtualSize: data.VirtualSize,
- author: data.Author,
- created: data.Created ? Math.round(new Date(data.Created).getTime() / 1000) : 0,
- containerConfig: data.ContainerConfig ? data.ContainerConfig : {},
- graphDriver: data.GraphDriver ? data.GraphDriver : {},
- repoDigests: data.RepoDigests ? data.RepoDigests : {},
- repoTags: data.RepoTags ? data.RepoTags : {},
- config: data.Config ? data.Config : {},
- rootFS: data.RootFS ? data.RootFS : {},
- });
- } catch (err) {
- resolve();
- }
- });
- } else {
- resolve();
- }
- });
- });
- }
- exports.dockerImages = dockerImages;
- function dockerContainers(all, callback) {
- function inContainers(containers, id) {
- let filtered = containers.filter(obj => {
- /**
- * @namespace
- * @property {string} Id
- */
- return (obj.Id && (obj.Id === id));
- });
- return (filtered.length > 0);
- }
- // fallback - if only callback is given
- if (util.isFunction(all) && !callback) {
- callback = all;
- all = false;
- }
- if (typeof all === 'string' && all === 'true') {
- all = true;
- }
- if (typeof all !== 'boolean' && all !== undefined) {
- all = false;
- }
- all = all || false;
- let result = [];
- return new Promise((resolve) => {
- process.nextTick(() => {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- const workload = [];
- _docker_socket.listContainers(all, data => {
- let docker_containers = {};
- try {
- docker_containers = data;
- if (docker_containers && Object.prototype.toString.call(docker_containers) === '[object Array]' && docker_containers.length > 0) {
- // GC in _docker_container_stats
- for (let key in _docker_container_stats) {
- if ({}.hasOwnProperty.call(_docker_container_stats, key)) {
- if (!inContainers(docker_containers, key)) { delete _docker_container_stats[key]; }
- }
- }
- docker_containers.forEach(function (element) {
- if (element.Names && Object.prototype.toString.call(element.Names) === '[object Array]' && element.Names.length > 0) {
- element.Name = element.Names[0].replace(/^\/|\/$/g, '');
- }
- workload.push(dockerContainerInspect(element.Id.trim(), element));
- // result.push({
- // id: element.Id,
- // name: element.Name,
- // image: element.Image,
- // imageID: element.ImageID,
- // command: element.Command,
- // created: element.Created,
- // state: element.State,
- // ports: element.Ports,
- // mounts: element.Mounts,
- // // hostconfig: element.HostConfig,
- // // network: element.NetworkSettings
- // });
- });
- if (workload.length) {
- Promise.all(
- workload
- ).then(data => {
- if (callback) { callback(data); }
- resolve(data);
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- } catch (err) {
- // GC in _docker_container_stats
- for (let key in _docker_container_stats) {
- if ({}.hasOwnProperty.call(_docker_container_stats, key)) {
- if (!inContainers(docker_containers, key)) { delete _docker_container_stats[key]; }
- }
- }
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- });
- });
- }
- // --------------------------
- // container inspect (for one container)
- function dockerContainerInspect(containerID, payload) {
- return new Promise((resolve) => {
- process.nextTick(() => {
- containerID = containerID || '';
- if (typeof containerID !== 'string') {
- return resolve();
- }
- const containerIdSanitized = (util.isPrototypePolluted() ? '' : util.sanitizeShellString(containerID, true)).trim();
- if (containerIdSanitized) {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- _docker_socket.getInspect(containerIdSanitized.trim(), data => {
- try {
- resolve({
- id: payload.Id,
- name: payload.Name,
- image: payload.Image,
- imageID: payload.ImageID,
- command: payload.Command,
- created: payload.Created,
- started: data.State && data.State.StartedAt ? Math.round(new Date(data.State.StartedAt).getTime() / 1000) : 0,
- finished: data.State && data.State.FinishedAt && !data.State.FinishedAt.startsWith('0001-01-01') ? Math.round(new Date(data.State.FinishedAt).getTime() / 1000) : 0,
- createdAt: data.Created ? data.Created : '',
- startedAt: data.State && data.State.StartedAt ? data.State.StartedAt : '',
- finishedAt: data.State && data.State.FinishedAt && !data.State.FinishedAt.startsWith('0001-01-01') ? data.State.FinishedAt : '',
- state: payload.State,
- restartCount: data.RestartCount || 0,
- platform: data.Platform || '',
- driver: data.Driver || '',
- ports: payload.Ports,
- mounts: payload.Mounts,
- // hostconfig: payload.HostConfig,
- // network: payload.NetworkSettings
- });
- } catch (err) {
- resolve();
- }
- });
- } else {
- resolve();
- }
- });
- });
- }
- exports.dockerContainers = dockerContainers;
- // --------------------------
- // helper functions for calculation of docker stats
- function docker_calcCPUPercent(cpu_stats, precpu_stats) {
- /**
- * @namespace
- * @property {object} cpu_usage
- * @property {number} cpu_usage.total_usage
- * @property {number} system_cpu_usage
- * @property {object} cpu_usage
- * @property {Array} cpu_usage.percpu_usage
- */
- if (!_windows) {
- let cpuPercent = 0.0;
- // calculate the change for the cpu usage of the container in between readings
- let cpuDelta = cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage;
- // calculate the change for the entire system between readings
- let systemDelta = cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage;
- if (systemDelta > 0.0 && cpuDelta > 0.0) {
- // calculate the change for the cpu usage of the container in between readings
- cpuPercent = (cpuDelta / systemDelta) * cpu_stats.cpu_usage.percpu_usage.length * 100.0;
- }
- return cpuPercent;
- } else {
- let nanoSecNow = util.nanoSeconds();
- let cpuPercent = 0.0;
- if (_docker_last_read > 0) {
- let possIntervals = (nanoSecNow - _docker_last_read); // / 100 * os.cpus().length;
- let intervalsUsed = cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage;
- if (possIntervals > 0) {
- cpuPercent = 100.0 * intervalsUsed / possIntervals;
- }
- }
- _docker_last_read = nanoSecNow;
- return cpuPercent;
- }
- }
- function docker_calcNetworkIO(networks) {
- let rx;
- let wx;
- for (let key in networks) {
- // skip loop if the property is from prototype
- if (!{}.hasOwnProperty.call(networks, key)) { continue; }
- /**
- * @namespace
- * @property {number} rx_bytes
- * @property {number} tx_bytes
- */
- let obj = networks[key];
- rx = +obj.rx_bytes;
- wx = +obj.tx_bytes;
- }
- return {
- rx,
- wx
- };
- }
- function docker_calcBlockIO(blkio_stats) {
- let result = {
- r: 0,
- w: 0
- };
- /**
- * @namespace
- * @property {Array} io_service_bytes_recursive
- */
- if (blkio_stats && blkio_stats.io_service_bytes_recursive && Object.prototype.toString.call(blkio_stats.io_service_bytes_recursive) === '[object Array]' && blkio_stats.io_service_bytes_recursive.length > 0) {
- blkio_stats.io_service_bytes_recursive.forEach(function (element) {
- /**
- * @namespace
- * @property {string} op
- * @property {number} value
- */
- if (element.op && element.op.toLowerCase() === 'read' && element.value) {
- result.r += element.value;
- }
- if (element.op && element.op.toLowerCase() === 'write' && element.value) {
- result.w += element.value;
- }
- });
- }
- return result;
- }
- function dockerContainerStats(containerIDs, callback) {
- let containerArray = [];
- return new Promise((resolve) => {
- process.nextTick(() => {
- // fallback - if only callback is given
- if (util.isFunction(containerIDs) && !callback) {
- callback = containerIDs;
- containerArray = ['*'];
- } else {
- containerIDs = containerIDs || '*';
- if (typeof containerIDs !== 'string') {
- if (callback) { callback([]); }
- return resolve([]);
- }
- let containerIDsSanitized = '';
- containerIDsSanitized.__proto__.toLowerCase = util.stringToLower;
- containerIDsSanitized.__proto__.replace = util.stringReplace;
- containerIDsSanitized.__proto__.trim = util.stringTrim;
- containerIDsSanitized = containerIDs;
- containerIDsSanitized = containerIDsSanitized.trim();
- if (containerIDsSanitized !== '*') {
- containerIDsSanitized = '';
- const s = (util.isPrototypePolluted() ? '' : util.sanitizeShellString(containerIDs, true)).trim();
- for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
- if (!(s[i] === undefined)) {
- s[i].__proto__.toLowerCase = util.stringToLower;
- const sl = s[i].toLowerCase();
- if (sl && sl[0] && !sl[1]) {
- containerIDsSanitized = containerIDsSanitized + sl[0];
- }
- }
- }
- }
- containerIDsSanitized = containerIDsSanitized.trim().toLowerCase().replace(/,+/g, '|');
- containerArray = containerIDsSanitized.split('|');
- }
- const result = [];
- const workload = [];
- if (containerArray.length && containerArray[0].trim() === '*') {
- containerArray = [];
- dockerContainers().then(allContainers => {
- for (let container of allContainers) {
- containerArray.push(container.id);
- }
- if (containerArray.length) {
- dockerContainerStats(containerArray.join(',')).then(result => {
- if (callback) { callback(result); }
- resolve(result);
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- } else {
- for (let containerID of containerArray) {
- workload.push(dockerContainerStatsSingle(containerID.trim()));
- }
- if (workload.length) {
- Promise.all(
- workload
- ).then(data => {
- if (callback) { callback(data); }
- resolve(data);
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- }
- });
- });
- }
- // --------------------------
- // container stats (for one container)
- function dockerContainerStatsSingle(containerID) {
- containerID = containerID || '';
- let result = {
- id: containerID,
- memUsage: 0,
- memLimit: 0,
- memPercent: 0,
- cpuPercent: 0,
- pids: 0,
- netIO: {
- rx: 0,
- wx: 0
- },
- blockIO: {
- r: 0,
- w: 0
- },
- restartCount: 0,
- cpuStats: {},
- precpuStats: {},
- memoryStats: {},
- networks: {},
- };
- return new Promise((resolve) => {
- process.nextTick(() => {
- if (containerID) {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- _docker_socket.getInspect(containerID, dataInspect => {
- try {
- _docker_socket.getStats(containerID, data => {
- try {
- let stats = data;
- if (!stats.message) {
- result.memUsage = (stats.memory_stats && stats.memory_stats.usage ? stats.memory_stats.usage : 0);
- result.memLimit = (stats.memory_stats && stats.memory_stats.limit ? stats.memory_stats.limit : 0);
- result.memPercent = (stats.memory_stats && stats.memory_stats.usage && stats.memory_stats.limit ? stats.memory_stats.usage / stats.memory_stats.limit * 100.0 : 0);
- result.cpuPercent = (stats.cpu_stats && stats.precpu_stats ? docker_calcCPUPercent(stats.cpu_stats, stats.precpu_stats) : 0);
- result.pids = (stats.pids_stats && stats.pids_stats.current ? stats.pids_stats.current : 0);
- result.restartCount = (dataInspect.RestartCount ? dataInspect.RestartCount : 0);
- if (stats.networks) { result.netIO = docker_calcNetworkIO(stats.networks); }
- if (stats.blkio_stats) { result.blockIO = docker_calcBlockIO(stats.blkio_stats); }
- result.cpuStats = (stats.cpu_stats ? stats.cpu_stats : {});
- result.precpuStats = (stats.precpu_stats ? stats.precpu_stats : {});
- result.memoryStats = (stats.memory_stats ? stats.memory_stats : {});
- result.networks = (stats.networks ? stats.networks : {});
- }
- } catch (err) {
- util.noop();
- }
- // }
- resolve(result);
- });
- } catch (err) {
- util.noop();
- }
- });
- } else {
- resolve(result);
- }
- });
- });
- }
- exports.dockerContainerStats = dockerContainerStats;
- // --------------------------
- // container processes (for one container)
- function dockerContainerProcesses(containerID, callback) {
- let result = [];
- return new Promise((resolve) => {
- process.nextTick(() => {
- containerID = containerID || '';
- if (typeof containerID !== 'string') {
- return resolve(result);
- }
- const containerIdSanitized = (util.isPrototypePolluted() ? '' : util.sanitizeShellString(containerID, true)).trim();
- if (containerIdSanitized) {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- _docker_socket.getProcesses(containerIdSanitized, data => {
- /**
- * @namespace
- * @property {Array} Titles
- * @property {Array} Processes
- **/
- try {
- if (data && data.Titles && data.Processes) {
- let titles = data.Titles.map(function (value) {
- return value.toUpperCase();
- });
- let pos_pid = titles.indexOf('PID');
- let pos_ppid = titles.indexOf('PPID');
- let pos_pgid = titles.indexOf('PGID');
- let pos_vsz = titles.indexOf('VSZ');
- let pos_time = titles.indexOf('TIME');
- let pos_elapsed = titles.indexOf('ELAPSED');
- let pos_ni = titles.indexOf('NI');
- let pos_ruser = titles.indexOf('RUSER');
- let pos_user = titles.indexOf('USER');
- let pos_rgroup = titles.indexOf('RGROUP');
- let pos_group = titles.indexOf('GROUP');
- let pos_stat = titles.indexOf('STAT');
- let pos_rss = titles.indexOf('RSS');
- let pos_command = titles.indexOf('COMMAND');
- data.Processes.forEach(process => {
- result.push({
- pidHost: (pos_pid >= 0 ? process[pos_pid] : ''),
- ppid: (pos_ppid >= 0 ? process[pos_ppid] : ''),
- pgid: (pos_pgid >= 0 ? process[pos_pgid] : ''),
- user: (pos_user >= 0 ? process[pos_user] : ''),
- ruser: (pos_ruser >= 0 ? process[pos_ruser] : ''),
- group: (pos_group >= 0 ? process[pos_group] : ''),
- rgroup: (pos_rgroup >= 0 ? process[pos_rgroup] : ''),
- stat: (pos_stat >= 0 ? process[pos_stat] : ''),
- time: (pos_time >= 0 ? process[pos_time] : ''),
- elapsed: (pos_elapsed >= 0 ? process[pos_elapsed] : ''),
- nice: (pos_ni >= 0 ? process[pos_ni] : ''),
- rss: (pos_rss >= 0 ? process[pos_rss] : ''),
- vsz: (pos_vsz >= 0 ? process[pos_vsz] : ''),
- command: (pos_command >= 0 ? process[pos_command] : '')
- });
- });
- }
- } catch (err) {
- util.noop();
- }
- if (callback) { callback(result); }
- resolve(result);
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- });
- }
- exports.dockerContainerProcesses = dockerContainerProcesses;
- function dockerVolumes(callback) {
- let result = [];
- return new Promise((resolve) => {
- process.nextTick(() => {
- if (!_docker_socket) {
- _docker_socket = new DockerSocket();
- }
- _docker_socket.listVolumes(data => {
- let dockerVolumes = {};
- try {
- dockerVolumes = data;
- if (dockerVolumes && dockerVolumes.Volumes && Object.prototype.toString.call(dockerVolumes.Volumes) === '[object Array]' && dockerVolumes.Volumes.length > 0) {
- dockerVolumes.Volumes.forEach(function (element) {
- result.push({
- name: element.Name,
- driver: element.Driver,
- labels: element.Labels,
- mountpoint: element.Mountpoint,
- options: element.Options,
- scope: element.Scope,
- created: element.CreatedAt ? Math.round(new Date(element.CreatedAt).getTime() / 1000) : 0,
- });
- });
- if (callback) { callback(result); }
- resolve(result);
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- } catch (err) {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- });
- });
- }
- exports.dockerVolumes = dockerVolumes;
- function dockerAll(callback) {
- return new Promise((resolve) => {
- process.nextTick(() => {
- dockerContainers(true).then(result => {
- if (result && Object.prototype.toString.call(result) === '[object Array]' && result.length > 0) {
- let l = result.length;
- result.forEach(function (element) {
- dockerContainerStats(element.id).then(res => {
- // include stats in array
- element.memUsage = res[0].memUsage;
- element.memLimit = res[0].memLimit;
- element.memPercent = res[0].memPercent;
- element.cpuPercent = res[0].cpuPercent;
- element.pids = res[0].pids;
- element.netIO = res[0].netIO;
- element.blockIO = res[0].blockIO;
- element.cpuStats = res[0].cpuStats;
- element.precpuStats = res[0].precpuStats;
- element.memoryStats = res[0].memoryStats;
- element.networks = res[0].networks;
- dockerContainerProcesses(element.id).then(processes => {
- element.processes = processes;
- l -= 1;
- if (l === 0) {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- // all done??
- });
- });
- } else {
- if (callback) { callback(result); }
- resolve(result);
- }
- });
- });
- });
- }
- exports.dockerAll = dockerAll;
|