Hooks

A hook is a python function, class, or class method that is executed before or after an action is taken for the entire config.

Only the following actions allow pre/post hooks:

deploy

using fields pre_deploy and post_deploy

destroy

using fields pre_destroy and post_destroy

class cfngin.hook

When defining a hook in one of the supported fields, the follow fields can be used.

Lookup Support

The following fields support lookups:

args: Optional[Dict[str, Any]] = {}

A dictionary of arguments to pass to the hook.

This field supports the use of lookups.

Important

Lookups that change the order of execution, like output, can only be used in a post hook but hooks like rxref are able to be used with either pre or post hooks.

Example

pre_deploy:
  - args:
      key: ${val}
data_key: Optional[str] = None

If set, and the hook returns data (a dictionary), the results will be stored in CfnginContext.hook_data with the data_key as its key.

Example

pre_deploy:
  - data_key: example-key
enabled: Optional[bool] = True

Whether to execute the hook every CFNgin run. This field provides the ability to execute a hook per environment when combined with a variable.

Example

pre_deploy:
  - enabled: ${enable_example_hook}
path: str

Python importable path to the hook.

Example

pre_deploy:
  - path: runway.cfngin.hooks.command.run_command
required: Optional[bool] = True

Whether to stop execution if the hook fails.


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_deploy or post_deploy 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] = None

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] = None

The resource record cache time to live (TTL), in seconds. (default: 300)

Example

namespace: example
cfngin_bucket: ''

sys_path: ./

pre_deploy:
  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}

New in version 1.6.0.


aws_lambda.upload_lambda_functions

Description

Build Lambda payloads from user configuration and upload them to S3 using the following process:

  1. Constructs ZIP archives containing files matching specified patterns for each function.

  2. Uploads the result to Amazon S3

  3. Returns a Dict of “function name: troposphere.awslambda.Code”.

The returned value can retrieved using the hook_data Lookup or by interacting with the CfnginContext object passed to the Blueprint.

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 file 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 the cfngin_bucket or an explicitly specified bucket, with the object 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] = None

Custom bucket to upload functions to. If not provided, cfngin_bucket will be used.

bucket_region: Optional[str] = None

The region in which the bucket should exist. If not provided, cfngin_bucket_region will be used.

prefix: Optional[str] = None

S3 key prefix to prepend to the uploaded zip name.

follow_symlinks: Optional[bool] = False

Whether symlinks should be followed and included with the zip artifact.

payload_acl: runway.cfngin.hooks.aws_lambda.PayloadAclTypeDef = private

The canned S3 object ACL to be applied to the uploaded payload.

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] = None

Path to a local DockerFile that will be built and used for dockerize_pip. Must provide exactly one of docker_file, docker_image, or runtime.

docker_image: Optional[str] = None

Custom Docker image to use with dockerize_pip. Must provide exactly one of docker_file, docker_image, or runtime.

dockerize_pip: Optional[Union[bool, Literal[non-linux]]] = None

Whether to use Docker when restoring dependencies with pip. Can be set to true/false or the special string non-linux which will only run on non Linux systems. To use this option Docker must be installed.

exclude: Optional[Union[List[str], str]] = None

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[List[str], str] = None

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] = None

Absolute path to a python interpreter to use for pip/pipenv actions. If not provided, the current python interpreter will be used for pip and pipenv will be used from the current $PATH.

runtime: Optional[str] = None

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 of docker_file, docker_image, or runtime.

use_pipenv: Optional[bool] = False

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_deploy:
  - 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
"""Example Blueprint."""
from __future__ import annotations

from typing import cast

from troposphere.awslambda import Code, Function

from runway.cfngin.blueprints.base import Blueprint


class LambdaBlueprint(Blueprint):
    """Example Blueprint."""

    def create_template(self) -> None:
        """Create a template from the blueprint."""
        code = cast(Code, self.context.hook_data["lambda"]["MyFunction"])

        self.template.add_resource(
            Function(
                "MyFunction",
                Code=code,
                Handler="my_function.handler",
                Role="...",
                Runtime="python3.8",
            )
        )

build_staticsite.build

Description

Build static site. Used by the Static Site module type.

Hook Path

runway.cfngin.hooks.staticsite.build_staticsite.build()

Args

See Static Site module documentation for details.

Changed in version 2.0.0: Moved from runway.hooks to runway.cfngin.hooks.

cleanup_s3.purge_bucket

Description

Delete objects in a Bucket. Primarily used as a pre_destroy hook before deleting an S3 bucket.

Hook Path

runway.cfngin.hooks.cleanup_s3.purge_bucket()

Args

bucket_name: str

Name of the S3 bucket.

Changed in version 2.0.0: Moved from runway.hooks to runway.cfngin.hooks.

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.cfngin.hooks.cleanup_ssm.delete_param()

Args

parameter_name: str

Name of an SSM parameter.

Changed in version 2.0.0: Moved from runway.hooks to runway.cfngin.hooks.

command.run_command

Description

Run a shell custom command as a hook.

Hook Path

runway.cfngin.hooks.command.run_command()

Args

command: Union[List[str], str]

Command(s) to run.

capture: Optional[bool] = False

If enabled, capture the command’s stdout and stderr, and return them in the hook result.

interactive: Optional[bool] = False

If enabled, allow the command to interact with stdin. Otherwise, stdin will be set to the null device.

ignore_status: Optional[bool] = False

Don’t fail the hook if the command returns a non-zero status.

quiet: Optional[bool] = False

Redirect the command’s stdout and stderr to the null device, silencing all output. Should not be enabled if capture is also enabled.

stdin: Optional[str] = None

String to send to the stdin of the command. Implicitly disables interactive.

env: Optional[Dict[str, str]] = None

Dictionary of environment variable overrides for the command context. Will be merged with the current environment.

**kwargs

Any other arguments will be forwarded to the subprocess.Popen function. Interesting ones include: cwd and shell.

Example

pre_deploy:
  - path: runway.cfngin.hooks.command.run_command
    required: true
    enabled: true
    data_key: copy_env
    args:
      command: ['cp', 'environment.template', 'environment']
  - 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
  - path: runway.cfngin.hooks.command.run_command
    args:
      command: '`cd $PROJECT_DIR/project; npm install`'
      env:
        PROJECT_DIR: ./my-project
        shell: true

docker

A collection of hooks that interact with 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]] = None

Dict of build-time variables.

custom_context: bool = False

Optional if providing a path to a zip file.

extra_hosts: Optional[Dict[str, str]] = None

Extra hosts to add to /etc/hosts in the building containers. Defined as a mapping of hostname to IP address.

forcerm: bool = False

Always remove intermediate containers, even after unsuccessful builds.

isolation: Optional[str] = None

Isolation technology used during build.

nocache: bool = False

Don’t use cache when set to True.

platform: Optional[str] = None

Set platform if server is multi-platform capable. Uses format os[/arch[/variant]].

pull: bool = False

Download any updates to the FROM image in the Dockerfile.

rm: bool = True

Remove intermediate containers.

squash: bool = False

Squash the resulting image layers into a single layer.

tag: Optional[str] = None

Optional name and tag to apply to the base image when it is built.

target: Optional[str] = None

Name of the build-stage to build in a multi-stage Dockerfile.

timeout: Optional[int] = None

HTTP timeout.

use_config_proxy: bool = False

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.

dockerfile: Optional[str] = "./Dockerfile"

Path within the build context to the Dockerfile.

ecr_repo: Optional[Dict[str, Optional[str]]] = None

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 and registry_alias.

account_id: Optional[str] = None

AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.

aws_region: Optional[str] = None

AWS region where the registry is located. If not provided, it will be acquired automatically if needed.

registry_alias: Optional[str] = None

If it is a public repository, provide the alias.

repo_name: str

The name of the repository.

path: Optional[str]

Path to the directory containing the Dockerfile.

repo: Optional[str] = None

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]] = ["latest"]

List of tags to apply to the image.

Returns

type

DockerHookData

description

The value of item image in the returned object is set to the DockerImage that was just created.

The returned object is 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).

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_deploy:
  - 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}

New in version 1.18.0.

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]]] = None

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 or image.

If using a private registry, only repo_name is required. If using a public registry, repo_name and registry_alias.

account_id: Optional[str] = None

AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.

aws_region: Optional[str] = None

AWS region where the registry is located. If not provided, it will be acquired automatically if needed.

registry_alias: Optional[str] = None

If it is a public repository, provide the alias.

repo_name: str

The name of the repository.

image: Optional[DockerImage] = None

A DockerImage object. This can be retrieved from hook_data for a preceding docker.image.build using the hook_data Lookup.

If providing a value for this field, do not provide a value for ecr_repo or repo.

repo: Optional[str] = None

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]] = ["latest"]

List of tags to push.

Example

pre_deploy:
  - 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}

New in version 1.18.0.

docker.image.remove

Description

Docker image remove 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]]] = None

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 or image.

If using a private registry, only repo_name is required. If using a public registry, repo_name and registry_alias.

account_id: Optional[str] = None

AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.

aws_region: Optional[str] = None

AWS region where the registry is located. If not provided, it will be acquired automatically if needed.

registry_alias: Optional[str] = None

If it is a public repository, provide the alias.

repo_name: str

The name of the repository.

force: Optional[bool] = False

Whether to force the removal of the image.

image: Optional[DockerImage] = None

A DockerImage object. This can be retrieved from hook_data for a preceding docker.image.build using the hook_data Lookup.

If providing a value for this field, do not provide a value for ecr_repo or repo.

noprune: Optional[bool] = False

Whether to delete untagged parents.

repo: Optional[str] = None

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]] = ["latest"]

List of tags to remove.

Example

pre_deploy:
  - 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_deploy:
  - path: runway.cfngin.hooks.docker.image.remove
    args:
      image: ${hook_data docker.image}
      tags:
        - latest
        - python3.9

New in version 1.18.0.

docker.login

Description

Docker login hook.

Replicates the functionality of the docker login CLI command.

Hook Path

runway.cfngin.hooks.docker.login()

Args

dockercfg_path: Optional[str] = None

Use a custom path for the Docker config file ($HOME/.docker/config.json if present, otherwise $HOME/.dockercfg).

ecr: Optional[Dict[str, Optional[str]]] = None

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 or image.

If using a private registry, only repo_name is required. If using a public registry, repo_name and registry_alias.

account_id: Optional[str] = None

AWS account ID that owns the registry being logged into. If not provided, it will be acquired automatically if needed.

alias: Optional[str] = None

If it is a public registry, provide the alias.

aws_region: Optional[str] = None

AWS region where the registry is located. If not provided, it will be acquired automatically if needed.

email: Optional[str] = None

The email for the registry account.

password: str

The plaintext password for the registry account.

registry: Optional[str] = None

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: Optional[str] = None

The registry username. Defaults to AWS if supplying ecr.

Example

pre_deploy:
  - path: runway.cfngin.hooks.docker.login
    args:
      ecr: true
      password: ${ecr login-password}

New in version 1.18.0.

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

New in version 1.18.0.


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 IAM role.

Hook Path

runway.cfngin.hooks.iam.create_ecs_service_role()

Args

role_name: Optional[str] = "ecsServiceRole"

Name of the role to create.


iam.ensure_server_cert_exists

Description

Ensure server certificate exists.

Hook Path

runway.cfngin.hooks.iam.ensure_server_cert_exists()

Args

cert_name: str

Name of the certificate that should exist.

prompt: bool = True

Whether to prompt to upload a certificate if one does not exist.


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

public_key_path: Optional[str] = None

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.

ssm_key_id: Optional[str] = None

ID of a KMS key to encrypt the SSM parameter with. If omitted, the default key will be used.

ssm_parameter_name: Optional[str] = None

Path to an SSM store parameter to receive the generated private key, instead of importing it or storing it locally.


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.sync

Description

Sync static website to S3 bucket. Used by the Static Site module type.

Hook Path

runway.cfngin.hooks.staticsite.upload_staticsite.sync()

Args

See Static Site module documentation for details.

Changed in version 2.0.0: Moved from runway.hooks to runway.cfngin.hooks.


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 field 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 a Dict or MutableMap 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 a Dict or MutableMap, 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 __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from runway.context import CfnginContext


def do_something(context: CfnginContext, **_kwargs: Any) -> None:
    """Do something."""
    s3_client = context.get_session().client("s3")

Example Hook Function

local_path/hooks/my_hook.py
"""My hook."""
from __future__ import annotations

from typing import Dict, Optional


def do_something(*, is_failure: bool = True, **kwargs: str) -> Optional[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_deploy:
  - 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, Optional

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_deploy:
          - path: hooks.my_hook.MyClass
            args:
            is_failure: False
            name: Karen

    """

    def post_deploy(self) -> Optional[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_deploy:
  - path: hooks.my_hook.MyClass
    args:
      is_failure: False
      name: Karen