Lookups
Important
Runway lookups and CFNgin lookups are not interchangeable. While they do share a similar base class and syntax, they exist in two different registries. Runway config files can’t use CFNgin lookups just as the CFNgin config cannot use Runway lookups.
Runway’s CFNgin provides the ability to dynamically replace values in the config via a concept called lookups. A lookup is meant to take a value and convert it by calling out to another service or system.
A lookup is denoted in the config with the ${<lookup type> <lookup input>}
syntax.
Lookups are only resolved within Variables. They can be nested in any part of a YAML data structure and within another lookup itself.
Note
If a lookup has a non-string return value, it can be the only lookup within a field.
e.g. if custom
returns a list, this would raise an exception:
Variable: ${custom something}, ${output otherStack.Output}
This is valid:
Variable: ${custom something}
For example, given the following:
stacks:
- name: sg
class_path: some.stack.blueprint.Blueprint
variables:
Roles:
- ${output otherStack.IAMRole}
Values:
Env:
Custom: ${custom ${output otherStack.Output}}
DBUrl: postgres://${output dbStack.User}@${output dbStack.HostName}
The Blueprint
would have access to the following resolved variables dictionary:
{
"Roles": ["other-stack-iam-role"],
"Values": {
"Env": {
"Custom": "custom-output",
"DBUrl": "postgres://user@hostname",
},
},
}
Built-in Lookups
- ami
- awslambda
- awslambda.Code
- awslambda.CodeSha256
- awslambda.CompatibleArchitectures
- awslambda.CompatibleRuntimes
- awslambda.Content
- awslambda.License
- awslambda.Runtime
- awslambda.S3Bucket
- awslambda.S3Key
- awslambda.S3ObjectVersion
- cfn
- default
- dynamodb
- ecr
- env
- envvar
- file
- hook_data
- kms
- output
- random.string
- rxref
- ssm
- xref
Writing A Custom Lookup
A custom lookup may be registered within the config.
It custom lookup must be in an executable, importable python package or standalone file.
The lookup 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 lookup must be a subclass of LookupHandler
with a @classmethod
of handle
with a similar signature to what is provided in the example below.
The subclass must override the TYPE_NAME
class variable with a name that will be used to register the lookup.
There must be only one lookup per file.
The lookup must return a string if being used for a CloudFormation parameter.
If using boto3 in a lookup, use context.get_session()
instead of creating a new session to ensure the correct credentials are used.
Important
When using a pydantic.root_validator()
or pydantic.validator()
in a lookup allow_reuse=True
must be passed to the decorator.
This is because of how lookups are loaded/re-loaded when they are registered.
Failure to do so will result in an error if the lookup is registered more than once.
Example
"""Example lookup."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Final, Literal, Optional, Union
from runway.cfngin.utils import read_value_from_path
from runway.lookups.handlers.base import LookupHandler
if TYPE_CHECKING:
from runway.cfngin.providers.aws.default import Provider
from runway.context import CfnginContext, RunwayContext
class MylookupLookup(LookupHandler):
"""My lookup."""
TYPE_NAME: Final[Literal["mylookup"]] = "mylookup"
"""Name that the Lookup is registered as."""
@classmethod
def handle(
cls,
value: str,
context: Union[CfnginContext, RunwayContext],
*_args: Any,
provider: Optional[Provider] = None,
**_kwargs: Any
) -> str:
"""Do something.
Args:
value: Value to resolve.
context: The current context object.
provider: CFNgin AWS provider.
"""
query, args = cls.parse(read_value_from_path(value))
# example of using get_session for a boto3 session
s3_client = context.get_session().client("s3")
return "something"