Old Styled Parameter

Unlike writing in JSON and YAML Cloudformation Template, you can leverage the built-in control flow, if else condition, for loop iteration in Python. Sometimes the value of Parameter can be used as a factor in control flow, however the value is not avaialble yet in Template Declaration phase. Because people usually pass in value to Parameter after the full Template is declared.

In cottonformation, there’s a best practice called Late Template Creation for this Situation. In this example, we declared a comma delimitered string parameter called Parameter(AllGroup, ...). It is the list IAM Group name you want to create. The number of IAM Group Resource to declare should equal to number of item in this Parameter.

Parameter has two method that allow to “set” value for template creation and “get” value for future use. You can firstly declare all Parameter, give them values, and eventually execute the Template generation logic.

# -*- coding: utf-8 -*-

import typing

import cottonformation as ctf
from cottonformation.res import iam


# declare multiple Parameter
# use one data container class to organize everything
class Params:
    env_name: ctf.Parameter = ctf.Parameter("EnvName", Type=ctf.Parameter.TypeEnum.String)
    all_group: ctf.Parameter = ctf.Parameter("AllGroup", Type=ctf.Parameter.TypeEnum.CommaDelimitedList)


# declare a function that creates Template object from Parameters, Mappings,
# Conditions, Rules ...
# In this example, parameters data container class is the only argument
# But you could use mapping container class, condition container class too
def create_template(params: typing.Type[Params]) -> ctf.Template:
    tpl = ctf.Template(Description="Demo: ctf styled parameter")

    # add all parameter declaration to template
    tpl.add(params.env_name)
    tpl.add(params.all_group)

    # create many iam users based on the list data in parameter all_user_email
    for group_name in params.all_group.get_value().split(","):
        iam_group = iam.Group(
            f"IamGroup{group_name}",
            p_GroupName=group_name,
        )
        tpl.add(iam_group)

    # tag everything using parameter env_name
    tpl.batch_tagging(dict(EnvName=params.env_name.ref()))

    return tpl


if __name__ == "__main__":
    # give values to parameters before the creation of Template
    Params.env_name.set_value("ctf-old-style-param")

    all_group_values = [
        "Developer",
        "DevOps",
        "Manager",
    ]
    Params.all_group.set_value(",".join(all_group_values))

    # now generate the template base on the parameter value
    tpl = create_template(Params)
    print(tpl.to_json())

    # my private aws account session and bucket for testing
    from cottonformation.tests.boto_ses import bsm, bucket

    env = ctf.Env(bsm=bsm)
    env.deploy(
        template=tpl,
        stack_name=Params.env_name.get_value(),
        # helper method gives you the python dict view of parameter id and value
        stack_parameters=tpl.get_param_values(),
        bucket_name=bucket,
        include_iam=True,
    )

Template json:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Demo: ctf styled parameter",
    "Metadata": {
        "cottonformation": {
            "version": "0.0.3"
        }
    },
    "Parameters": {
        "EnvName": {
            "Type": "String"
        },
        "AllGroup": {
            "Type": "CommaDelimitedList"
        }
    },
    "Resources": {
        "IamGroupDeveloper": {
            "Type": "AWS::IAM::Group",
            "Properties": {
                "GroupName": "Developer"
            }
        },
        "IamGroupDevOps": {
            "Type": "AWS::IAM::Group",
            "Properties": {
                "GroupName": "DevOps"
            }
        },
        "IamGroupManager": {
            "Type": "AWS::IAM::Group",
            "Properties": {
                "GroupName": "Manager"
            }
        }
    }
}