My Bref Makefile
In order to use Bref efficiently, I’ve developed a Makefile so that I don’t have to remember all the various commands required. In particular, looking up the correct parameters to sam package & sam deploy is a pain and it’s much easier to type make deploy and it all works as I expect.
It looks like this:
Makefile:
# vim: noexpandtab tabstop=4 filetype=make
.PHONY: list invoke invoke-local deploy outputs lastlog clean clean-all setup
REGION := eu-west-2
PROJECT_NAME := hello-world
UNIQUE_KEY := 1557903576
BUCKET_NAME := $(PROJECT_NAME)-$(UNIQUE_KEY)-brefapp
STACK_NAME := $(PROJECT_NAME)-$(UNIQUE_KEY)-brefapp
# default function to invoke. To override: make invoke FUNCTION=foo
FUNCTION ?= my-function
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
invoke:
vendor/bin/bref --region=$(REGION) invoke $(FUNCTION)
invoke-local:
sam local invoke $(FUNCTION) --no-event
deploy:
sam package \
--region $(REGION) \
--template-file template.yaml \
--output-template-file .stack-template.yaml \
--s3-bucket $(BUCKET_NAME)
-sam deploy \
--region $(REGION) \
--template-file .stack-template.yaml \
--stack-name $(STACK_NAME) \
--capabilities CAPABILITY_IAM
vendor/bin/bref deployment --region $(REGION) $(STACK_NAME)
outputs:
aws --region $(REGION) cloudformation describe-stacks --stack-name $(STACK_NAME) | jq '.Stacks[0]["Outputs"]'
lastlog:
sam logs --region $(REGION) --name $(FUNCTION)
geterror:
vendor/bin/bref deployment --region $(REGION) $(STACK_NAME)
clean:
aws --region $(REGION) cloudformation delete-stack --stack-name $(STACK_NAME)
clean-all: clean
aws --region $(REGION) s3 rb s3://$(BUCKET_NAME) --force
setup:
aws --region $(REGION) s3 mb s3://$(BUCKET_NAME)
There’s three variables that I need to set at the top:
- REGION – The AWS region. This has to match the Bref layer used in template.yaml.
- PROJECT_NAME – The name of the project. This is used as part of the S3 bucket and CloudFormation stack names
- UNIQUE_KEY – A random string to ensure uniqueness for bucket and stack names. I tend to use the current time to the ms, but any string.
I’ve included a full-cycle set of targets so make setup will create the initial S3 bucket that’s required for the project and then make deploy is used to deploy my project.
If I want to start again, make clean will remove the CloudFormation stack and make clean-all will remove the stack and the bucket.
I’ve also included a few utility targets:
- make invoke FUNCTION=foo invokes the function foo on AWS.
- make invoke-local FUNCTION=foo invokes the function foo on sam-local.
- make outputs displays the outputs of the CloudFormation stack. This is useful for picking up the API Gateway URL for instance, if you set it up in your template.yaml.
- make lastlog FUNCTION=foo displays the logs for the last invocation of the function foo.
Parameters for template.yaml
I pass the PROJECT_NAME and UNIQUE_KEY through to the template as the parameters ProjectName and UniqueKey respectively. These are then set in the Parameters section of the template:
template.yaml:
Parameters:
ProjectName:
Type: String
UniqueKey:
Type: String
I then use them in the template when I need uniqueness, such as when creating an S3 bucket:
template.yaml:
Resources:
ImagesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Join [ '-', [!Ref "ProjectName", !Ref "UniqueKey", "files" ] ]
Which creates a bucket named “hello-world-1557903576-files” which nicely complements “hello-world-1557903576-brefapp”.
Hi Rob – thanks for writing this up.
Can you explain why you went with a makefile instead of one or more shell scripts? I see this a lot recently – using make when there are no dependency trees – and don't understand the appeal.
Greg,
Mostly for consistency. I write projects in different languages and different systems and I've found make to integrate well with my editor. There's no reason that this couldn't be a set of composer scripts for instance.