Skip to content

Commit

Permalink
Merge pull request #12 from Pararius/second-attempt-workspaces
Browse files Browse the repository at this point in the history
Implemented variables, workspace and destroy with minimized changes
  • Loading branch information
cleentfaar authored Nov 12, 2021
2 parents ae907eb + bad1168 commit 9d14556
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea
node_modules/
10 changes: 10 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ inputs:
required: false
description: Whether to run `terraform apply` as last step
default: 'false'
terraform_do_destroy:
required: false
description: Whether to run `terraform destroy` (`terraform_do_apply` and `terraform_do_destroy` can not both be true)
default: 'false'
terraform_lock:
required: false
description: Whether to (try to) lock the state during plan/apply
Expand All @@ -21,6 +25,12 @@ inputs:
required: false
description: Limit the number of concurrent operations during plan/apply
default: '10'
terraform_variables:
required: false
description: 'A JSON string containing variables that should be passed to terraform. For example: {"my_var": "my_value"}'
terraform_workspace:
required: false
description: The name of the workspace that resources should be applied in
runs:
# node16 not available
# https://github.com/actions/runner/issues/772
Expand Down
112 changes: 106 additions & 6 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5240,15 +5240,22 @@ async function terraform(args) {

(async () => {
const terraformDirectory = core.getInput('terraform_directory');
let terraformDoApply = core.getInput('terraform_do_apply');
let terraformDoApply = core.getInput('terraform_do_apply') === 'true';
let terraformDoDestroy = core.getInput('terraform_do_destroy') === 'true';
const terraformLock = core.getInput('terraform_lock');
const terraformParallelism = core.getInput('terraform_parallelism');
const terraformVariables = core.getInput('terraform_variables');
const terraformWorkspace = core.getInput('terraform_workspace');

let tf_version = '<unknown>';
let tf_init = status_skipped;
let tf_fmt = status_skipped;
let tf_plan = status_skipped;
let tf_apply = status_skipped;
let tf_destroy = status_skipped;
let tf_workspace_selection = status_skipped;
let tf_workspace_creation = status_skipped;
let tf_workspace_deletion = status_skipped;

core.startGroup('Sanity checking inputs');
if (terraformLock !== 'true' && terraformLock !== 'false') {
Expand All @@ -5259,6 +5266,10 @@ async function terraform(args) {
core.setFailed(`Sanity checks failed. Non-integer value for 'terraform_parallelism': ${terraformParallelism}`);
process.exit(1);
}
if (terraformDoApply === true && terraformDoDestroy === true) {
core.setFailed('Sanity checks failed. Can\'t apply AND destroy in the same action');
process.exit(1);
}
core.info('Good to go!');
core.endGroup();

Expand Down Expand Up @@ -5287,7 +5298,7 @@ async function terraform(args) {
if (tfv.status > 0) {
core.info(`status: ${tfv.status}`);
core.setFailed(`Failed to determine terraform version [err:${tfv.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_version = tfv.stdout.replace(/\r?\n|\r/g, ' ').match(/ v([0-9]+\.[0-9]+\.[0-9]+) /)[1];
}
Expand All @@ -5298,11 +5309,61 @@ async function terraform(args) {
if (tfi.status > 0) {
tf_init = status_failed;
core.setFailed(`Failed to initialize terraform [err:${tfi.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_init = status_success;
}

/* VARIABLES START */
core.startGroup('Assign terraform variables');
if (terraformVariables) {
const variables = JSON.parse(terraformVariables);
for (let key in variables) {
if (Object.prototype.hasOwnProperty.call(variables, key)) {
process.env[`TF_VAR_${key}`] = variables[key];
core.info(`Assigned variable ${key} with value ${variables[key]}`);
}
}
} else {
core.info('No variables to assign');
}
core.endGroup();
/* VARIABLES END */

/* WORKSPACE SELECTION START */
core.startGroup('Run terraform workspace selection');
core.startGroup(`Workspace input: ${terraformWorkspace}`);
if (terraformWorkspace) {
const tfws = await terraform(['workspace', 'select', terraformWorkspace]);
core.info(tfws.stdout);
core.endGroup();

if (tfws.status > 0) {
tf_workspace_selection = status_failed;

core.startGroup('Failed to select workspace (assuming non-existent), creating workspace...');
const tfwc = await terraform(['workspace', 'new', terraformWorkspace]);
core.info(tfwc.stdout);
core.endGroup();

if (tfwc.status > 0) {
tf_workspace_creation = status_failed;
core.setFailed('Failed to create workspace');

process.exit(1);
} else {
tf_workspace_selection = status_success;
tf_workspace_creation = status_success;
}
} else {
tf_workspace_selection = status_success;
}
} else {
core.info('Skipped');
core.endGroup();
}
/* WORKSPACE SELECTION END */

core.startGroup('Run terraform fmt');
const tffc = await terraform(['fmt', '-check']);
if (tffc.status > 0) {
Expand All @@ -5312,7 +5373,7 @@ async function terraform(args) {
if (tffc.status > 0) {
tf_fmt = status_failed;
core.setFailed(`Failed to pass terraform formatting checks [err:${tffc.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_fmt = status_success;
}
Expand All @@ -5323,13 +5384,13 @@ async function terraform(args) {
if (tfp.status > 0) {
tf_plan = status_failed;
core.setFailed(`Failed to prepare the terraform plan [err:${tfp.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_plan = status_success;
}

core.startGroup('Run terraform apply');
if (terraformDoApply === 'true') {
if (terraformDoApply === true) {
const tfa = await terraform(['apply', `-lock=${terraformLock}`, `-parallelism=${terraformParallelism}`, '-auto-approve', 'terraform.plan']);
core.endGroup();
if (tfa.status > 0) {
Expand All @@ -5342,12 +5403,51 @@ async function terraform(args) {
core.info('Skipped');
core.endGroup();
}

/* DESTROY START */
core.startGroup('Run terraform destroy');
if (terraformDoDestroy === true) {
const tfd = await terraform(['destroy', `-lock=${terraformLock}`, `-parallelism=${terraformParallelism}`, '-auto-approve']);
core.info(tfd.stdout);
core.endGroup();
if (tfd.status > 0) {
tf_destroy = status_failed;
core.setFailed(`Failed to destroy resources [err:${tfd.status}]`);
} else {
tf_destroy = status_success;

if (terraformWorkspace && terraformWorkspace !== 'default') {
core.startGroup('Run terraform workspace deletion');
await terraform(['workspace', 'select', 'default']); // have to switch to different workspace before deleting workspace defined in `terraformWorkspace`
const tfwd = await terraform(['workspace', 'delete', terraformWorkspace]); // have to switch to different workspace before deleting workspace defined in `terraformWorkspace`

core.info(tfwd.stdout);
core.endGroup();

if (tfwd.status > 0) {
tf_workspace_deletion = status_failed;
core.setFailed(`Failed to delete terraform workspace [err:${tfwd.status}]`);
} else {
tf_workspace_deletion = status_success;
}
}
}
} else {
core.info('Skipped');
core.endGroup();
}
/* DESTROY END */

core.info('');
core.info(`Version: ${tf_version}`);
core.info(`Initialization: ${tf_init}`);
core.info(`Formatting: ${tf_fmt}`);
core.info(`Workspace selection: ${tf_workspace_selection}`);
core.info(`Workspace creation: ${tf_workspace_creation}`);
core.info(`Plan: ${tf_plan}`);
core.info(`Apply: ${tf_apply}`);
core.info(`Destroy: ${tf_destroy}`);
core.info(`Workspace deletion: ${tf_workspace_deletion}`);
})().catch(error => {
core.setFailed(error.message);
});
Expand Down
112 changes: 106 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ async function terraform(args) {

(async () => {
const terraformDirectory = core.getInput('terraform_directory');
let terraformDoApply = core.getInput('terraform_do_apply');
let terraformDoApply = core.getInput('terraform_do_apply') === 'true';
let terraformDoDestroy = core.getInput('terraform_do_destroy') === 'true';
const terraformLock = core.getInput('terraform_lock');
const terraformParallelism = core.getInput('terraform_parallelism');
const terraformVariables = core.getInput('terraform_variables');
const terraformWorkspace = core.getInput('terraform_workspace');

let tf_version = '<unknown>';
let tf_init = status_skipped;
let tf_fmt = status_skipped;
let tf_plan = status_skipped;
let tf_apply = status_skipped;
let tf_destroy = status_skipped;
let tf_workspace_selection = status_skipped;
let tf_workspace_creation = status_skipped;
let tf_workspace_deletion = status_skipped;

core.startGroup('Sanity checking inputs');
if (terraformLock !== 'true' && terraformLock !== 'false') {
Expand All @@ -58,6 +65,10 @@ async function terraform(args) {
core.setFailed(`Sanity checks failed. Non-integer value for 'terraform_parallelism': ${terraformParallelism}`);
process.exit(1);
}
if (terraformDoApply === true && terraformDoDestroy === true) {
core.setFailed('Sanity checks failed. Can\'t apply AND destroy in the same action');
process.exit(1);
}
core.info('Good to go!');
core.endGroup();

Expand Down Expand Up @@ -86,7 +97,7 @@ async function terraform(args) {
if (tfv.status > 0) {
core.info(`status: ${tfv.status}`);
core.setFailed(`Failed to determine terraform version [err:${tfv.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_version = tfv.stdout.replace(/\r?\n|\r/g, ' ').match(/ v([0-9]+\.[0-9]+\.[0-9]+) /)[1];
}
Expand All @@ -97,11 +108,61 @@ async function terraform(args) {
if (tfi.status > 0) {
tf_init = status_failed;
core.setFailed(`Failed to initialize terraform [err:${tfi.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_init = status_success;
}

/* VARIABLES START */
core.startGroup('Assign terraform variables');
if (terraformVariables) {
const variables = JSON.parse(terraformVariables);
for (let key in variables) {
if (Object.prototype.hasOwnProperty.call(variables, key)) {
process.env[`TF_VAR_${key}`] = variables[key];
core.info(`Assigned variable ${key} with value ${variables[key]}`);
}
}
} else {
core.info('No variables to assign');
}
core.endGroup();
/* VARIABLES END */

/* WORKSPACE SELECTION START */
core.startGroup('Run terraform workspace selection');
core.startGroup(`Workspace input: ${terraformWorkspace}`);
if (terraformWorkspace) {
const tfws = await terraform(['workspace', 'select', terraformWorkspace]);
core.info(tfws.stdout);
core.endGroup();

if (tfws.status > 0) {
tf_workspace_selection = status_failed;

core.startGroup('Failed to select workspace (assuming non-existent), creating workspace...');
const tfwc = await terraform(['workspace', 'new', terraformWorkspace]);
core.info(tfwc.stdout);
core.endGroup();

if (tfwc.status > 0) {
tf_workspace_creation = status_failed;
core.setFailed('Failed to create workspace');

process.exit(1);
} else {
tf_workspace_selection = status_success;
tf_workspace_creation = status_success;
}
} else {
tf_workspace_selection = status_success;
}
} else {
core.info('Skipped');
core.endGroup();
}
/* WORKSPACE SELECTION END */

core.startGroup('Run terraform fmt');
const tffc = await terraform(['fmt', '-check']);
if (tffc.status > 0) {
Expand All @@ -111,7 +172,7 @@ async function terraform(args) {
if (tffc.status > 0) {
tf_fmt = status_failed;
core.setFailed(`Failed to pass terraform formatting checks [err:${tffc.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_fmt = status_success;
}
Expand All @@ -122,13 +183,13 @@ async function terraform(args) {
if (tfp.status > 0) {
tf_plan = status_failed;
core.setFailed(`Failed to prepare the terraform plan [err:${tfp.status}]`);
terraformDoApply = 'false';
terraformDoApply = false;
} else {
tf_plan = status_success;
}

core.startGroup('Run terraform apply');
if (terraformDoApply === 'true') {
if (terraformDoApply === true) {
const tfa = await terraform(['apply', `-lock=${terraformLock}`, `-parallelism=${terraformParallelism}`, '-auto-approve', 'terraform.plan']);
core.endGroup();
if (tfa.status > 0) {
Expand All @@ -141,12 +202,51 @@ async function terraform(args) {
core.info('Skipped');
core.endGroup();
}

/* DESTROY START */
core.startGroup('Run terraform destroy');
if (terraformDoDestroy === true) {
const tfd = await terraform(['destroy', `-lock=${terraformLock}`, `-parallelism=${terraformParallelism}`, '-auto-approve']);
core.info(tfd.stdout);
core.endGroup();
if (tfd.status > 0) {
tf_destroy = status_failed;
core.setFailed(`Failed to destroy resources [err:${tfd.status}]`);
} else {
tf_destroy = status_success;

if (terraformWorkspace && terraformWorkspace !== 'default') {
core.startGroup('Run terraform workspace deletion');
await terraform(['workspace', 'select', 'default']); // have to switch to different workspace before deleting workspace defined in `terraformWorkspace`
const tfwd = await terraform(['workspace', 'delete', terraformWorkspace]); // have to switch to different workspace before deleting workspace defined in `terraformWorkspace`

core.info(tfwd.stdout);
core.endGroup();

if (tfwd.status > 0) {
tf_workspace_deletion = status_failed;
core.setFailed(`Failed to delete terraform workspace [err:${tfwd.status}]`);
} else {
tf_workspace_deletion = status_success;
}
}
}
} else {
core.info('Skipped');
core.endGroup();
}
/* DESTROY END */

core.info('');
core.info(`Version: ${tf_version}`);
core.info(`Initialization: ${tf_init}`);
core.info(`Formatting: ${tf_fmt}`);
core.info(`Workspace selection: ${tf_workspace_selection}`);
core.info(`Workspace creation: ${tf_workspace_creation}`);
core.info(`Plan: ${tf_plan}`);
core.info(`Apply: ${tf_apply}`);
core.info(`Destroy: ${tf_destroy}`);
core.info(`Workspace deletion: ${tf_workspace_deletion}`);
})().catch(error => {
core.setFailed(error.message);
});

0 comments on commit 9d14556

Please sign in to comment.