Authoring Your Own Blueprints
Create cloud infrastructure templates tailored specifically for your company and teams
Blueprints are templated Terraform files that streamline creating similar configurations. They use tags as placeholders, enhancing reusability and customizability across diverse setups.
During resource creation, the blueprint is rendered into the final Terraform configuration with tags substituted by the values provided by a developer. Resourcely will open a PR containing the ready-to-apply, customized Terraform config.
Quickstart
The blueprint templating syntax consists of variable tags, section blocks, and other metadata.
Variable Tag: A placeholder {{ name }}
that gets replaced with its respective value during rendering.
Section Block: A block of content enclosed in opening and closing section tags {{# name }}...{{/ name }}
. During rendering, the content is repeated once for each element of the respective value (which must be a list).
Tag Parameters: Arguments to tags are specified using the pipe |
character: {{ name | desc: "Name of project" | required: true }}
.
Special Variable: {{ __guid }}
is a special variable that generates a single unique value during rendering, useful for ensuring unique resource names across multiple renderings.
Frontmatter: The blueprint may start with a YAML frontmatter section, specifying both variable objects (as alternative means of declaring tag parameters) and constant objects (defining internal constant values).
Example
For a practical understanding of the Blueprint templating language, consider the following example that creates an AWS EC2 instance with a corresponding security group with arbitrary ingress and egress rules.
From this blueprint, the Resourcely Portal generates a form that makes it easy for a developer to supply the required values and render the resulting Terraform configuration.
Syntax
Variable Tags
Variable tags are inputs that are replaced by respective values during rendering. The syntax for variable tags is {{ name }}
.
Section Tags
Section tags enclose content that can be repeated during rendering. A {{# name }}
tag opens a repeated section and a corresponding {{/ name }}
closes it. Section tags can be nested to allow complex structures.
The section tag is given a list of values during rendering. The enclosed content is repeated for each value in the list. Nested tags can reference the current element by using the section name.
Section tags also have a special property called __index
that can be used to access the index of the list being referenced. This can be helpful to create unique names inside a section tag.
Another example of section tags for AWS tagging functionality
Dotted Syntax in Tag Names
Dotted syntax in tag names allows for accessing nested properties of an input object supplied for rendering. When values are passed into the blueprint for rendering, they form a structure that mirrors the structure of the tags in the blueprint.
This becomes even more useful when dealing with repeated sections. For instance, consider a repeated section {{# users }}...{{/ users }}
that creates multiple users. Inside this section, you might have tags like {{ users.name }}
and {{ users.email }}
. Here, the users list will be an array of objects, with each object having properties name and email.
Tag Parameters
Tag parameters are additional metadata for each tag. They can be declared inline inside a tag using the pipe (|
) character:
They can also be declared in the front matter.
The following tag parameters are supported. All are optional.
type
Defines the type of the input variable, such as string, number, or boolean. It helps in validating the input and may affect how the input is rendered or processed.
The type parameter is usually automatically inferred, so does not need to be explicitly included. See Type Inference for details.
desc
Description of the variable. This will be shown in the Resourcely Portal to assist the user creating a resource from the blueprint.
. This allows you to create multi-line descriptions with formatting, linking, bullets, headings, and more.
required
A boolean that, when true, specifies that the input variable must be provided. If a required variable is missing, it will prevent the blueprint from being instantiated.
suggest
Specifies an initial value for the input variable. This value will be pre-populated when the create form loads, but the user can change it.
Currently complex suggestions (lists and objects) can only be specified in the frontmatter, not inline. Primitive defaults can be specified inline as well.
order
Controls the order in which input fields appear in the Resourcely Portal form.
group
Specifies a grouping for the input fields in the Resourcely Portal form.
global_value
Constrains the available inputs to only those referenced by a Global Value The value here should be the key
of the Global Value.
Alternatively, provide the Global Value options as suggestions in a drop-down, but still allow the user to type in a different value. Use the syntax suggestions(key
) for this behavior.
advanced
This will move this particular input to an "Advanced" section at the bottom of the Resourcely Portal Create form. This is usually used for optional inputs that require additional context only a power user will have.
links_to
Specifies that this input can link to resource properties of the given type. See 'Links' section for more detail.
prefer_mode
Specifies the prefer mode for an input in the create form, the supported mode is env
.
Type Inference
The type
of most tags is inferred automatically from their context within the Terraform config. If a tag is used as the value for a Terraform attribute, Resourcely will use the expected type of that attribute. For instance, if a tag is used as the value for the bucket attribute of an aws_s3_bucket
resource, the tags will be automatically inferred from the type of aws_s3_bucket.bucket
.
However, there may be instances where automatic type inference is not possible or sufficient. In these cases, the type parameter can be explicitly specified. This is often necessary when the tag is used as an input to a Terraform module, as modules do not have a fixed structure that the templating engine can infer types from.
For instance, a tag with an explicit type parameter may look like
Here, the type: string
specification ensures that module_input
will be processed as a string, even though its type cannot be inferred from the content.
Type Syntax
The type syntax is an extension of the Terraform type constraint syntax. In addition to the types supported by Terraform, you can reference the type of resource property directly.
or
This makes it possible to easily give exact types for module inputs without having to duplicate the entire typing of the underlying resource properties.
These "reference" types can be nested inside of list or object types, just like any other type.
Links
In Terraform, it is common for resources to reference other resources by name or id. This DRYs out the Terraform config, and (much more importantly) teaches Terraform how to create and destroy resources in the correct order.
In most cases, Resourcely will infer whether each input supports links, and if so, which resource properties it can link to. You can augment the inference for a given input by adding a links_to tag parameter. links_to must be followed by the name of a resource property or a complex type whose leaves are resource properties (see 'Advanced Linking,' below). Resourcely parses this value to determine the resource type and property path.
In the following example, {{ kms_key_id }}
can link to the key_id
property on any aws_kms_key
resource. The tag can also link to data sources that match the given resource type and property.
The create form user will see a list of resources (or data sources) of the given type that have the given property. Using the example above, this looks like:
The list includes resources that are currently being created, as well as already-checked-in resources. Currently, Resourcely doesn't support linking to repeating (count, for_each) resources, optional properties, or repeating properties (list/map items, HCL blocks). If one of these is important to you, let us know!
Link inference
Just like how Resourcely can infer type
, it can infer links_to
in many cases. Here are our inference rules, with examples:
When you use a {{ tag }}
as the value of a resource property that "usually" links to other resources, Resourcely will infer links_to
. "Usually" reflects how Resourcely's knowledge of linkability is constantly evolving in response to feedback. If you think you found a missing linkability inference, let us know!
When you use a resource property as the type of a tag, and that property usually links to other resources, Resourcely will infer links_to
.
You can always explicitly specify links_to
. Explicitly specified values augment any inferred values.
Advanced Linking
There are three advanced topics associated with links_to
:
Complex types
Linking to multiple types
Structural matching and type coercion
Complex types
When type
is a complex type such as list(string)
, the structure of links_to
must match the structure of type
. You can always make a valid links_to
parameter by copying the type
parameter and replacing all occurrences of string
, number
, and bool
with some resource property, like resource.aws_kms_key.key_id
.
In the next example, {{ kms_key_ids }}
is a list of strings, and each item can link to the key_id
property on any aws_kms_key
resource.
Linking to multiple types
Certain Terraform resources support polymorphic links, such as aws_lambda_function.dead_letter_config.target_arn. This property, for example, can contain the arn of an SNS topic or an SQS queue.
You can specify multiple types in links_to
by separating them with |
. Note that you must enclose the links_to
value in quotes when |
is present.
Link within prefix and suffix
If you to link to a resource but within a string with prefix and suffix you can do the following
Structural matching and type coercion
Terraform supports type coercion between strings, numbers, and booleans. Because of this, Resourcely checks for a structural match between type
and links_to
but does not otherwise check for type alignment. This is best explained by example.
Module input defaults
If your blueprint invokes a module, you can specify each module input's default value in the blueprint. Resourcely will omit that property during rendering if the current value is equal to the default value. This can lead to substantially shorter module blocks, especially for modules with a large number of optional properties.
You can specify both default and suggest on one variable. Resourcely will initialize the create form using the suggest value and omit the property if the user enters the default value. This is useful with 3rd-party modules: if you don't like their default, Resourcely can suggest your preferred default.
If only default is specified, Resourcely will automatically suggest the default value. This lets the create form user see what the value will be, even though it won't appear in the rendered Terraform.
Constants and Special Variables
Variables beginning with double underscore (__) are not exposed in the Resourcely Portal form, so are considered to be internal values.
Constants can be defined in the constants section of the frontmatter. This is useful for avoiding repetition in your template.
There are two special variables whose values are automatically supplied during rendering.
__guid
__guid
is a special constant that gets a unique value during rendering. This is useful for generating unique resource names across multiple renderings of the same blueprint.
__index
Inside of a repeated section, <name>.__index
is a special variable that points to the current element's index in the <name>
list.
Conventions
Common convention is to define a __name
constant that incorporates the __guid
variable. Use {{ __name }}
as part of each Terraform block local name (resource, data source, module, etc.) to ensure that
resources created together share a name, for easy identification.
resource names will not conflict when the Blueprint is instantiated multiple times.
Front matter
The blueprint can include a YAML frontmatter section to define variables and constants.
Variables
The variables
object is an alternative way to specify the various tag parameters for the corresponding tag:
Groups
The groups
object defines metadata for groups.
Constants
The constants
object defines variables with constant values that can be referenced in the blueprint. These constant values can themselves be simple templated strings.
Terraform Style Config
The terraform_style_config
object is used to customize how the blueprint's Terraform will be rendered in a PR.
Only a single property is supported today:
block_names.allow_hyphens
Controls whether hyphens-
should be allowed in block names. Terraform only allows certain characters (including hyphens-)
in block names. If the value of a{{ tag }}
used in a block name contains illegal characters, Resourcely will replace them with underscores_
when rendering the blueprint. Many users prefer to standardize on underscores_
, not hyphens-
, in block names. If this setting isfalse
, hyphens-
will be treated as illegal in block names and will be replaced by underscores_
. Defaults totrue
.
Example:
The blueprint
with inputs
will render as
Notice that the name
property is still rendered verbatim — it includes the hyphens and special chars. Only the module block name is transformed to comply with Terraform's block name rules.
Groups
Top-level tags can be grouped using the group
tag param. If a tag is in a group, its order
param specifies its order within its group. Any tags without an explicit group
are placed in the default General
group.
Groups support their own metadata params that can be set in the groups
frontmatter object.
desc
Description of the variable. This will be shown in the Resourcely Portal to assist the user creating a resource from the blueprint.
order
Controls the order in which the groups appear in the Resourcely Portal form.
Global Values
Admins can create globally defined values that you can then use to restrict inputs to a Blueprint.
You can reference Global Values in Blueprints through either the Frontmatter definition, or inline.
The following example shows both cases. The dept
tag parameter references the Global Values of department
in the frontmatter, and the ami
tag parameter references the Global Values of approved_amis
inline.
Global Values can also be complex types (lists/structs). Since each Global Value has a schema for these complex types, you can dereference these types directly in the Blueprint.
In the following example, os
references the global value os_family
, which is a struct with keys ami
and os_type
.
Global Value Group By
By default, the global value options are presented to the user in a selection dropdown. When there are hundreds of options, it may be difficult for the user to find the desired one.
group_by(...)
only works for global values with OBJECT type.
Use the group_by
modifier to specify a set of properties on each option object that can be used to filter the options available in the selection dropdown:
In the following example, the {{ ami }}
variable uses the amis
global value, filtered by distribution
and virt_type
.
Assume the amis
global value has the following options:
The following blueprint uses the group_by
modifier to display the distribution
and virt_type
filter dropdowns.
Global Value Suggestions
Instead of restricting the inputs of a blueprint, global values can also be used to suggest possible values for the inputs. The values will be shown in a dropdown, but the user can also type in a different value.
suggestions(...)
only works for string inputs.
To use a global value as a source of suggestions, wrap its key in the suggestions(...)
modifier:
In the following example, the {{ name }}
uses the departments
global_value to suggest some values.
Comments
Resourcely preserves most comments from the blueprint through to the rendered Terraform. In general, we preserve:
Any
// whole-line comment
(including# these
and/* these */
)/* inline */
comments found within HCL function calls.
If we aren't preserving a comment that's important to you, please contact us.
Resourcely also parses special // resourcely:<key>
comments. These contain metadata that is useful for Resourcely, but never useful for Terraform. Unless noted below, these comments will not be preserved in the rendered Terraform.
File placement comments
What do they do? These comments let your blueprint place top-level HCL resources in specific files when creating the pull request. Include these in your blueprint if your organization has per file naming conventions (e.g. storage.tf
vs instance.tf
).
File placement comments will override the default_file
specified in resourcely.yaml.
Where do they go? Before any top-level HCL block (e.g. resource
or data
).
Example: // resourcely:file <filename.tf>
you can embed tags directly into file placement comments by incorporating them within the filename e.g // resourcely:file ec2-{{ name }}.tf
Module output comments
What do they do? These comments teach Resourcely about the presence (and type) of module outputs. When you create a blueprint by importing a module, Resourcely automatically generates these comments.
Where do they go? As whole-line comments within the module
invocation block.
Example: // resourcely:output instance_arns list(aws_instance.arn)
Last updated