Templates¶
Sceptre uses CloudFormation Templates to launch AWS Stacks. Templates must be
stored in a directory named templates/
, in the same directory as the
config/
directory:
.
├── config
│ └── dev
│ ├── config.yaml
│ └── vpc.yaml
└── templates
└── vpc.py
CloudFormation¶
Templates with .json
or .yaml
extensions are treated as CloudFormation
Templates. They are read in and used without modification.
Jinja¶
Templates with .j2
extensions are treated as Jinja2 Templates.
These are rendered and should create a raw JSON or YAML CloudFormation
Template. Sceptre User Data is accessible within Templates as
sceptre_user_data
. For example {{ sceptre_user_data.some_variable }}
.
sceptre_user_data
accesses the sceptre_user_data
key in the Stack
Config file.
Example¶
While rendering templates with Jinja2, some characters aren’t supported by AWS. A workaround for this is to use Jinja to replace -, . and _ with other characters to ensure that we produce a valid template. With this we had some plasticity to the template and it becomes easier to add/remove entries on a particular stack.
With this templating some problems will arise, such empty strings as parameters. In the following example you can find a work around for this issues.
This represents a stack to deploy route53 records, it’s only showing CNAME and ALIAS records to not get too large.
Stack:
template
path: templates/dns-extras.j2
type: file
dependencies:
- prod/route53/domain-zone.yaml
parameters:
DomainName: "example.com"!stack_output prod/route53/example-com-zone.yaml::FullDomainName
Zone: !stack_output prod/route53/example-com-zone.yaml::HostedZoneID
sceptre_user_data:
CNAMErecords:
- record: "example01"
address: "example01.otherdomain.com."
ttl: 600
- record: "example02"
address: "example01.otherdomain.com."
ttl: 600
ALIASrecords:
- record: ""
hostedzoneid: "ZYOURZONEIDDDD"
dnsnamealias: "ELB07-Sites-000000000.us-east-1.elb.amazonaws.com"
ttl: 600
- record: "www"
hostedzoneid: "Z32O12XQLNTSW2"
dnsnamealias: "ELB07-Sit es-000000000.us-east-1.elb.amazonaws.com"
ttl: 600
Template dns-extras.j2:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Add Route53 - CNAME and ALIAS records'
Parameters:
DomainName:
Type: String
Default: example.net
Zone:
Type: String
{% if sceptre_user_data.CNAMErecords is defined %}{% for rule in sceptre_user_data.CNAMErecords %}
{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}cnamerecord:
Type: String
Default: "{{rule.record}}"{% endfor %}{% endif %}
{% if sceptre_user_data.ALIASrecords is defined %}{% for rule in sceptre_user_data.ALIASrecords %}
{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}aliasrecord:
Type: String
Default: "{{rule.record}}"
{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}aliasvalue:
Type: String
Default: "{{rule.dnsnamealias}}"
{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}aliaszoneid:
Type: String
Default: "{{rule.hostedzoneid}}"
{% endfor %}{% endif %}
Resources:
{% if sceptre_user_data.CNAMErecords is defined %}{% for rule in sceptre_user_data.CNAMErecords %}add{{ rule.record | replace("-","d")|replace("_","s")|replace('.',"p")}}cnamerecord:
{% set record = rule.record %}
Type: 'AWS::Route53::RecordSet'
Properties:
Name: !Join
- ""
- [ !Sub '${ {{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}cnamerecord }','.', !Ref DomainName, '.']
HostedZoneId: !Sub '${Zone}'
Type: CNAME
TTL: {{ rule.ttl }}
ResourceRecords:
- {{ rule.address }}
{% endfor %}{% endif %}
{% if sceptre_user_data.ALIASrecords is defined %}{% for rule in sceptre_user_data.ALIASrecords %}
{% set entry = rule.record |replace("-","d")|replace("_","s")|replace('.',"p")%}add{{entry}}aliasrecord:
Type: AWS::Route53::RecordSet
Properties:
{% if rule.record == "" %}
Name: !Ref DomainName
{% else %}
Name: !Join
- ""
- [ !Sub '${ {{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}aliasrecord }','.', !Ref DomainName, '.']
{% endif %}
Type: A
HostedZoneId: !Ref Zone
AliasTarget:
DNSName: "{{ rule.dnsnamealias }}"
HostedZoneId: "{{ rule.hostedzoneid }}"
{% endfor %}{% endif %}
Outputs:
{% if sceptre_user_data.CNAMErecords is defined %}{% for rule in sceptre_user_data.CNAMErecords %}add{{ rule.record | replace("-","d")|replace("_","s")|replace('.',"p")}}cnamerecord:
Value: !Ref 'add{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}cnamerecord'
Description: '{{ rule.address }}'
{% endfor %}{% endif %}
{% if sceptre_user_data.ALIASrecords is defined %}{% for rule in sceptre_user_data.ALIASrecords %}add{{ rule.record | replace("-","d")|replace("_","s")|replace('.',"p")}}aliasrecord:
Value: !Ref 'add{{ rule.record |replace("-","d")|replace("_","s")|replace('.',"p")}}aliasrecord'
Description: '{{ rule.dnsnamealias }}'
{% endfor %}{% endif %}
StackName:
Description: 'Stack name.'
Value: !Sub '${AWS::StackName}'
Export:
Name: !Sub '${AWS::StackName}'
Python¶
Templates with a .py
extension are treated as Python Templates. They should
implement a function named sceptre_handler(sceptre_user_data)
which returns
the CloudFormation Template as a string
. Sceptre User Data is passed to
this function as an argument. If Sceptre User Data is not defined in the Stack
Config file, Sceptre passes an empty dict
.
Example¶
Troposphere¶
This example is using troposphere to generate CloudFormation Template as a json string.
from troposphere import Template
from troposphere.ec2 import VPC
def vpc(sceptre_user_data):
"""AWS VPC CloudFormationTemplate"""
template = Template()
template.add_resource(VPC(
"VirtualPrivateCloud",
CidrBlock=sceptre_user_data["cidr_block"]
))
return template.to_yaml()
def sceptre_handler(sceptre_user_data):
return vpc(sceptre_user_data)
Note
To generate templates using Troposphere you must install the
Troposphere library by running pip install sceptre[troposphere]
AWS CDK¶
AWS CDK can be used to programmatically generate templates for your stacks and then Sceptre can deploy those stacks. Taking this approach leverages the best capabilities of CDK (simple template generation with sane defaults) and the best capabilities of Sceptre (“wiring together” stacks and deploying them as consistent environments, leveraging hooks and resolvers to dynamically connect them).
In order to use CDK with Sceptre, you need to install the sceptre_cdk_handler package. You can find documentation and examples on how to use it on the github repository.
AWS SAM¶
There is now a SAM Template Handler that lets you incorporate SAM templates into environments that are managed and deployed using Sceptre. For more information on how to install and use SAM in your Sceptre project, see the sceptre-sam-handler page on PyPI.