Hooks¶
A hook is a python function or class method that is executed before or after the action is taken. To see how to define hooks in a config file see the Pre & Post Hooks documentation.
Built-in Hooks¶
acm.Certificate¶
Requirements
Route 53 hosted zone
authoritative for the domain the certificate is being created for
in the same AWS account as the certificate being created
Description
Manage a DNS validated certificate in AWS Certificate Manager.
When used in the pre_build or post_build stage this hook will create a CloudFormation stack containing a DNS validated certificate.
It will automatically create a record in Route 53 to validate the certificate and wait for the stack to complete before returning the CertificateArn
as hook data.
The CloudFormation stack also outputs the ARN of the certificate as CertificateArn
so that it can be referenced from other stacks.
When used in the pre_destroy or post_destroy stage this hook will delete the validation record from Route 53 then destroy the stack created during a deploy stage.
If the hook fails during a deploy stage (e.g. stack rolls back or Route 53 can’t be updated) all resources managed by this hook will be destroyed. This is done to avoid orphaning resources/record sets which would cause errors during subsequent runs. Resources effected include the CloudFormation stack it creates, ACM certificate, and Route 53 validation record.
Hook Path
runway.cfngin.hooks.acm.Certificate
Args
- alt_names (Optional[List[str]])
Additional FQDNs to be included in the Subject Alternative Name extension of the ACM certificate. For example, you can add www.example.net to a certificate for which the
domain
field is www.example.com if users can reach your site by using either name.- domain (str)
The fully qualified domain name (FQDN), such as www.example.com, with which you want to secure an ACM certificate. Use an asterisk (
*
) to create a wildcard certificate that protects several sites in the same domain. For example, *.example.com protects www.example.com, site.example.com, and images.example.com.- hosted_zone_id (str)
The ID of the Route 53 Hosted Zone that contains the resource record sets that you want to change. This must exist in the same account that the certificate will be created in.
- stack_name (Optional[str])
Provide a name for the stack used to create the certificate. If not provided, the domain is used (replacing
.
with-
). If the is provided in a deploy stage, its needs to be provided in the matching destroy stage.- ttl (Optional[int])
The resource record cache time to live (TTL), in seconds. (default:
300
)
Example
namespace: example
cfngin_bucket: ''
sys_path: ./
pre_build:
acm-cert:
path: runway.cfngin.hooks.acm.Certificate
required: true
args:
domain: www.example.com
hosted_zone_id: ${rxref example-com::HostedZone}
stack:
sampleapp:
class_path: blueprints.sampleapp.BlueprintClass
variables:
cert_arn: ${rxref www-example-com::CertificateArn}
post_destroy:
acm-cert:
path: runway.cfngin.hooks.acm.Certificate
required: true
args:
domain: www.example.com
hosted_zone_id: ${rxref example-com::HostedZone}
aws_lambda.upload_lambda_functions¶
Description
Build Lambda payloads from user configuration and upload them to S3.
Constructs ZIP archives containing files matching specified patterns for
each function, uploads the result to Amazon S3, then stores objects (of
type troposphere.awslambda.Code
) in the context’s hook data,
ready to be referenced in blueprints.
Configuration consists of some global options, and a dictionary of function specifications. In the specifications, each key indicating the name of the function (used for generating names for artifacts), and the value determines what files to include in the ZIP (see more details below).
If a requirements.txt
or Pipfile/Pipfile.lock
files are found at the root of the provided path
, the hook will use the appropriate method to package dependencies with your source code automatically. If you want to explicitly use pipenv
over pip
, provide use_pipenv: true
for the function.
Docker can be used to collect python dependencies instead of using system python to build appropriate binaries for Lambda.
This can be done by including the dockerize_pip
configuration option which can have a value of true
or non-linux
.
Payloads are uploaded to either a custom bucket or the CFNgin default bucket, with the key containing it’s checksum, to allow repeated uploads to be skipped in subsequent runs.
Hook Path
runway.cfngin.hooks.aws_lambda.upload_lambda_functions
Args
- bucket (Optional[str])
Custom bucket to upload functions to. Omitting it will cause the default CFNgin bucket to be used.
- bucket_region (Optional[str])
The region in which the bucket should exist. If not given, the region will be either be that of the global
cfngin_bucket_region
setting, or else the region in use by the provider.- prefix (Optional[str])
S3 key prefix to prepend to the uploaded zip name.
- follow_symlinks (Optional[bool])
Will determine if symlinks should be followed and included with the zip artifact. (default:
False
)- payload_acl (Optional[str])
The canned S3 object ACL to be applied to the uploaded payload. (default: private)
- functions (Dict[str, Any])
Configurations of desired payloads to build. Keys correspond to function names, used to derive key names for the payload. Each value should itself be a dictionary, with the following data:
- docker_file (Optional[str])
Path to a local DockerFile that will be built and used for
dockerize_pip
. Must provide exactly one ofdocker_file
,docker_image
, orruntime
.- docker_image (Optional[str])
Custom Docker image to use with
dockerize_pip
. Must provide exactly one ofdocker_file
,docker_image
, orruntime
.- dockerize_pip (Optional[Union[str, bool]])
Whether to use Docker when restoring dependencies with pip. Can be set to
true
/false
or the special stringnon-linux
which will only run on non Linux systems. To use this option Docker must be installed.- exclude (Optional[Union[str, List[str]]])
Pattern or list of patterns of files to exclude from the payload. If provided, any files that match will be ignored, regardless of whether they match an inclusion pattern.
Commonly ignored files are already excluded by default, such as
.git
,.svn
,__pycache__
,*.pyc
,.gitignore
, etc.- include (Optional[Union[str, List[str]]])
Pattern or list of patterns of files to include in the payload. If provided, only files that match these patterns will be included in the payload.
Omitting it is equivalent to accepting all files that are not otherwise excluded.
- path (str)
Base directory of the Lambda function payload content. If it not an absolute path, it will be considered relative to the directory containing the CFNgin configuration file in use.
Files in this directory will be added to the payload ZIP, according to the include and exclude patterns. If no patterns are provided, all files in this directory (respecting default exclusions) will be used.
Files are stored in the archive with path names relative to this directory. So, for example, all the files contained directly under this directory will be added to the root of the ZIP file.
- python_path (Optional[str])
Absolute path to a python interpreter to use for
pip
/pipenv
actions. If not provided, the current python interpreter will be used forpip
andpipenv
will be used from the current$PATH
.- runtime (Optional[str])
Runtime of the AWS Lambda Function being uploaded. Used with
dockerize_pip
to automatically select the appropriate Docker image to use. Must provide exactly one ofdocker_file
,docker_image
, orruntime
.- use_pipenv (Optional[bool]):
Will determine if pipenv will be used to generate requirements.txt from an existing Pipfile. To use this option pipenv must be installed.
Example
Hook configuration
pre_build:
upload_functions:
path: runway.cfngin.hooks.aws_lambda.upload_lambda_functions
required: true
enabled: true
data_key: lambda
args:
bucket: custom-bucket
follow_symlinks: true
prefix: cloudformation-custom-resources/
payload_acl: authenticated-read
functions:
MyFunction:
path: ./lambda_functions
dockerize_pip: non-linux
use_pipenv: true
runtime: python3.8
include:
- '*.py'
- '*.txt'
exclude:
- '*.pyc'
- test/
Blueprint Usage
from troposphere.awslambda import Function
from runway.cfngin.blueprints.base import Blueprint
class LambdaBlueprint(Blueprint):
def create_template(self):
code = self.context.hook_data['lambda']['MyFunction']
self.template.add_resource(
Function(
'MyFunction',
Code=code,
Handler='my_function.handler',
Role='...',
Runtime='python2.7'
)
)
build_staticsite.build¶
Description
Build static site. Used by the staticsite module type.
Hook Path
runway.hooks.staticsite.build_staticsite.build
Args
See staticsite module documentation for details.
cleanup_s3.purge_bucket¶
Description
Delete objects in bucket. Primarily used as a pre_destroy
hook before deleting an S3 bucket.
Hook Path
runway.hooks.cleanup_s3.purge_bucket
Args
- bucket_name (str)
Name of the S3 bucket.
- bucket_output_lookup (str)
Value to pass to
runway.cfngin.lookups.handlers.output.OutputLookup
to retrieve an S3 bucket name.- bucket_rxref_lookup (str)
Value to pass to
runway.cfngin.lookups.handlers.rxref.RxrefLookup
to retrieve an S3 bucket name.- bucket_xref_lookup (str)
Value to pass to
runway.cfngin.lookups.handlers.xref.XrefLookup
to retrieve an S3 bucket name.
cleanup_ssm.delete_param¶
Description
Delete SSM parameter. Primarily used when an SSM parameter is created by a hook rather than CloudFormation.
Hook Path
runway.hooks.cleanup_ssm.delete_param
Args
- parameter_name (str)
Name of an SSM parameter.
command.run_command¶
Description
Run a custom command as a hook.
Hook Path
runway.cfngin.hooks.command.run_command
Args
- command (Union[str, List[str]])
Command(s) to run.
- capture (bool)
If enabled, capture the command’s stdout and stderr, and return them in the hook result. (default:
False
)- interactive (bool)
If enabled, allow the command to interact with stdin. Otherwise, stdin will be set to the null device. (default:
False
)- ignore_status (bool)
Don’t fail the hook if the command returns a non-zero status. (default:
False
)- quiet (bool)
Redirect the command’s stdout and stderr to the null device, silencing all output. Should not be enabled if
capture
is also enabled. (default:False
)- stdin (Optional[str])
String to send to the stdin of the command. Implicitly disables
interactive
.- env (Optional[Dict[str, str]])
Dictionary of environment variable overrides for the command context. Will be merged with the current environment.
- **kwargs (Any)
Any other arguments will be forwarded to the
subprocess.Popen
function. Interesting ones include:cwd
andshell
.
Example
pre_build:
command_copy_environment:
path: runway.cfngin.hooks.command.run_command
required: true
enabled: true
data_key: copy_env
args:
command: ['cp', 'environment.template', 'environment']
command_git_rev_parse:
path: runway.cfngin.hooks.command.run_command
required: true
enabled: true
data_key: get_git_commit
args:
command: ['git', 'rev-parse', 'HEAD']
cwd: ./my-git-repo
capture: true
command_npm_install:
path: runway.cfngin.hooks.command.run_command
args:
command: '`cd $PROJECT_DIR/project; npm install`'
env:
PROJECT_DIR: ./my-project
shell: true
docker¶
docker.image.build¶
Description
Docker image build hook.
Replicates the functionality of the docker image build
CLI command.
Hook Path
runway.cfngin.hooks.docker.image.build
Args
- docker (Optional[Dict[str, Any]])
Options for
docker image build
.- buildargs (Optional[Dict[str, str]])
Dict of build-time variables.
- custom_context (bool)
Optional if providing a path to a zip file. (default:
False
)- extra_hosts (Optional[Dict[str, str]])
Extra hosts to add to /etc/hosts in the building containers. Defined as a mapping of hostmane to IP address.
- forcerm (bool)
Always remove intermediate containers, even after unsuccessful builds. (default:
False
)- isolation (Optional[str])
Isolation technology used during build.
- network_mode (Optional[str])
Network mode for the run commands during build.
- nocache (bool)
Don’t use cache when set to
True
. (default:False
)- platform (Optional[str])
Set platform if server is multi-platform capable. Uses format
os[/arch[/variant]]
.- pull (bool)
Download any updates to the FROM image in the Dockerfile. (default:
False
)- rm (bool)
Remove intermediate containers. (default:
True
)- squash (bool)
Squash the resulting image layers into a single layer. (default:
False
)- tag (Optional[str])
Optional name and tag to apply to the base image when it is built.
- target (Optional[str])
Name of the build-stage to build in a multi-stage Dockerfile.
- timeout (Optional[int])
HTTP timeout.
- use_config_proxy (bool)
If
True
and if the docker client configuration file (~/.docker/config.json
by default) contains a proxy configuration, the corresponding environment variables will be set in the container being built. (default:False
)
- dockerfile (Optional[str])
Path within the build cont4ext to the Dockerfile. (default: ./Dockerfile)
- ecr_repo (Optional[Dict[str, Optional[str]]])
Information describing an ECR repository. This is used to construct the repository URL. If providing a value for this field, do not provide a value for
repo
.If using a private registry, only
repo_name
is required. If using a public registry,repo_name
andregistry_alias
.- account_id (Optional[str])
AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.
- aws_region (Optional[str])
AWS region where the registry is located. If not provided, it will be acquired automatically if needed.
- registry_alias (Optional[str])
If it is a public repository, provide the alias.
- repo_name (str)
The name of the repository
- path (Optional[str])
Path to the directory continaing the Dockerfile. (defaults to the current working directory)
- repo (Optional[str])
URI of a non Docker Hub repository where the image will be stored. If providing one of the other repo values, leave this value empty.
- tags (Optional[List[str]])
List of tags to apply to the image. (default:
["latest"]
)
Returns
The following are values accessible with the hook_data Lookup
under the data_key
of docker
(do not specify a data_key
for the hook, this
is handled automatically).
- image (DockerImage)
A
DockerImage
object for the image that was just built.Important
Each execution of this hook overwrites any previous values stored in this attribute. It is advices to consume the resulting image object after it has been built, if it will be consumed by a later hook/stack.
Example
pre_build:
- path: runway.cfngin.hooks.docker.login
args:
ecr: true
password: ${ecr login-password}
- path: runway.cfngin.hooks.docker.image.build
args:
ecr_repo:
repo_name: ${cfn ${namespace}-test-ecr.Repository}
tags:
- latest
- python3.9
- path: runway.cfngin.hooks.docker.image.push
args:
image: ${hook_data docker.image}
docker.image.push¶
Description
Docker image push hook.
Replicates the functionality of the docker image push
CLI command.
Hook Path
runway.cfngin.hooks.docker.image.push
Args
- ecr_repo (Optional[Dict[str, Optional[str]]])
Information describing an ECR repository. This is used to construct the repository URL. If providing a value for this field, do not provide a value for
image
orrepo
.If using a private registry, only
repo_name
is required. If using a public registry,repo_name
andregistry_alias
.- account_id (Optional[str])
AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.
- aws_region (Optional[str])
AWS region where the registry is located. If not provided, it will be acquired automatically if needed.
- registry_alias (Optional[str])
If it is a public repository, provide the alias.
- repo_name (str)
The name of the repository
- image (Optional[DockerImage])
A
DockerImage
object. This can be retrieved fromhook_data
for a preceding build using the hook_data Lookup.If providing a value for this field, do not provide a value for
ecr_repo
orrepo
.- repo (Optional[str])
URI of a non Docker Hub repository where the image will be stored. If providing one of the other repo values or
image
, leave this value empty.- tags (Optional[List[str]])
List of tags push. (default:
["latest"]
)
Example
pre_build:
- path: runway.cfngin.hooks.docker.login
args:
ecr: true
password: ${ecr login-password}
- path: runway.cfngin.hooks.docker.image.build
args:
ecr_repo:
repo_name: ${cfn ${namespace}-test-ecr.Repository}
tags:
- latest
- python3.9
- path: runway.cfngin.hooks.docker.image.push
args:
image: ${hook_data docker.image}
stacks:
ecr-lambda-function:
class_path: blueprints.EcrFunction
variables:
ImageUri: ${hook_data docker.image.uri.latest}
docker.image.remove¶
Description
Docker image build hook.
Replicates the functionality of the docker image remove
CLI command.
Hook Path
runway.cfngin.hooks.docker.image.remove
Args
- ecr_repo (Optional[Dict[str, Optional[str]]])
Information describing an ECR repository. This is used to construct the repository URL. If providing a value for this field, do not provide a value for
image
orrepo
.If using a private registry, only
repo_name
is required. If using a public registry,repo_name
andregistry_alias
.- account_id (Optional[str])
AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.
- aws_region (Optional[str])
AWS region where the registry is located. If not provided, it will be acquired automatically if needed.
- registry_alias (Optional[str])
If it is a public repository, provide the alias.
- repo_name (str)
The name of the repository
- force (bool)
Force removal of the image. (default:
False
)- image (Optional[DockerImage])
A
DockerImage
object. If providing anImage
object from`hook_data
, it will be removed from from there as well.If providing a value for this field, do not provide a value for
ecr_repo
orrepo
.- noprune (bool)
Do not delete untagged parents. (default:
False
)- repo (Optional[str])
URI of a non Docker Hub repository where the image is stored. If providing one of the other repo values or
image
, leave this value empty.- tags (Optional[List[str]])
List of tags delete. (default:
["latest"]
)
Example
pre_build:
- path: runway.cfngin.hooks.docker.login
args:
ecr: true
password: ${ecr login-password}
- path: runway.cfngin.hooks.docker.image.build
args:
ecr_repo:
repo_name: ${cfn ${namespace}-test-ecr.Repository}
tags:
- latest
- python3.9
- path: runway.cfngin.hooks.docker.image.push
args:
image: ${hook_data docker.image}
tags:
- latest
- python3.9
stacks:
...
post_build:
- path: runway.cfngin.hooks.docker.image.remove
args:
image: ${hook_data docker.image}
tags:
- latest
- python3.9
docker.login¶
Description
Docker login hook.
Replicates the functionality of the docker login
CLI command.
This hook does not modify the Docker config file. The credentials/authenticated session is stored in memory and is deleted after processing a given CFNgin config file.
This hook can be executed as a pre or post hook. The authenticated session carries over from pre to post and to each subsequent built-in Docker hook.
Hook Path
runway.cfngin.hooks.docker.login
Args
- dockercfg_path (Optional[str])
Use a custom path for the Docker config file (
$HOME/.docker/config.json
if present, otherwise$HOME/.dockercfg
).- ecr (Optional[Union[bool, Dict[str, Optional[str]]]])
Information describing an ECR registry. This is used to construct the registry URL. If providing a value for this field, do not provide a value for
registry
.If using a private registry, the value can simply be
true
. If using a public registry, more information is required.- account_id (Optional[str])
AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.
- alias (Optional[str])
If it is a public repository, provide the alias.
- aws_region (Optional[str])
AWS region where the registry is located. If not provided, it will be acquired automatically if needed.
- email (Optional[str])
The email for the registry account.
- password (str)
The plaintext password.
- registry (Optional[str])
URL to the registry (e.g.
https://index.docker.io/v1/
).If providing a value for this field, do not provide a value for
ecr
.- username (str)
The registry username. Defaults to
AWS
if supplyingecr
.
Example
pre_build:
- path: runway.cfngin.hooks.docker.login
args:
ecr: true
password: ${ecr login-password}
ecr.purge_repository¶
Description
Purge all images from an ECR repository.
Hook Path
runway.cfngin.hooks.ecr.purge_repository
Args
- repository_name (str)
The name of the ECR repository to purge.
Example
pre_destroy:
- path: runway.cfngin.hooks.ecr.purge_repository
args:
repository_name: example-repo
ecs.create_clusters¶
Description
Create ECS clusters.
Hook Path
runway.cfngin.hooks.ecs.create_clusters
Args
- clusters (List[str])
Names of clusters to create.
iam.create_ecs_service_role¶
Description
Create ecsServiceRole, which has to be named exactly that currently.
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/IAM_policies.html#service_IAM_role
Hook Path
runway.cfngin.hooks.iam.create_ecs_service_role
Args
- role_name (str)
Name of the role to create. (default: ecsServiceRole)
iam.ensure_server_cert_exists¶
Description
Ensure server cert exists.
Hook Path
runway.cfngin.hooks.iam.ensure_server_cert_exists
Args
- cert_name (str)
Name of the certificate that should exist.
- prompt (bool)
Whether to prompt to upload a certificate if one does not exist. (default:
True
)
keypair.ensure_keypair_exists¶
Description
Ensure a specific keypair exists within AWS. If the key doesn’t exist, upload it.
Hook Path
runway.cfngin.hooks.keypair.ensure_keypair_exists
Args
- keypair (str)
Name of the key pair to create
- ssm_parameter_name (Optional[str])
Path to an SSM store parameter to receive the generated private key, instead of importing it or storing it locally.
- ssm_key_id (Optional[str])
ID of a KMS key to encrypt the SSM parameter with. If omitted, the default key will be used.
- public_key_path (Optional[str])
Path to a public key file to be imported instead of generating a new key. Incompatible with the SSM options, as the private key will not be available for storing.
route53.create_domain¶
Description
Create a domain within route53.
Hook Path
runway.cfngin.hooks.route53.create_domain
Args
- domain (str)
Domain name for the Route 53 hosted zone to be created.
upload_staticsite.get_distribution_data¶
Description
Retrieve information about the CloudFront distribution. Used by the Static Site module type.
Hook Path
runway.hooks.staticsite.upload_staticsite.get_distribution_data
Args
See Static Site module documentation for details.
upload_staticsite.sync¶
Description
Sync static website to S3 bucket. Used by the Static Site module type.
Hook Path
runway.hooks.staticsite.upload_staticsite.sync
Args
See Static Site module documentation for details.
Writing A Custom Hook¶
A custom hook must be in an executable, importable python package or standalone file.
The hook must be importable using your current sys.path
.
This takes into account the sys_path defined in the config file as well as any paths
of package_sources.
The hook must accept a minimum of two arguments, context
and provider
.
Aside from the required arguments, it can have any number of additional arguments or use **kwargs
to accept anything passed to it.
The values for these additional arguments come from the args
key of the hook definition.
The hook must return True
or a truthy object if it was successful.
It must return False
or a falsy object if it failed.
This signifies to CFNgin whether or not to halt execution if the hook is required
.
If dict
is returned, it can be accessed by subsequent hooks, lookups, or Blueprints from the context object.
It will be stored as context.hook_data[data_key]
where data_key
is the value set in the hook definition.
If data_key
is not provided or the type of the returned data is not dict
, it will not be added to the context object.
If using boto3 in a hook, use context.get_session()
instead of creating a new session to ensure the correct credentials are used.
"""context.get_session() example."""
from runway.cfngin.context import Context
from runway.cfngin.providers.aws.default import Provider
def do_something(context: Context, provider: Provider, **kwargs: str) -> None:
"""Do something."""
session = context.get_session()
s3_client = session.client('s3')
Example Hook Function¶
local_path/hooks/my_hook.py
"""My hook."""
from typing import Dict
from runway.cfngin.context import Context
from runway.cfngin.providers.aws.default import Provider
def do_something(context: Context,
provider: Provider,
is_failure: bool = True,
**kwargs: str
) -> Dict[str, str]:
"""Do something."""
if is_failure:
return None
return {'result': f"You are not a failure {kwargs.get('name', 'Kevin')}."}
local_path/cfngin.yaml
namespace: example
sys_path: ./
pre_build:
my_hook_do_something:
path: hooks.my_hook.do_something
args:
is_failure: False
Example Hook Class¶
local_path/hooks/my_hook.py
"""My hook."""
import logging
from typing import Dict
from runway.cfngin.hooks.base import Hook
LOGGER = logging.getLogger(__name__)
class MyClass(Hook):
"""My class does a thing.
Keyword Args:
is_failure (bool): Force the hook to fail if true.
name (str): Name used in the response.
Returns:
Dict[str, str]: Response message is stored in ``result``.
Example:
.. code-block:: yaml
pre_build:
my_hook_do_something:
path: hooks.my_hook.MyClass
args:
is_failure: False
name: Karen
"""
def post_deploy(self) -> Dict[str, str]:
"""Run during the **post_deploy** stage."""
if self.args.is_failure:
return None
return {'result': f"You are not a failure {self.args.name}."}
def post_destroy(self) -> None:
"""Run during the **post_destroy** stage."""
LOGGER.error('post_destroy is not supported by this hook')
def pre_deploy(self) -> None:
"""Run during the **pre_deploy** stage."""
LOGGER.error('pre_deploy is not supported by this hook')
def pre_destroy(self) -> None:
"""Run during the **pre_destroy** stage."""
LOGGER.error('pre_destroy is not supported by this hook')
local_path/cfngin.yaml
namespace: example
sys_path: ./
pre_build:
my_hook_do_something:
path: hooks.my_hook.MyClass
args:
is_failure: False
name: Karen