Using Jinja2 to play with Template Engine

Imagine the scenario, we want to create multiple S3 buckets using the Cloudformation block below:

1
2
3
4
5
6
7
# template.yml
Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: my-bucket-1

But we don’t want to repeat and hardcode values inside the manifest, one alternative is using a template engine to allow variables and loops to generate the final manifest.

For example, we will use Jinja2 Template Engine with a CLI tool named Jinja2 CLI to be easy to execute the templates.

$ python3 -m venv venv $ source venv/bin/activate $ pip3 install jinja2-cli

Now is possible to create a jinja2 template with a parametrized name variable following Jinja2 Syntax:

1
2
3
4
5
6
7
# template.j2
Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: {{ name }}

And with our dependencies installed, we can execute it to render the template.

1
$ jinja2 template.j2 -D name=my-api-bucket

The output was a rendered template with my-api-bucket, But if we want to create 5 different buckets ? First, we will define our variables in a JSON file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# names.json
{
  "names": [
    "backend-s3",
    "nextjs",
    "landpage",
    "blog",
    "reports"
  ]
}

And create a jinja2 template with a for loop to iterate through the list creating an S3 block for each name:

1
2
3
4
5
6
7
8
9
# template.j2
Resources:
{% for item in names %}
  {{ item }}:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: {{ item }}
{% endfor %}

Below is the command to render the template passing a JSON file with variables:

1
$ cat names.json | jinja2 template.j2 

With that, we can receive the output for our final manifest.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Resources:

  backend-s3:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: backend-s3

  nextjs:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: nextjs

  landpage:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: landpage

  blog:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: blog

  reports:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: reports

With this simple case, we saw how to use jinja2-cli to iterate to generate dynamic configuration and declarative files.