lova
lova

Reputation: 879

AWS Cloudformation: how to manage relationship between configtemplate and environment?

I have a configtemplate which describes things I want in my environment. For example:

OptionSettings:
- Namespace: aws:autoscaling:asg
  OptionName: MinSize
  Value: 1

I use this in my environment (templatename):

appEnvironment:
  Type: AWS::ElasticBeanstalk::Environment
  Properties:
    EnvironmentName: xx
    ApplicationName: xx
    TemplateName: !Ref appConfiguration
    VersionLabel: xx

It works well. But now I need to add a new optionsetting which contains the URL of the environment:

- Namespace: aws:elasticbeanstalk:application:environment
    OptionName: URL
    Value: !GetAtt appEnvironment.EndpointURL

But this does not work because now I have a dependency on environment and environment has a dependency on template.

Can someone explain to me how to handle this properly in one template? I can't imagine there aren't others who are facing this problem.

Thanks

Upvotes: 0

Views: 248

Answers (1)

KayakinKoder
KayakinKoder

Reputation: 3451

This is probably more than you want to get into, but I use build system to handle things like this and hopefully this will help someone. It makes my Cloudformation templates much cleaner, and I highly recommend it. My build system consists of Nunjucks & Gulp

What does that allow me to do? First, I can for example add variables/data to .json files. Lets take a simple example, dev and prod having two different endpoints. I would create these two files:

data-dev.json

{
   "url": "my-dev-endpoint.com"
}

data-prod.json

{
   "url": "my-prod-endpoint.com"
}

configtemplate

- Namespace: aws:elasticbeanstalk:application:environment
    OptionName: URL
    Value: {{ url }}

{{ url }} is a Nujucks variable; if you aren't familiar with Nunjucks, you could use any templating system (Handlebars, Mustache, etc.) although Nunjucks is the most fully featured in my experience. Now all we need to do is create a build script which will get our url value from either data-dev.json or data-prod.json, and replace {{ url }} in our configtemplate with the value from our .json file.

This is where Gulp comes in. This should get you started if you aren't familiar with Gulp; it's quite simple to learn, in a day or so you should be able to get things going:

gulpfile.js

const gulp = require('gulp');
const nunjucksRender = require('gulp-nunjucks-render');
const data = require('gulp-data');
const fs = require('fs');

gulp.task('default', function(){
    return gulp.src(['src'])
        .pipe(data(function() {
            return JSON.parse(fs.readFileSync('./dev-data.json'))
        }))
        .pipe(nunjucksRender({path: ['src/nunjucks']}))
        .pipe(gulp.dest('dist'));
});

gulp.src(['src']) defines where your source configtemplate file is; in this example, it's a folder named src. ./data-dev.json is our data file, so this gulp task will replace {{ url }} with my-dev-endpoint.com (you'll write another gulp task to for data-prod.json). nunjucksRender({path: ['src/nunjucks']}) is a path to a folder, in this case it can be empty (more info below on what you could put in this folder). gulp.dest('dist') defines the location of where you want the output to go, in this case a /dist folder.

If you have the time to get into this, it is well worth it in the long run. Nunjucks is a templating system, which is what it sounds like; more than injecting data like we did in this example, you can create templates for oft used code. In CF I use this chunk quite often (note that I use .json not yaml; that detail is irrelevant):

{
    "Namespace": "the-namespace",
    "OptionName": "the-option",
    "Value": "the-value"
}

Instead of writing that dozens of times, I put it in a template my-template.nunjucks; following the example above, this template would go in a folder: src/nunjucks. Then whenever I need this chunk of code in a CF template, I can just do this one liner:

{% include "my-template.nunjucks" %}

Putting it all together

configtemplate source file:

- Namespace: aws:elasticbeanstalk:application:environment
    OptionName: URL
    Value: {{ url }}

{% include "my-template.nunjucks" %}

will output

- Namespace: aws:elasticbeanstalk:application:environment
    OptionName: URL
    Value: my-dev-endpoint.com

{
    "Namespace": "the-namespace",
    "OptionName": "the-option",
    "Value": "the-value"
}

(obviously mixing yaml and .json like this makes no sense, it's just an example to show how Nunjucks can be used to include files)

Upvotes: 1

Related Questions