Skip to content

Commit

Permalink
Merge pull request #1091 from tfxor/feature/added_new_feature
Browse files Browse the repository at this point in the history
Feature/added new feature and fixed issue #550
  • Loading branch information
eistrati authored Oct 19, 2021
2 parents 03116b0 + 17a1875 commit 0553e9b
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 17 deletions.
1 change: 1 addition & 0 deletions docs/commands/apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ this command will run `terraform apply` across multiple terrahub components
Options:
--auto-approve, -y Auto approve terraform execution
--refresh-only, -R Use Refresh-Only Mode to Sync Terraform State
--include, -i List of components to include (comma separated values)
--exclude, -x List of components to exclude (comma separated values)
--include-regex, -I List of components to include (regex search)
Expand Down
12 changes: 11 additions & 1 deletion src/commands/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ class ApplyCommand extends DistributedCommand {
this
.setName('apply')
.setDescription('run distributedly `terraform apply` across multiple terrahub components')
.addOption('auto-approve', 'y', 'Auto approve terraform execution', Boolean, false);
.addOption('auto-approve', 'y', 'Auto approve terraform execution', Boolean, false)
.addOption('refresh-only', 'R', 'Use Refresh-Only Mode to Sync Terraform State', Boolean, false);
}

/**
* @returns {Promise}
*/
async run() {
const config = this.getFilteredConfig();
this._refreshOnly = this.getOption('refresh-only');

this.checkDependencies(config);

Expand All @@ -28,6 +30,14 @@ class ApplyCommand extends DistributedCommand {
throw new Error('Action aborted');
}

if (this._refreshOnly) {
return [{
actions: ['workspaceSelect', 'plan', 'applyRefreshOnly'],
config,
dependencyDirection: Dictionary.DIRECTION.FORWARD
}];
}

return [{
actions: ['workspaceSelect', 'plan', 'apply'],
config,
Expand Down
4 changes: 2 additions & 2 deletions src/config-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ class ConfigLoader {
return {
terraform: {
var: {},
varFile: [],
varFile: ['default.tfvars'],
backend: {},
version: '0.14.5',
version: '1.0.9',
backup: false,
workspace: 'default',
},
Expand Down
18 changes: 15 additions & 3 deletions src/helpers/distributors/distributor.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ class Distributor {

if (config.build && config.build.env && config.build.env.variables) {
Object.entries(config.build.env.variables)
.filter((element) => element[1] !== '' && typeof element[1] === 'string')
.filter((element) => element[1] !== '' && typeof element[1] === 'string' && !this._isJSON(element[1]))
.forEach((element) => {
element[1] = this._replaceEnv(config.build.env.variables, element[1]);
const stdout = execSync(`echo "${element[1]}"`);
Expand All @@ -360,7 +360,7 @@ class Distributor {

if (config.project.env && config.project.env.variables) {
Object.entries(config.project.env.variables)
.filter((element) => element[1] !== '' && typeof element[1] === 'string')
.filter((element) => element[1] !== '' && typeof element[1] === 'string' && !this._isJSON(element[1]))
.forEach((element) => {
element[1] = this._replaceEnv(config.project.env.variables, element[1]);
const stdout = execSync(`echo "${element[1]}"`);
Expand All @@ -376,7 +376,7 @@ class Distributor {

if (config.processEnv) {
Object.entries(config.processEnv)
.filter((element) => element[1] !== '' && typeof element[1] === 'string')
.filter((element) => element[1] !== '' && typeof element[1] === 'string' && !this._isJSON(element[1]))
.forEach((element) => {
element[1] = this._replaceEnv(config.processEnv, element[1]);
const stdout = execSync(`echo "${element[1]}"`);
Expand Down Expand Up @@ -418,6 +418,18 @@ class Distributor {
}
}

/**
* @param {String} str
* @return {boolean}
*/
_isJSON(str) {
try {
return (JSON.parse(str.replaceAll('=', ':')) && !!str.replaceAll('=', ':'));
} catch (e) {
return false;
}
}

/**
* @param {String} importLines
* @return {Promise}
Expand Down
53 changes: 42 additions & 11 deletions src/helpers/wrappers/terraform.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ class Terraform {
*/
_varFile() {
const result = [];
this._tf.varFile.push(`${this._config.terraform.workspace}.tfvars`);
const uSet = new Set(this._tf.varFile);

this._tf.varFile.forEach(fileName => {
uSet.forEach(fileName => {
const varFile = path.join(this._metadata.getRoot(), fileName);

if (fs.existsSync(varFile)) {
Expand Down Expand Up @@ -302,13 +304,13 @@ class Terraform {
* @return {Promise}
*/
plan() {
const options = { '-out': this._metadata.getPlanPath(), '-input': false };
const options = { '-out': this._metadata.getPlanPath(), '-input': false, '-lock': false };
const args = process.env.planDestroy === 'true' ? ['-no-color', '-destroy'] : ['-no-color'];
const { providerId } = process.env;
if (providerId) {
const { targets } = this._config;
if (targets.length) {
Object.assign(options, { '-target': `${targets[providerId]}`, '-lock': false });
Object.assign(options, { '-target': `${targets[providerId]}` });
}
}

Expand Down Expand Up @@ -342,12 +344,24 @@ class Terraform {
fse.outputFileSync(backupPath, planContent);
}

return Promise.resolve({
buffer: buffer,
skip: skip,
metadata: metadata,
status: Dictionary.REALTIME.SUCCESS
});
if (!skip) {
return Promise.resolve({
buffer: buffer,
skip: skip,
metadata: metadata,
status: Dictionary.REALTIME.SUCCESS
});
}

return this.run('refresh', args.concat(this._varFile(), this._var()))
.then(() => {
return Promise.resolve({
buffer: buffer,
skip: skip,
metadata: metadata,
status: Dictionary.REALTIME.SUCCESS
});
});
});
}

Expand Down Expand Up @@ -485,13 +499,30 @@ class Terraform {
apply() {
const backupPath = this._metadata.getStateBackupPath();
fse.ensureFileSync(backupPath);
const options = { '-backup': backupPath, '-auto-approve': true, '-input': false };

const options = {
'-backup': backupPath, '-auto-approve': true, '-input': false, '-lock': false
};

return this.run('apply', ['-no-color'].concat(this._optsToArgs(options), this._metadata.getPlanPath()))
.then(() => this._getStateContent())
.then(buffer => ({ buffer: buffer, status: Dictionary.REALTIME.SUCCESS }));
}

/**
* https://www.terraform.io/docs/commands/apply.html
* @return {Promise}
*/
applyRefreshOnly() {
const options = {
'-lock': false
};

return this.run('apply', ['-refresh-only'].concat(this._optsToArgs(options), this._metadata.getPlanPath()))
.then(() => this._getStateContent())
.then(buffer => ({ buffer: buffer, status: Dictionary.REALTIME.SUCCESS }));
}

/**
* Get state content whether is remote or local
* @return {Promise}
Expand All @@ -516,7 +547,7 @@ class Terraform {
* @return {Promise}
*/
refresh() {
const options = { '-backup': this._metadata.getStateBackupPath(), '-input': false };
const options = { '-backup': this._metadata.getStateBackupPath(), '-input': false, '-lock': false };

const localBackend = [];
const { template } = this._config;
Expand Down
6 changes: 6 additions & 0 deletions src/templates/help/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
"description": "Auto approve terraform execution",
"defaultValue": false
},
{
"name": "refresh-only",
"shortcut": "R",
"description": "Use Refresh-Only Mode to Sync Terraform State",
"defaultValue": false
},
{
"name": "include",
"shortcut": "i",
Expand Down

0 comments on commit 0553e9b

Please sign in to comment.