The Open Construct Foundation

OCF

Command Line Arguments

2019-11-12command line Matthew Bonig

Command Line Arguments

CDK modules are just normal language apps that happen to do something specific. However, since you’re typically going to synthesize your constructs using cdk synth command. This does not allow you to directly pass any build parameters from your CLI to your code. There are two workarounds though:

Use Context Variables

Context variables allow you to define variables that are accessible at runtime. More info can be found on AWS’s Developer Guide. The usage looks something like this:

$ cdk synth -c some_variable=some_value

The some_variable is available from within a Stack or Construct using the .tryGetContext() method:

const some_variable = this.node.tryGetContext('some_variable');
console.log(some_variable); // some_value

You can also supply context variables via the cdk.json file:

{
  "context": {
    "some_variable": "some_value"
  }
}

Environment Variables

The one drawback to context variables is that they’re not available outside of the CDK API. They’re only exposed on the underlying node object in a construct.

If you want values to be accessible outside of a CDK construct, you can use environment variables as well:

$ SOME_VARIABLE=some_value cdk synth

and then inside of your code (but not inside of a CDK construct):

const some_variable = process.env["SOME_VARIABLE"];
console.log(some_variable); // some_value

Lots of data

But what happens when you need to be able to provide more than just a few variables. Environment variables and context variables don’t scale particularly well:

$ cdk synth -c database_1_type="db.m5.large" -c database_1_engine="mysql" -c database_1_type="db.r5.xlarge" -c database_1_engine="postgres"

This isn’t going to work well if you have to define 10 databases.

Instead, all of this information can be put into a json file (or similar) and parsed by your application code:

[
    {"engine":  "mysql", "class":  "db.m5.large"},
    {"engine":  "postgres", "class":  "db.r5.xlarge"}
]

These variables would just be loaded at runtime and passed to the construct:

const dbDefinitions = require('./dbs.json');
new MyDatabasesStack(app, 'so-many-dbs', dbDefinitions);

But this isn’t very interesting. What if you need to reuse this stack across multiple projects?

That’s fine! Just use an environment variable to define the file to open:

$ DBS_FILE=someproject.json cdk synth

And:

const projectFile = process.env["DBS_FILE"];
if (!projectFile) {
    throw new Error("Please provide a DBS_FILE to use");
}
const dbDefinitions = require(projectFile);
new MyDatabaseStack(app, 'so-many-dbs', dbDefinitions);

Choose which pattern is going to work best for you.