401 lines
15 KiB
JavaScript
401 lines
15 KiB
JavaScript
const Docker = require('dockerode');
|
|
const docker = new Docker({
|
|
'socketPath': '/home/docker.sock'
|
|
});
|
|
const fs = require('fs');
|
|
const GIT_SCENARIOS = process.env.GIT_SCENARIOS;
|
|
const GIT_TAG = process.env.GIT_TAG || "master";
|
|
const SSHPATH = process.env.SSHPATH;
|
|
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
|
|
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
function _buildVarsExec( exec, provision ) {
|
|
|
|
let gitBranch = GIT_TAG;
|
|
if ( provision._scenarioDoc && provision._scenarioDoc.gitBranch && provision._scenarioDoc.gitBranch.trim() !== "") {
|
|
gitBranch = provision._scenarioDoc.gitBranch;
|
|
}
|
|
let prefix = provision.scenario.toUpperCase();
|
|
prefix = prefix.replace(/AZQMI/g, 'QMI');
|
|
|
|
let envs = [
|
|
`AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}`,
|
|
`AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}`,
|
|
`AWS_DEFAULT_REGION=us-east-1`,
|
|
`TF_VAR_envbranch=${gitBranch}`,
|
|
`TF_VAR_user_email=${provision.user.upn}`,
|
|
`TF_VAR_user_oid=${provision.user.oid}`,
|
|
`TF_VAR_prefix=${prefix}`
|
|
];
|
|
|
|
if ( provision.deployOpts ) {
|
|
|
|
if ( provision.deployOpts.subsId ) {
|
|
exec.push('-var');
|
|
exec.push(`subscription_id=${provision.deployOpts.subsId}`);
|
|
}
|
|
|
|
if ( provision.deployOpts.location ) {
|
|
exec.push('-var');
|
|
exec.push(`location=${provision.deployOpts.location}`);
|
|
}
|
|
|
|
if ( provision.deployOpts.vnetExists ) {
|
|
envs.push(`TF_VAR_subnet_id=${provision.deployOpts.subnetId}`);
|
|
if ( provision.isExternalAccess ) {
|
|
envs.push(`TF_VAR_app_gw_subnet=${provision.deployOpts.appGwSubnetId}`);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
exec.push('-var');
|
|
exec.push(`provision_id=${provision._id}`);
|
|
exec.push('-var');
|
|
exec.push(`user_id=${provision.user.displayName}`);
|
|
|
|
//DEPRECATED VMIMAGE
|
|
if ( provision.vmImage ) {
|
|
for ( let key in provision.vmImage ) {
|
|
|
|
if ( !provision.vmImage[key].disabled ) {
|
|
|
|
if ( provision.vmImage[key].nodeCount ) {
|
|
exec.push('-var');
|
|
exec.push(`agent_count_${key}=${provision[key].nodeCount}`);
|
|
}
|
|
|
|
if ( provision.vmImage[key].vmType ) {
|
|
exec.push('-var');
|
|
exec.push(`vm_type_${key}=${provision.vmImage[key].vmType}`);
|
|
} else {
|
|
exec.push('-var');
|
|
exec.push(`vm_type_${key}=ENABLED`);
|
|
}
|
|
|
|
if ( provision.vmImage[key].diskSizeGb ) {
|
|
exec.push('-var');
|
|
exec.push(`disk_size_gb_${key}=${provision.vmImage[key].diskSizeGb}`);
|
|
}
|
|
|
|
if ( provision.vmImage[key].version && provision.vmImage[key].version.image) {
|
|
exec.push('-var');
|
|
exec.push(`image_reference_${key}=${provision.vmImage[key].version.image}`);
|
|
}
|
|
|
|
if ( provision.vmImage[key].version && provision.vmImage[key].version.init_password) {
|
|
exec.push('-var');
|
|
exec.push(`image_reference_${key}_init_password=${provision.vmImage[key].version.init_password}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// NEW ATTRS
|
|
if ( provision.options ) {
|
|
for ( let key in provision.options ) {
|
|
|
|
if ( !provision.options[key].disabled ) {
|
|
|
|
if ( key.indexOf("vm") !== -1 ) {
|
|
if ( provision.options[key].nodeCount ) {
|
|
exec.push('-var');
|
|
exec.push(`agent_count_${key}=${provision[key].nodeCount}`);
|
|
}
|
|
if ( provision.options[key].vmType ) {
|
|
exec.push('-var');
|
|
exec.push(`vm_type_${key}=${provision.options[key].vmType}`);
|
|
}else {
|
|
exec.push('-var');
|
|
exec.push(`vm_type_${key}=ENABLED`);
|
|
}
|
|
if ( provision.options[key].diskSizeGb ) {
|
|
exec.push('-var');
|
|
exec.push(`disk_size_gb_${key}=${provision.options[key].diskSizeGb}`);
|
|
}
|
|
if ( provision.options[key].selected && provision.options[key].selected.value) {
|
|
exec.push('-var');
|
|
exec.push(`image_reference_${key}=${provision.options[key].selected.value}`);
|
|
}
|
|
|
|
if ( provision.options[key].selected && provision.options[key].selected.init_password) {
|
|
exec.push('-var');
|
|
exec.push(`image_reference_${key}_init_password=${provision.options[key].selected.init_password}`);
|
|
}
|
|
} else {
|
|
if ( provision.options[key].selected && provision.options[key].selected.value) {
|
|
exec.push('-var');
|
|
exec.push(`attr_${key}=${provision.options[key].selected.value}`);
|
|
} else {
|
|
exec.push('-var');
|
|
exec.push(`attr_${key}=ENABLED`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( provision.isExternalAccess ) {
|
|
exec.push('-var');
|
|
exec.push(`is_external_access=${provision.isExternalAccess}`);
|
|
}
|
|
|
|
if ( provision.schedule ) {
|
|
if ( provision.schedule.is24x7 === true ) {
|
|
exec.push('-var');
|
|
exec.push(`is_24x7=true`);
|
|
} else if ( provision.schedule.is24x7 === false ) {
|
|
exec.push('-var');
|
|
exec.push(`is_24x7=false`);
|
|
if ( provision.schedule.utcTagStartupTime && provision.schedule.isStartupTimeEnable ) {
|
|
exec.push('-var');
|
|
exec.push(`startupTime=${provision.schedule.utcTagStartupTime}`);
|
|
}
|
|
if ( provision.schedule.utcTagShutdownTime ) {
|
|
exec.push('-var');
|
|
exec.push(`shutdownTime=${provision.schedule.utcTagShutdownTime}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
return {"exec": exec, "envs": envs};
|
|
}
|
|
|
|
const init = function( provision ) {
|
|
|
|
const name = `qmi-tf-init-${provision._id}`;
|
|
console.log(`Terraform# Init: will spin up container: ${name}`);
|
|
var processStream = fs.createWriteStream(provision.logFile, {flags:'a'});
|
|
let gitBranch = GIT_TAG;
|
|
if ( provision._scenarioDoc && provision._scenarioDoc.gitBranch && provision._scenarioDoc.gitBranch.trim() !== "") {
|
|
gitBranch = provision._scenarioDoc.gitBranch;
|
|
}
|
|
let exec = ['terraform', 'init', '-no-color', `-from-module=${GIT_SCENARIOS}//${provision.scenario}?ref=${gitBranch}`];
|
|
console.log('Terraform# Init: exec: '+exec.join(" "));
|
|
console.log('Terraform# Init: version to use is : '+provision.terraformImage);
|
|
return docker.run(provision.terraformImage, exec, processStream, {
|
|
//"Env": [],
|
|
"name": name,
|
|
"WorkingDir": "/app",
|
|
"HostConfig": {
|
|
"Binds": [
|
|
`${provision.path}:/app`
|
|
]
|
|
}
|
|
}).then(function(data) {
|
|
var output = data[0];
|
|
var container = data[1];
|
|
console.log(`Terraform# Init: ${name} (${container.id}) has finished with code: ${output.StatusCode}`);
|
|
return container.remove().then(function(){
|
|
console.log(`Terraform# Init: ${name} removed!`);
|
|
return output.StatusCode;
|
|
});
|
|
}).then(function(statusCode) {
|
|
return {"provision": provision, "statusCode": statusCode};
|
|
});
|
|
};
|
|
|
|
const plan = function( provision ) {
|
|
|
|
const name = `qmi-tf-plan-${provision._id}`;
|
|
console.log(`Terraform# Plan: will spin up container: ${name}`);
|
|
var processStream = fs.createWriteStream(provision.logFile, {flags:'a'});
|
|
//var processStream = process.stdout;
|
|
var exec = ['terraform', 'plan', '-no-color', '-input=false', '-out=tfplan' ];
|
|
var vars = _buildVarsExec(exec, provision);
|
|
exec = vars.exec;
|
|
console.log('Terraform# Plan: exec: '+exec.join(" "));
|
|
console.log('Terraform# Plan: version to use is : '+provision.terraformImage);
|
|
return docker.run(provision.terraformImage, exec, processStream, {
|
|
"Env": vars.envs,
|
|
"name": name,
|
|
"WorkingDir": "/app",
|
|
"HostConfig": {
|
|
"Binds": [
|
|
`${provision.path}:/app`,
|
|
`${SSHPATH}:/root/.ssh`
|
|
],
|
|
"NetworkMode": "host"
|
|
}
|
|
}).then(function(data){
|
|
var container = data[1];
|
|
console.log(`Terraform# Plan: ${name} (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
|
return container.remove().then(function(){
|
|
console.log(`Terraform# Plan: ${name} removed!`);
|
|
return data[0].StatusCode;
|
|
});
|
|
}).then(function(statusCode) {
|
|
return {"output": fs.readFileSync(provision.logFile), "statusCode": statusCode};
|
|
})
|
|
};
|
|
|
|
const apply = function( provision ) {
|
|
|
|
const name = `qmi-tf-apply-${provision._id}`;
|
|
console.log(`Terraform# Apply: will spin up container: ${name}`);
|
|
var processStream = fs.createWriteStream(provision.logFile, {flags:'a'});
|
|
//var processStream = process.stdout;
|
|
|
|
var exec = ['terraform', 'apply', 'tfplan', '-no-color'];
|
|
console.log('Terraform# Apply: exec: '+exec.join(" "));
|
|
console.log('Terraform# Apply: version to use is : '+provision.terraformImage);
|
|
return docker.run(provision.terraformImage, exec, processStream, {
|
|
"Env": [
|
|
`AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}`,
|
|
`AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}`,
|
|
`AWS_DEFAULT_REGION=us-east-1`
|
|
],
|
|
"name": name,
|
|
"WorkingDir": "/app",
|
|
"HostConfig": {
|
|
"Binds": [
|
|
`${provision.path}:/app`,
|
|
`${SSHPATH}:/root/.ssh`
|
|
],
|
|
"NetworkMode": "host"
|
|
}
|
|
}).then(function(data){
|
|
let container = data[1];
|
|
console.log(`Terraform# Apply: ${name} (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
|
return container.remove().then(function(){
|
|
console.log(`Terraform# Apply: Container '${name}' removed!`);
|
|
return data[0].StatusCode;
|
|
});
|
|
}).then(function(statusCode) {
|
|
return {"output": fs.readFileSync(provision.logFile), "statusCode": statusCode};
|
|
})
|
|
}
|
|
|
|
const destroy = function(destroyMongo, provision) {
|
|
|
|
const name = `qmi-tf-destroy-${destroyMongo._id}`;
|
|
console.log(`Terraform# Destroy: will spin up container: ${name}`);
|
|
var processStream = fs.createWriteStream(destroyMongo.logFile, {flags:'a'});
|
|
var exec = ['terraform', 'destroy', '-auto-approve', '-no-color'];
|
|
var vars = _buildVarsExec(exec, provision);
|
|
exec = vars.exec;
|
|
console.log('Terraform# Destroy: exec: '+exec.join(" "));
|
|
console.log('Terraform# Destroy: version to use is : '+provision.terraformImage);
|
|
|
|
return docker.run(provision.terraformImage, exec, processStream, {
|
|
"Env": vars.envs,
|
|
"name": name,
|
|
"WorkingDir": "/app",
|
|
"HostConfig": {
|
|
"Binds": [
|
|
`${provision.path}:/app`,
|
|
`${SSHPATH}:/root/.ssh`
|
|
]
|
|
}
|
|
}).then(function(data) {
|
|
var container = data[1];
|
|
console.log(`Terraform# Destroy: '${name}' (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
|
return container.remove().then(function(){
|
|
console.log(`Terraform# Destroy: Container '${name}' removed!`);
|
|
return data[0].StatusCode;
|
|
});
|
|
}).then(async function(statusCode) {
|
|
|
|
return {"output": fs.readFileSync(destroyMongo.logFile), "statusCode": statusCode};
|
|
});
|
|
};
|
|
|
|
const outputs = function(provision) {
|
|
|
|
const name = `qmi-tf-output-${provision._id}`;
|
|
console.log(`Terraform# Output: will spin up container: ${name}`);
|
|
|
|
|
|
var exec = ['terraform', 'output', '-no-color', '-json'];
|
|
console.log('Terraform# Output: exec: '+exec.join(" "));
|
|
|
|
var tfout = "";
|
|
var unhook = hook_stdout(function(string, encoding, fd) {
|
|
tfout += string.trim();
|
|
});
|
|
return docker.run(provision.terraformImage, exec, process.stdout, {
|
|
//"Env": [],
|
|
"name": name,
|
|
"WorkingDir": "/app",
|
|
"HostConfig": {
|
|
"Binds": [
|
|
`${provision.path}:/app`
|
|
]
|
|
}
|
|
}).then(function(data) {
|
|
unhook();
|
|
var container = data[1];
|
|
console.log(`Terraform# Output: '${name}' (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
|
return container.remove();
|
|
}).then(async function(data) {
|
|
console.log(`Terraform# Output: Container '${name}' removed!`);
|
|
//console.log("Terraform# Output: tfout: " + tfout);
|
|
var out = JSON.parse(tfout);
|
|
var o = {};
|
|
for (var key in out) {
|
|
o[key] = out[key].value;
|
|
}
|
|
return o;
|
|
});
|
|
};
|
|
|
|
const stop = function(provision) {
|
|
|
|
if ( provision.status !== "provisioning" ) {
|
|
console.log(`Terraform# Stop: provision (${provision._id}) is not provisioning`);
|
|
return {"message": `Won't stop container: provision (${provision._id}) is not provisioning`};
|
|
}
|
|
|
|
const name = `qmi-tf-apply-${provision._id}`;
|
|
|
|
console.log(`Terraform# Stop: will try to stop container: ${name}`);
|
|
|
|
return docker.listContainers().then(function(containers) {
|
|
|
|
var containerID;
|
|
|
|
for (let i=0;i<containers.length;i++) {
|
|
if ( containers[i].Names && containers[i].Names.length ) {
|
|
//console.log(`Terraform# Stop: debug container Names: ${containers[i].Names[0]}`);
|
|
if ( containers[i].Names[0] === ("/"+name) ) {
|
|
console.log(`Terraform# Stop: container found: ${name}`);
|
|
containerID = containers[i].Id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( containerID ) {
|
|
console.log(`Terraform# Stop: stopping container: ${name} with ID ${containerID}`);
|
|
return docker.getContainer(containerID).kill().then(function(){
|
|
console.log(`Terraform# Stop: container stopped!!: ${name}`);
|
|
return {"message": `container ${name} stopped`}
|
|
});
|
|
} else {
|
|
console.log(`Terraform# Stop: container ${name} not found!`);
|
|
return {"message": `container ${name} not found`};
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
module.exports.init = init;
|
|
module.exports.plan = plan;
|
|
module.exports.apply = apply;
|
|
module.exports.destroy = destroy;
|
|
module.exports.outputs = outputs;
|
|
module.exports.stop = stop; |