UNPKG

firmament-docker

Version:

Typescript classes for performing Docker operations

872 lines (863 loc) 41.1 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); var DockerProvisionImpl_1; const inversify_1 = require("inversify"); const firmament_yargs_1 = require("firmament-yargs"); const async = require("async"); const fs = require("fs"); const YAML = require("yamljs"); const path = require("path"); const tmp = require("tmp"); const mkdirp = require("mkdirp"); const touch = require("touch"); const fileExists = require('file-exists'); let DockerProvisionImpl = DockerProvisionImpl_1 = class DockerProvisionImpl extends firmament_yargs_1.ForceErrorImpl { constructor(commandUtil, spawn, safeJson, remoteCatalogGetter, processCommandJson, dockerUtil, dockerImageManagement, dockerContainerManagement, positive, progressBar) { super(); this.commandUtil = commandUtil; this.spawn = spawn; this.safeJson = safeJson; this.remoteCatalogGetter = remoteCatalogGetter; this.processCommandJson = processCommandJson; this.dockerUtil = dockerUtil; this.dockerImageManagement = dockerImageManagement; this.dockerContainerManagement = dockerContainerManagement; this.positive = positive; this.progressBar = progressBar; this.writeScripts = false; } validateDockerStackConfigTemplate(argv, dockerStackConfigTemplate, cb) { const me = this; const dsct = dockerStackConfigTemplate; const dockerImageRegex = /.+?(:\d+?)?\/.+?:.+$/g; const dockerVolumesRegex = /:\//g; Object.assign(dsct.dockerMachineDriverOptions, dsct.dockerMachines.common); delete dsct.dockerMachines.common; const manager = dsct.dockerMachines.manager; manager.engineLabels = manager.engineLabels || { role: 'manager', affinity: manager.nodeName }; manager.engineLabels.role = manager.engineLabels.role || 'manager'; manager.engineLabels.affinity = manager.engineLabels.affinity || manager.nodeName; dsct.dockerMachines.workers = dsct.dockerMachines.workers || []; dsct.dockerMachines.workers.forEach((worker) => { worker.engineLabels = worker.engineLabels || { role: 'worker', affinity: worker.nodeName }; worker.engineLabels.role = worker.engineLabels.role || 'worker'; worker.engineLabels.affinity = worker.engineLabels.affinity || worker.nodeName; }); dsct.nfsConfig = dsct.nfsConfig || { nfsUser: undefined, nfsPassword: undefined, nfsSshKeyPath: undefined, nfsSshPort: 22, exportBaseDir: undefined, serverAddr: undefined, options: undefined }; dsct.nfsConfig.nfsUser = dsct.nfsConfig.nfsUser || undefined; dsct.nfsConfig.nfsPassword = dsct.nfsConfig.nfsPassword || undefined; dsct.nfsConfig.nfsSshKeyPath = dsct.nfsConfig.nfsSshKeyPath || undefined; dsct.nfsConfig.nfsSshPort = dsct.nfsConfig.nfsSshPort || undefined; dsct.nfsConfig.exportBaseDir = dsct.nfsConfig.exportBaseDir || undefined; dsct.nfsConfig.serverAddr = dsct.nfsConfig.serverAddr || undefined; dsct.nfsConfig.options = dsct.nfsConfig.options || undefined; dsct.dockerComposeYaml.volumes = dsct.dockerComposeYaml.volumes || {}; for (const volume in dsct.dockerComposeYaml.volumes) { const v = dsct.dockerComposeYaml.volumes[volume]; if (v.driver_opts && v.driver_opts.type === 'nfs' && v.driver === 'local') { v.driver_opts.device = v.driver_opts.device || volume; dockerVolumesRegex.lastIndex = 0; if (!dockerVolumesRegex.test(v.driver_opts.device)) { if (!dsct.nfsConfig) { return cb(new Error(`'${volume}.driver_opts.device' does not begin with ':/' but no 'nfsConfig' is specified`)); } if (!dsct.nfsConfig.exportBaseDir) { return cb(new Error(`'${volume}.driver_opts.device' does not begin with ':/' but no 'nfsConfig.exportBaseDir' is specified`)); } v.driver_opts.device = `:${dsct.nfsConfig.exportBaseDir}/${v.driver_opts.device}`; } if (!v.driver_opts.o) { if (!dsct.nfsConfig) { return cb(new Error(`'${volume}.driver_opts.o' does not exist but no 'nfsConfig' is specified`)); } if (!dsct.nfsConfig.serverAddr) { return cb(new Error(`'${volume}.driver_opts.o' does not exist but no 'nfsConfig.serverAddr' is specified`)); } if (!dsct.nfsConfig.options) { return cb(new Error(`'${volume}.driver_opts.o' does not exist but no 'nfsConfig.options' is specified`)); } v.driver_opts.o = dsct.nfsConfig.options; } const optionsHash = DockerProvisionImpl_1.optionsStringToHash(v.driver_opts.o); if (!optionsHash['addr'] && !dsct.nfsConfig.serverAddr) { return cb(new Error(`'${volume}.driver_opts.o[addr=]' does not exist but no 'nfsConfig.serverAddr' is specified`)); } optionsHash['addr'] = optionsHash['addr'] || dsct.nfsConfig.serverAddr; v.driver_opts.o = DockerProvisionImpl_1.optionsHashToString(optionsHash); } } for (const service in dsct.dockerComposeYaml.services) { const s = dsct.dockerComposeYaml.services[service]; dockerImageRegex.lastIndex = 0; if (!dockerImageRegex.test(s.image)) { if (!dsct.defaultDockerRegistry) { return cb(new Error(`Service '${service}' missing 'image' property and 'defaultDockerRegistry' is undefined`)); } if (!dsct.defaultDockerImageTag) { return cb(new Error(`Service '${service}' missing 'image' property and 'defaultDockerImageTag' is undefined`)); } if (s.image) { if (/.+?:\d+?/.test(s.image)) { s.image = `${dsct.defaultDockerRegistry}/${s.image}`; } else { s.image = `${dsct.defaultDockerRegistry}/${s.image}:${dsct.defaultDockerImageTag}`; } } else { s.image = `${dsct.defaultDockerRegistry}/${service}:${dsct.defaultDockerImageTag}`; } } const labels = {}; if (s.deploy.labels) { let traefikPortLabelPresent = 0; let frontendRuleLabelPresent = 0; const portRegex = /traefik\.(.*?\.|)port/g; const frontendRuleRegex = /traefik\.(.*?\.|)frontend.rule/g; s.deploy.labels.forEach((label) => { const tuple = label.split('='); portRegex.lastIndex = frontendRuleRegex.lastIndex = 0; if (portRegex.test(tuple[0])) { ++traefikPortLabelPresent; } if (frontendRuleRegex.test(tuple[0])) { ++frontendRuleLabelPresent; } labels[tuple[0]] = tuple[1]; }); if (labels['traefik.enable'] !== 'false') { if (!traefikPortLabelPresent) { return cb(new Error(`'traefik.??.port' label not present for service '${service}'`)); } if (!labels['traefik.backend'] && frontendRuleLabelPresent === 1) { labels['traefik.backend'] = service; } if (!frontendRuleLabelPresent) { if (!dsct.traefikZoneName) { return cb(new Error(`'traefik.??.frontend.rule' label and 'traefikZoneName' both undefined for service '${service}'`)); } labels['traefik.frontend.rule'] = `Host: ${service}.${dsct.traefikZoneName}`; } } s.deploy.labels.length = 0; for (const label in labels) { s.deploy.labels.push(`${label}=${labels[label]}`); } } } this.dockerUtil.writeJsonTemplateFile(dsct, '/tmp/tmp.json'); if (argv.noNfs) { return cb(null, dsct); } me.checkNfsMounts(dsct, (err, dsct) => { me.commandUtil.processExitIfError(err); cb(null, dsct); }); } checkNfsMounts(dsct, cb) { const me = this; const localSpawnOptions = { suppressStdOut: false, suppressStdErr: false, cacheStdOut: true, cacheStdErr: true, suppressResult: false }; const remoteSpawnOptions = Object.assign({}, localSpawnOptions, { remoteHost: '', remoteUser: dsct.nfsConfig.nfsUser, remotePassword: dsct.nfsConfig.nfsPassword }); const volumes = Object.keys(dsct.dockerComposeYaml.volumes).map((key) => dsct.dockerComposeYaml.volumes[key]); async.waterfall([ (cb) => { const nfsServerHash = {}; volumes.forEach((v) => { if (v.driver_opts && v.driver_opts.type === 'nfs' && v.driver === 'local') { const host = DockerProvisionImpl_1.optionsStringToHash(v.driver_opts.o).addr; nfsServerHash[host] = nfsServerHash[host] || []; nfsServerHash[host].push(v.driver_opts.device.slice(1)); } }); const nfsServers = Object.keys(nfsServerHash).map((key) => key); async.each(nfsServers, (nfsServer, cb) => { me.spawn.spawnShellCommandAsync([ 'showmount', '-e', nfsServer ], localSpawnOptions, () => { }, (err, result) => { if (err) { const resultObject = me.safeJson.safeParseSync(err.message); if (resultObject.obj.code !== 0) { const cmds = [ [ 'apt-get', 'update' ], [ 'apt-get', 'install', '-y', 'nfs-kernel-server' ] ]; return me.remoteSpawnCmdArray(cmds, Object.assign({}, remoteSpawnOptions, { remoteHost: nfsServer }), (err) => { me.callbackAndExitIfError(err, cb); cb(); }); } } cb(); }); }, (err) => { me.callbackAndExitIfError(err, cb); cb(null, nfsServerHash); }); }, (nfsServerHash, cb) => { const nfsServers = Object.keys(nfsServerHash).map((key) => key); async.each(nfsServers, (nfsServer, cb) => { me.spawn.spawnShellCommandAsync([ 'showmount', '-e', nfsServer ], localSpawnOptions, () => { }, (err, result) => { me.safeJson.safeParse(result, (err, obj) => { if (obj.code) { return cb(new Error(`local 'showmount' FAILED`)); } const exportList = obj.stdoutText.split('\n').slice(1, -1).map((exportLine) => exportLine.split(/\s/)[0]); const volumes = nfsServerHash[nfsServer]; const addExportSpawnOptions = Object.assign({}, remoteSpawnOptions, { remoteHost: nfsServer }); async.series([ (cb) => { async.each(volumes, (volume, cb) => { const msg = `Checking NFS mount ${nfsServer}:${volume} ...`; if (exportList.indexOf(volume) !== -1) { me.commandUtil.log(`${msg} OK`); return cb(); } me.commandUtil.log(`${msg} NOT EXPORTED`); me.commandUtil.log(`Attempting to export NFS volume ${nfsServer}:${volume} ...`); if (!addExportSpawnOptions.remoteHost || !addExportSpawnOptions.remoteUser || !addExportSpawnOptions.remotePassword) { return cb(new Error(`nfsConfig [nfsHost && (nfsUser + nfsPassword) || nfsSshKeyPath] must be specified to export NFS volume. Cannot continue.`)); } const etcExportsEntry = `${volume} *(insecure,rw,sync,no_root_squash,no_subtree_check)`; const cmds = [ [ 'mkdir', '-p', volume ], [ 'chmod', '777', volume ], [ `grep -q -F '${etcExportsEntry}' /etc/exports || echo '${etcExportsEntry}' >> /etc/exports` ] ]; me.remoteSpawnCmdArray(cmds, addExportSpawnOptions, cb); }, cb); }, (cb) => { const cmds = [ [ '/usr/sbin/exportfs', '-ra' ] ]; me.remoteSpawnCmdArray(cmds, addExportSpawnOptions, (err) => { me.commandUtil.log(`Restarted NFS services on ${nfsServer}`); cb(err); }); } ], cb); }); }); }, cb); } ], (err) => { cb(err, dsct); }); } remoteSpawnCmdArray(cmds, remoteSpawnOptions, cb) { const me = this; async.eachSeries(cmds, (cmd, cb) => { me.spawn.spawnShellCommandAsync(cmd, remoteSpawnOptions, (err, result) => { me.commandUtil.log(result); }, (err, result) => { me.commandUtil.log(result); cb(err); }); }, (err) => { cb(err); }); } static optionsHashToString(hash) { let retVal = ''; for (const key in hash) { retVal += key + ((hash[key]) ? `=${hash[key]},` : ','); } return retVal.slice(0, -1); } static optionsStringToHash(optionsString) { const hash = {}; optionsString.split(',').forEach((option) => { const optionWithValue = option.split('='); hash[optionWithValue[0]] = optionWithValue[1]; }); return hash; } extractYamlFromJson(argv, cb = null) { const me = this; const { fullInputPath, stackConfigTemplate } = me.getContainerConfigsFromJsonFile(argv.inputJsonFile); me.createOutputPath(fullInputPath, argv.outputYamlFile, '.yaml', (err, outputYamlPath, outputFileExists) => { me.callbackAndExitIfError(err, cb); if (outputFileExists && !me.positive.areYouSure(`Output file '${outputYamlPath}' already exists. Overwrite? [Y/n] `, 'Operation canceled.', true, firmament_yargs_1.FailureRetVal.TRUE)) { me.callbackAndExitWithError(err, cb); } const yaml = YAML.stringify(stackConfigTemplate.dockerComposeYaml, 8, 2); fs.writeFile(outputYamlPath, yaml, (err) => { me.callbackAndExitWithError(err, cb); }); }); } makeTemplate(argv, cb = null) { const me = this; me.composeAndWriteTemplate(argv.get, argv.dm, argv.yaml, argv.output, (err, msg) => { me.callbackAndExitWithError(err, cb); }); } buildTemplate(argv, cb = null) { const me = this; const { fullInputPath, stackConfigTemplate } = me.getContainerConfigsFromJsonFile(argv.input); me.validateDockerStackConfigTemplate(argv, stackConfigTemplate, (err, stackConfigTemplate) => { if (err) { if (cb) { return cb(err); } me.commandUtil.processExitWithError(err, 'OK'); } me.stackConfigTemplate = stackConfigTemplate; switch (stackConfigTemplate.dockerMachineDriverOptions.driver) { case 'openstack': { const dmdo = stackConfigTemplate.dockerMachineDriverOptions; if (argv.username) { dmdo.openstackUsername = argv.username; } if (argv.password) { dmdo.openstackPassword = argv.password; } break; } case 'vmwarevsphere': { const dmdo = stackConfigTemplate.dockerMachineDriverOptions; if (argv.username) { dmdo.vmwarevsphereUsername = argv.username; } if (argv.password) { dmdo.vmwarevspherePassword = argv.password; } break; } case 'amazonec2': case 'virtualbox': default: break; } me.commandUtil.log("Constructing Docker Stack described in: '" + fullInputPath + "'"); me.createDockerMachines(fullInputPath, stackConfigTemplate, argv, (err, result) => { if (cb) { return cb(); } me.commandUtil.processExitWithError(err, 'OK'); }); }); } convertOptionsFromCamelToSnakeCase(options) { const me = this; const retVal = []; const excludeProperties = ['nodeCount', 'nodeName']; for (const option in options) { if (excludeProperties.indexOf(option) !== -1) { continue; } if (option === 'engineLabels') { for (const engineLabel in options[option]) { retVal.push('--engine-label'); retVal.push(`${engineLabel}=${options[option][engineLabel]}`); } continue; } const optionKey = me.camelToSnake(option, '-'); const optionValue = options[option]; const keyValueSeparator = ((typeof optionValue !== 'string') || (optionValue.indexOf('=') === -1)) ? '=' : ' '; retVal.push(`--${optionKey}${keyValueSeparator}${optionValue}`); } return retVal; } logErrAndResult(err, result) { const me = this; if (err) { return me.commandUtil.log(err.message); } me.commandUtil.log((result || '').toString()); } createDockerMachines(fullInputPath, stackConfigTemplate, argv, cb) { const me = this; cb = me.checkCallback(cb); const createOptions = me.convertOptionsFromCamelToSnakeCase(stackConfigTemplate.dockerMachineDriverOptions); async.waterfall([ (cb) => { const managerMachineName = `${stackConfigTemplate.stackName}-${stackConfigTemplate.dockerMachines.manager.nodeName}`; const managerDockerMachineCmd = createOptions.slice(); managerDockerMachineCmd.push.apply(managerDockerMachineCmd, me.convertOptionsFromCamelToSnakeCase(stackConfigTemplate.dockerMachines.manager)); managerDockerMachineCmd.push(managerMachineName); me.createDockerMachine(managerDockerMachineCmd, cb); }, (managerMachineName, ip, cb) => { const dockerMachineInitSwarmCmd = [ 'docker-machine', 'ssh', managerMachineName, 'docker', 'swarm', 'init', '--advertise-addr', ip ]; if (me.writeScripts) { fs.writeFileSync(`/home/jreeme/tmp/_init_swarm.sh`, dockerMachineInitSwarmCmd.join(' ')); return cb(null, managerMachineName, ip); } me.spawn.spawnShellCommandAsync(dockerMachineInitSwarmCmd, { cacheStdOut: true }, me.logErrAndResult.bind(me), (_err) => { if (_err) { const { err, obj } = me.safeJson.safeParseSync(_err.message); if (!err && obj.code === 1) { return cb(null, managerMachineName, ip); } } cb(_err, managerMachineName, ip); }); }, (managerMachineName, ip, cb) => { const dockerMachineInitSwarmCmd = [ 'docker-machine', 'ssh', managerMachineName, 'docker', 'swarm', 'join-token', 'worker', '-q' ]; if (me.writeScripts) { fs.writeFileSync(`/home/jreeme/tmp/_join_swarm.sh`, dockerMachineInitSwarmCmd.join(' ')); return cb(null, managerMachineName, ip, 'joinToken'); } me.spawn.spawnShellCommandAsync(dockerMachineInitSwarmCmd, { cacheStdOut: true }, me.logErrAndResult.bind(me), (err, result) => { const joinToken = me.safeJson.safeParseSync(result).obj.stdoutText.trim(); cb(null, managerMachineName, ip, joinToken); }); }, (managerMachineName, managerIp, joinToken, cb) => { let fnArray = []; stackConfigTemplate.dockerMachines.workers.forEach((workerDockerMachine) => { for (let i = 0; i < workerDockerMachine.nodeCount; ++i) { const workerMachineName = `${stackConfigTemplate.stackName}-${workerDockerMachine.nodeName}-${i}`; const workerDockerMachineCmd = createOptions.slice(); workerDockerMachineCmd.push.apply(workerDockerMachineCmd, me.convertOptionsFromCamelToSnakeCase(workerDockerMachine)); workerDockerMachineCmd.push(workerMachineName); fnArray.push(async.apply(me.createWorkerDockerMachine.bind(me), workerDockerMachineCmd, managerIp, joinToken)); } }); async.parallel(fnArray, (err) => { cb(err, managerMachineName, managerIp); }); }, (managerMachineName, ip, cb) => { const dockerMachineGetMasterEnvCmd = [ 'docker-machine', 'env', managerMachineName ]; me.spawn.spawnShellCommandAsync(dockerMachineGetMasterEnvCmd, { cacheStdOut: true }, (err, result) => { me.commandUtil.log(result.toString()); }, (err, result) => { const regex = /export (.*)/g; const envString = me.safeJson.safeParseSync(result).obj.stdoutText.trim(); let match; let env = {}; do { match = regex.exec(envString); if (match) { const keyValue = match[1].split('='); env[keyValue[0]] = keyValue[1].replace(/"/g, ''); } } while (match); cb(null, env, ip); }); }, (env, ip, cb) => { tmp.file({ dir: path.dirname(fullInputPath) }, (err, tmpPath, fd, cleanupCb) => { try { if (argv.noPorts) { for (const serviceName in stackConfigTemplate.dockerComposeYaml.services) { const service = stackConfigTemplate.dockerComposeYaml.services[serviceName]; service.ports && delete service.ports; } } } catch (err) { me.commandUtil.error(`Failed to execute 'noPorts' option ${err}`); } const yaml = YAML.stringify(stackConfigTemplate.dockerComposeYaml, 8, 2).replace(/\$\{MASTER_IP\}/g, ip); if (me.commandUtil.callbackIfError(err)) { return; } fs.writeFile(tmpPath, yaml, (err) => { if (err) { me.logErrAndResult(err, ''); return cb(err); } const dockerMachineDeployCmd = [ 'docker', 'stack', 'deploy', '-c', tmpPath, stackConfigTemplate.stackName ? stackConfigTemplate.stackName : stackConfigTemplate.clusterPrefix ]; me.spawn.spawnShellCommandAsync(dockerMachineDeployCmd, { env, cacheStdOut: true }, (err, result) => { me.commandUtil.log(result.toString()); }, (err, result) => { me.logErrAndResult(err, result); cleanupCb(); cb(); }); }); }); } ], (err, result) => { me.logErrAndResult(err, result); cb(err, result); }); } createWorkerDockerMachine(dockerMachineCmd, managerIp, joinToken, cb) { const me = this; me.createDockerMachine(dockerMachineCmd, (err, workerMachineName, workerIp) => { if (err) { return cb(err); } const dockerMachineJoinSwarmCmd = [ 'docker-machine', 'ssh', workerMachineName, 'docker', 'swarm', 'join', '--advertise-addr', `${workerIp}:2377`, '--token', joinToken, `${managerIp}:2377` ]; if (me.writeScripts) { fs.writeFileSync(`/home/jreeme/tmp/_join_worker_${workerMachineName}.sh`, dockerMachineJoinSwarmCmd.join(' ')); return cb(null, ''); } me.spawn.spawnShellCommandAsync(dockerMachineJoinSwarmCmd, { cacheStdOut: true, cacheStdErr: true }, (err, result) => { me.commandUtil.log(result.toString()); }, (err, result) => { cb(null, result); }); }); } handleDockerMachineExecutionFailure(err, cb) { const me = this; me.safeJson.safeParse(err.message, (err, obj) => { try { if (obj.code.code === 'ENOENT') { if (me.positive.areYouSure(`Looks like 'docker-machine' is not installed. Want me to try to install it?`, 'Operation canceled.', true, firmament_yargs_1.FailureRetVal.TRUE)) { const installDockerMachineJson = path.resolve(__dirname, '../../firmament-bash/install-docker-machine.json'); return me.processCommandJson.processAbsoluteUrl(installDockerMachineJson, (err) => { cb(new Error(`'docker-machine' installed. Try provisioning again.`)); }); } return cb(new Error('docker-machine installation canceled')); } cb(null); } catch (err) { cb(err); } }); } createDockerMachine(dockerMachineCreateCmdOptions, cb) { const me = this; async.waterfall([ (cb) => { const dockerMachineCmd = [ 'docker-machine', 'create' ].concat(dockerMachineCreateCmdOptions); if (me.writeScripts) { fs.writeFileSync(`/home/jreeme/tmp/_create_${dockerMachineCmd[dockerMachineCmd.length - 1]}.sh`, dockerMachineCmd.join(' ')); return cb(null, ''); } me.spawn.spawnShellCommandAsync(dockerMachineCmd, {}, (err, result) => { me.commandUtil.log(result.toString()); }, (err) => { const machineName = dockerMachineCmd[dockerMachineCmd.length - 1]; if (err) { return me.handleDockerMachineExecutionFailure(err, (err) => { me.commandUtil.processExitIfError(err); cb(err, machineName); }); } switch (me.stackConfigTemplate.dockerMachineDriverOptions.driver) { case ('vmwarevsphere'): return me.finalConfig_VMWareVSphere(machineName, cb); case ('openstack'): return me.finalConfig_OpenStack(machineName, cb); case ('amazonec2'): return me.finalConfig_AmazonEC2(machineName, cb); case ('virtualbox'): default: return me.finalConfig_VirtualBox(machineName, cb); } }); }, (machineName, cb) => { const dockerMachineGetIpCmd = [ 'docker-machine', 'ip', machineName ]; if (me.writeScripts) { fs.writeFileSync(`/home/jreeme/tmp/_get_managerIp.sh`, dockerMachineGetIpCmd.join(' ')); return cb(null, machineName, '0.0.0.0'); } me.spawn.spawnShellCommandAsync(dockerMachineGetIpCmd, { cacheStdOut: true }, me.logErrAndResult.bind(me), (err, result) => { const ip = me.safeJson.safeParseSync(result).obj.stdoutText.trim(); cb(err, { machineName, ip }); }); } ], (err, result) => { const { machineName, ip } = result; cb(err, machineName, ip); }); } ; finalConfig_VirtualBox(machineName, cb) { this.adjustBoot2DockerProfile(machineName, cb); } finalConfig_AmazonEC2(machineName, cb) { cb(null, machineName); } finalConfig_OpenStack(machineName, cb) { cb(null, machineName); } finalConfig_VMWareVSphere(machineName, cb) { this.adjustBoot2DockerProfile(machineName, cb); } adjustBoot2DockerProfile(machineName, cb) { const me = this; const profileLines = (me.stackConfigTemplate.hostMachineDnsServer) ? ` #Need to set vm.max_map_count to 262144 to support ElasticSearch (ES fails in production without it) sysctl -w vm.max_map_count=262144 sysctl -w net.ipv4.tcp_keepalive_time=600 ulimit -l unlimited #swapoff /dev/sda2 #sed -i '\\''/sda2/ s/^/#/'\\'' /etc/fstab NETDEVICES="$(awk -F: '\\''/eth.:|tr.:/{print $1}'\\'' /proc/net/dev 2>/dev/null)" for DEVICE in $NETDEVICES; do DHCP_PID_FILE=/var/run/udhcpc.$DEVICE.pid echo "Checking existence of $DHCP_PID_FILE ..." until [ -f $DHCP_PID_FILE ]; do echo "Waiting for $DHCP_PID_FILE to exist ..." sleep 1 done done echo "$DHCP_PID_FILE exists ..." RESOLV_CONF=/etc/resolv.conf echo "Checking existence of $RESOLV_CONF ..." until [ -f $RESOLV_CONF ]; do echo "Waiting for $RESOLV_CONF to exist ..." sleep 1 done echo "$RESOLV_CONF exists ..." DATE_OF_DHCP_PID_FILE=$(date -u -r $DHCP_PID_FILE +%s) DATE_OF_RESOLV_CONF=$(date -u -r $RESOLV_CONF +%s) NOW=$(date -u +%s) echo "$DHCP_PID_FILE last modified at $DATE_OF_DHCP_PID_FILE" echo "$RESOLV_CONF last modified at $DATE_OF_RESOLV_CONF" echo $(( \${DATE_OF_DHCP_PID_FILE}-\${DATE_OF_RESOLV_CONF} )) echo 'nameserver ${me.stackConfigTemplate.hostMachineDnsServer}' > /etc/resolv.conf #Try to protect against resolver restart or DHCP lease renewal rewriting our resolv.conf file chmod 444 /etc/resolv.conf ` : ` #Need to set vm.max_map_count to 262144 to support ElasticSearch (ES fails in production without it) sysctl -w vm.max_map_count=262144 sysctl -w net.ipv4.tcp_keepalive_time=600 ulimit -l unlimited #swapoff /dev/sda2 #sed -i '\\''/sda2/ s/^/#/'\\'' /etc/fstab `; const dockerMachineJoinSwarmCmd = [ `echo '${profileLines}' | sudo tee -a /var/lib/boot2docker/profile && sudo /etc/init.d/docker restart` ]; me.runCommandOnDockerMachineHost(machineName, dockerMachineJoinSwarmCmd, (err, result) => { err && me.commandUtil.log(err.toString()); cb(err, machineName); }); } runCommandOnDockerMachineHost(machineName, commandArray, cb) { const me = this; commandArray.unshift('docker-machine', 'ssh', machineName); me.spawn.spawnShellCommandAsync(commandArray, { cacheStdOut: true }, (err, result) => { me.commandUtil.log(result.toString()); }, cb); } getContainerConfigsFromJsonFile(inputPath) { const me = this; const fullInputPath = me.commandUtil.getConfigFilePath(inputPath, '.json'); if (!fileExists.sync(fullInputPath)) { me.commandUtil.processExitWithError(new Error(`\n'${fullInputPath}' does not exist`)); } const stackConfigTemplate = me.safeJson.readFileSync(fullInputPath, undefined); return { fullInputPath, stackConfigTemplate }; } composeAndWriteTemplate(catalogEntryName, dockerMachineHostType, dockerComposeYamlPath, outputTemplateFileName, cb) { const me = this; me.createOutputPath(path.resolve(process.cwd(), 'tmp.txt'), outputTemplateFileName, '.json', (err, fullOutputPath, outputFileExists) => { if (catalogEntryName === undefined) { if (fileExists.sync(fullOutputPath) && !me.positive.areYouSure(`Config file '${fullOutputPath}' already exists. Overwrite? [Y/n] `, 'Operation canceled.', true, firmament_yargs_1.FailureRetVal.TRUE)) { return cb(null); } const dockerMachineWrapperPath = path.resolve(__dirname, `../../docker/docker-machine-wrappers/${dockerMachineHostType}.json`); const dockerMachineWrapper = me.safeJson.readFileSync(dockerMachineWrapperPath, undefined); const dockerComposeYaml = YAML.load(dockerComposeYamlPath); const jsonTemplate = Object.assign({}, dockerMachineWrapper, { dockerComposeYaml }); me.dockerUtil.writeJsonTemplateFile(jsonTemplate, fullOutputPath); cb(null, 'Template written.'); } else { cb(new Error('Provision from template not implemented.')); } }); } callbackAndExitIfError(err, cb) { if (!err) { return; } if (cb) { cb(); } this.commandUtil.processExitWithError(err, 'OK'); } callbackAndExitWithError(err, cb) { if (cb) { cb(); } this.commandUtil.processExitWithError(err, 'OK'); } camelToSnake(name, separator) { return name.replace(/([a-z]|(?:[A-Z]+))([A-Z]|$)/g, function (_, $1, $2) { return $1 + ($2 && (separator || '_') + $2); }).toLowerCase(); } createOutputPath(inPathFragment, outPathFragment, extension, cb) { if (path.extname(outPathFragment) !== extension) { outPathFragment += extension; } if (!path.isAbsolute(outPathFragment)) { outPathFragment = path.resolve(path.dirname(inPathFragment), outPathFragment); } const pathDirname = path.dirname(outPathFragment); mkdirp(pathDirname, (err) => { if (err) { return cb(err, outPathFragment); } fileExists(outPathFragment, (err, exists) => { touch(outPathFragment, (err) => { if (err || exists) { return cb(err, outPathFragment, exists); } fs.unlink(outPathFragment, (err) => { return cb(err, outPathFragment, exists); }); }); }); }); } ; }; DockerProvisionImpl = DockerProvisionImpl_1 = __decorate([ inversify_1.injectable(), __param(0, inversify_1.inject('CommandUtil')), __param(1, inversify_1.inject('Spawn')), __param(2, inversify_1.inject('SafeJson')), __param(3, inversify_1.inject('RemoteCatalogGetter')), __param(4, inversify_1.inject('ProcessCommandJson')), __param(5, inversify_1.inject('DockerUtil')), __param(6, inversify_1.inject('DockerImageManagement')), __param(7, inversify_1.inject('DockerContainerManagement')), __param(8, inversify_1.inject('Positive')), __param(9, inversify_1.inject('ProgressBar')), __metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]) ], DockerProvisionImpl); exports.DockerProvisionImpl = DockerProvisionImpl; //# sourceMappingURL=docker-provision-impl.js.map