const Docker = require('dockerode'); const docker = new Docker({ 'socketPath': '/home/docker.sock' }); const path = require('path'); const fs = require('fs'); const PROJECT_PATH = process.env.PROJECT_PATH; const DOCKERIMAGE = "qlikgear/terraform:1.0.0"; const SSHPATH = process.env.SSHPATH; function hook_stdout(callback) { var old_write = process.stdout.write process.stdout.write = (function(write) { return function(string, encoding, fd) { write.apply(process.stdout, arguments) callback(string, encoding, fd) } })(process.stdout.write) return function() { process.stdout.write = old_write } } const init = function( provMongo ) { const templatePath = path.join(PROJECT_PATH, 'az-tf-templates', provMongo.scenario); const name = `qmi-tf-init-${provMongo._id}`; console.log(`Provision: will spin up container: ${name}`); var processStream = fs.createWriteStream(provMongo.logFile, {flags:'a'}); return docker.run(DOCKERIMAGE, ['terraform', 'init', '-no-color', '-from-module=/template'], processStream, { //"Env": ["VAR_ENV=whatever"], "name": name, "WorkingDir": "/app", "HostConfig": { "Binds": [ `${provMongo.path}:/app`, `${templatePath}:/template` ] } }).then(function(data) { var output = data[0]; var container = data[1]; console.log(`Provision: ${name} (${container.id}) has finished with code: ${output.StatusCode}`); return container.remove(); }).then(function() { console.log(`Provision: ${name} removed!`); return provMongo; }); } const plan = function( provMongo, user ) { const name = `qmi-tf-plan-${provMongo._id}`; console.log(`Provision: will spin up container: ${name}`); var processStream = fs.createWriteStream(provMongo.logFile, {flags:'a'}); //var processStream = process.stdout; let exec = ['terraform', 'plan', '-no-color', '-input=false', '-out=tfplan', '-var-file=scenario.tfvars', '-var', `provision_id=${provMongo._id}`, '-var', `user_id=${user}`]; if ( provMongo.vmType ) { exec.push('-var'); exec.push(`vm_type=${provMongo.vmType}`); } if ( provMongo.nodeCount ) { exec.push('-var'); exec.push(`agent_count=${provMongo.nodeCount}`); } return docker.run(DOCKERIMAGE, exec, processStream, { //"Env": ["VAR_ENV=whatever"], "name": name, "WorkingDir": "/app", "HostConfig": { "Binds": [ `${provMongo.path}:/app`, `${SSHPATH}:/root/.ssh` ], "NetworkMode": "host" } }).then(function(data){ let output = data[0]; let container = data[1]; console.log(`Provision: ${name} (${container.id}) has finished with code: ${output.StatusCode}`); return container.remove(); }).then(function() { console.log(`Provision: ${name} removed!`); return fs.readFileSync(provMongo.logFile); }) } const apply = function( provMongo, user ) { const name = `qmi-tf-apply-${provMongo._id}`; console.log(`Provision: will spin up container: ${name}`); var processStream = fs.createWriteStream(provMongo.logFile, {flags:'a'}); //var processStream = process.stdout; return docker.run(DOCKERIMAGE, ['terraform', 'apply', 'tfplan', '-no-color'], processStream, { //"Env": ["VAR_ENV=whatever"], "name": name, "WorkingDir": "/app", "HostConfig": { "Binds": [ `${provMongo.path}:/app`, `${SSHPATH}:/root/.ssh` ], "NetworkMode": "host" } }).then(function(data){ let output = data[0]; let container = data[1]; console.log(`Provision: ${name} (${container.id}) has finished with code: ${output.StatusCode}`); return container.remove(); }).then(function() { console.log(`Provision: ${name} removed!`); return fs.readFileSync(provMongo.logFile); }) } const destroy = function(destroyMongo, provMongo) { const name = `qmi-tf-destroy-${destroyMongo._id}`; console.log(`Destroy Provision: will spin up container: ${name}`); var processStream = fs.createWriteStream(destroyMongo.logFile, {flags:'a'}); let exec = ['terraform', 'destroy', '-auto-approve', '-no-color', '-var-file=scenario.tfvars', "-var", `provision_id=${destroyMongo.provId}`]; if (provMongo.vmType) { exec.push("-var"); exec.push(`vm_type=${provMongo.vmType}`); } if ( provMongo.nodeCount ) { exec.push('-var'); exec.push(`agent_count=${provMongo.nodeCount}`); } return docker.run(DOCKERIMAGE, exec, processStream, { //"Env": ["VAR_ENV=whatever"], "name": name, "WorkingDir": "/app", "HostConfig": { "Binds": [ `${provMongo.path}:/app`, `${SSHPATH}:/root/.ssh` ] } }).then(function(data) { var output = data[0]; var container = data[1]; console.log(`Processor Destroy: '${name}' (${container.id}) has finished with code: ${output.StatusCode}`); return container.remove(); }).then(async function(data) { console.log(`Processor Destroy: '${name}' removed!`); return fs.readFileSync(destroyMongo.logFile); }); } const outputs = function(provMongo) { const name = `qmi-tf-output-${provMongo._id}`; console.log(`Destroy Provision: will spin up container: ${name}`); let tfout = ""; let unhook = hook_stdout(function(string, encoding, fd) { tfout += string.trim(); }); return docker.run(DOCKERIMAGE, ['terraform', 'output', '-no-color', '-json'], process.stdout, { //"Env": ["VAR_ENV=whatever"], "name": name, "WorkingDir": "/app", "HostConfig": { "Binds": [ `${provMongo.path}:/app` ] } }).then(function(data) { unhook(); let output = data[0]; let container = data[1]; console.log(`Processor Destroy: '${name}' (${container.id}) has finished with code: ${output.StatusCode}`); return container.remove(); }).then(async function(data) { console.log(`Processor Destroy: '${name}' removed!`); let out = JSON.parse(tfout); var o = {}; for (var key in out) { o[key] = out[key].value; } return o; }); } module.exports.init = init; module.exports.plan = plan; module.exports.apply = apply; module.exports.destroy = destroy; module.exports.outputs = outputs;