Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing yarn infra terraform command and adding documentation #117

Merged
merged 3 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions workspaces/docs/docs/templates/shared/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Infrastructure commands for this template can be run using `yarn`. There are fou
- `yarn infra plan`: For running [Terraform plan](https://www.terraform.io/docs/commands/plan.html).
- `yarn infra apply`: For running [Terraform apply](https://www.terraform.io/docs/commands/apply.html).
- `yarn infra destroy`: For destroying all infrastructure using [Terraform destroy](https://www.terraform.io/docs/commands/destroy.html).
- `yarn infra upgrade`: For upgrading the Terraform versions (supported by the template). To upgrade to an arbitrary version, use `yarn infra terraform`.
- `yarn infra terraform`: For running arbitrary [Terraform commands](https://www.terraform.io/cli/commands).

For each command, the deployment they should be applied to must be specified.

Expand All @@ -48,6 +50,25 @@ yarn infra up dev

Generally you will only need to run `yarn infra up`. However, if you are familiar with Terraform and want more fine-grained control over the deployment of your infrastructure, you can also use the other commands as required.

Note that for running `yarn infra terraform`, you will need to specify which command line arguments you want to provide to Terraform. By default, no extra arguments are provided:

```bash
yarn infra terraform [deployment] plan
```

If extra arguments are needed, such as variables, you can use the `--inject-variables` option, such as for running `terraform plan`:

```bash
yarn infra terraform [deployment] --inject-variables plan
```

If you want to interact with the remote backend, you can also provide the `--inject-backend-config` option, such as for running `terraform init`:

```bash
yarn infra terraform [deployment] --inject-backend-config init
```


### Customizing Terraform

Goldstack templates make it very easy to customize infrastructure to your specific needs. The easiest way to do this is to simply edit the `*.tf` files in the `infra/aws` folder. You can make the changes you need and then run `yarn infra up [deploymentName]` to apply the changes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const infraAwsDockerImageCli = async (
): Promise<void> => {
if (args.length < 1) {
throw new Error(
'Please provide the operation in the arguments: "init", "plan", "apply", "deploy", "destroy".'
'Please provide the operation in the arguments: "up", "init", "plan", "apply", "deploy", "destroy", "upgrade", "terraform".'
);
}
const [operation] = args;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const infraAwsStaticWebsiteCli = async (
): Promise<void> => {
if (args.length < 1) {
fatal(
'Please provide the operation in the arguments: "init", "plan", "apply", "deploy", "destroy".'
'Please provide the operation in the arguments: "up", "init", "plan", "apply", "deploy", "destroy", "upgrade", "terraform".'
);
throw new Error();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const buildCli = (params: BuildCliParams): Argv<any> => {
.scriptName('template')
.usage('$0 <infra|deploy>')
.command(
'infra <up|down|init|plan|apply|destroy> <deployment>',
'infra <up|down|init|plan|apply|destroy|upgrade|terraform> <deployment>',
'Manage infrastructure for deployment',
params.infraCommands
)
Expand Down
27 changes: 25 additions & 2 deletions workspaces/templates-lib/packages/utils-sh/src/utilsSh.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execSync, exec as processAsync } from 'child_process';
import { execSync, execFileSync, exec as processAsync } from 'child_process';
import fs from 'fs';
import ncp from 'ncp';

Expand Down Expand Up @@ -262,6 +262,29 @@ const exec = (cmd: string, params?: ExecParams): string => {
}
};

const execSafe = (
file: string,
args: string[],
params?: ExecParams
): string => {
try {
const res = execFileSync(file, args);
if (!params?.silent) {
console.log(res.toString());
}
return res.toString();
} catch (e) {
console.error('Command failed:', file, args);
if (e.stderr) {
console.error(e.stderr.toString());
}
if (e.stdout) {
console.log(e.stdout.toString());
}
throw e;
}
};

export const execAsync = async (
cmd: string,
params?: ExecParams
Expand Down Expand Up @@ -303,4 +326,4 @@ const commandExists = (command: string): boolean => {
return res !== null;
};

export { exec, pwd, read, write, cd, globSync, commandExists };
export { exec, execSafe, pwd, read, write, cd, globSync, commandExists };
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,11 @@ export class TerraformBuild {
};

private getTfVersion = (args: string[]): TerraformVersion => {
const deployment = getDeployment(args);
if (deployment.tfVersion) {
return deployment.tfVersion;
if (args.length > 0) {
const deployment = getDeployment(args);
if (deployment.tfVersion) {
return deployment.tfVersion;
}
}
if (fs.existsSync('./infra/tfConfig.json')) {
try {
Expand Down Expand Up @@ -511,6 +513,47 @@ export class TerraformBuild {
);
};

terraform(opArgs: string[]): void {
const provider = this.provider;
const deployment = getDeployment(opArgs);
const version = this.getTfVersion(opArgs);

let backendConfig: [string, string][] | undefined;

if (opArgs.find((arg) => arg === '--inject-backend-config')) {
backendConfig = this.getTfStateVariables(deployment);
}

let variables: [string, string][] | undefined;

cd('./infra/aws');
try {
if (opArgs.find((arg) => arg === '--inject-variables')) {
variables = [
...getVariablesFromHCL({
...deployment,
...deployment.configuration,
}),
];
}
tf(`workspace select ${opArgs[0]}`, { provider, version });
const remainingArgs = opArgs
.slice(1)
.filter(
(arg) =>
arg !== '--inject-backend-config' && arg !== '--inject-variables'
);
tf(remainingArgs.join(' '), {
provider,
backendConfig,
version,
variables,
});
} finally {
cd('../..');
}
}

constructor(provider: CloudProvider) {
assert(provider);
this.provider = provider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { exec, pwd, commandExists } from '@goldstack/utils-sh';
import { exec, execSafe, pwd, commandExists } from '@goldstack/utils-sh';
import {
assertDocker,
hasDocker,
Expand Down Expand Up @@ -61,16 +61,23 @@ const execWithDocker = (cmd: string, options: TerraformOptions): string => {
workspaceEnvVariable = `-e TF_WORKSPACE=${options.workspace}`;
}

const cmd3 =
`docker run --rm -v "${options.dir}":/app ` +
` ${options.provider.generateEnvVariableString()} ${workspaceEnvVariable} ` +
'-w /app ' +
`${imageTerraform(options.version)} ${cmd} ` +
` ${renderBackendConfig(options.backendConfig || [])} ` +
` ${renderVariables(options.variables || [])} ` +
` ${options.options?.join(' ') || ''} `;

return exec(cmd3, { silent: options.silent });
const args = [
'run',
'--rm',
'-v',
`${options.dir}:/app`,
...options.provider.generateEnvVariableString().split(' '),
workspaceEnvVariable,
'-w',
'/app',
imageTerraform(options.version),
...cmd.split(' '),
renderBackendConfig(options.backendConfig || []),
renderVariables(options.variables || []),
...(options.options ?? []),
].filter((o) => o);

return execSafe('docker', args, { silent: options.silent });
};

export const assertTerraform = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ export const infraCommands = (): any => {
demandOption: true,
});
}
)
.command(
'terraform <deployment> [command..]',
'Runs an arbitrary Terraform CLI command',
(yargs) => {
return deploymentPositional(yargs)
.option('inject-variables', {
description: 'Injects variables into the Terraform CLI command.',
default: false,
type: 'boolean',
demandOption: false,
})
.option('inject-backend-config', {
description:
'Injects backend config into the Terraform CLI command.',
default: false,
type: 'boolean',
demandOption: false,
});
}
);
};
};
Expand Down Expand Up @@ -111,6 +131,10 @@ export const terraformCli = (
build.upgrade(opArgs);
return;
}
if (operation === 'terraform') {
build.terraform(opArgs);
return;
}

throw new Error('Unknown infrastructure operation: ' + operation);
};