This document describes the behavior of resources implemented by the provider. In particular it describes in detail how AWS CloudFormation resource types are defined as Terraform resources.
We assume some familiarity with user-facing Terraform concepts like configuration, state, CLI workflow, etc. The Terraform website has documentation on these ideas.
Resources describe infrastructure objects such as virtual networks or compute instances. By declaring a Terraform resource block and applying that configuration, Terraform manages the lifecycle of the underlying infrastructure object so as to make its settings match the configuration.
Resource blocks declare a resource of a specific type with a specific local name. The local name is used solely to refer to that resource within its own module, having no meaning outside the module's scope. For example
resource "awscc_s3_bucket" "example" {
bucket_name = "example-bucket"
}
declares a resource of type awscc_s3_bucket
with its bucket_name
argument set to "example-bucket"
. The resource's module-local name is example
.
Resources are implemented in providers, plugins which interact with infrastructure providers such as AWS. A resource's implementation defines a schema which describes the resource's arguments, and methods (including CRUD methods) which define the resource's lifecycle management functionality.
Note that we will use the terms argument and attribute interchangeably from now on as Terraform plugins use attribute and Terraform CLI uses argument for the same concept.
Data sources are a variant of resource intended to allow Terraform to reference external data. Unlike managed resources, Terraform does not manage the underlying infrastructure object's lifecycle. Data sources are intended to have no side-effects.
For the purposes of this document we consider data sources to be similar to resources with only a Read method. We will call out differences where they are significant.
CloudFormation resources are conceptually very similar to Terraform resources. However, there are some differences:
- Resource type schemas are defined using JSON Schema dialect and published in the CloudFormation registry.
- Resources are implemented via CRUDL handlers, responsible for interacting with underlying AWS (or third-party) services to manage infrastructure lifecycle. Handlers are invoked either via a CloudFormation stack or the Cloud Control API.
During generation of the Terraform AWS Cloud Control Provider, all available CloudFormation resource schemas are downloaded from the CloudFormation registry and are cached in this GitHub repository (so as to have reproducible builds). Unless suppressed, each CloudFormation resource schema is then used to generate
- A Terraform resource.
- A Terraform singular data source. A singular data source returns attributes of a single AWS object. A unique identifier is used to specify for which AWS object information is returned.
- A plural data source. A plural data source returns a list of the unique identifiers for every AWS object of the resource's type (in the configured AWS account and Region).
CloudFormation resource type names consist of three parts; an organization, service and resource (for example AWS::EC2::Instance
).
Terraform type names are derived from the CloudFormation type name by lower casing the service part, snake casing the resource part and using awscc_
as a prefix. The resource part is pluralized for any plural data source type name.
For example, the AWS::EC2::Instance
CloudFormation resource type leads to the generation of the awscc_ec2_instance
resource and awscc_ec2_instance
and awscc_ec2_instances
data sources.
The shape of a resource defines the names, types and behaviors of its fields. Every property in a CloudFormation resource schema corresponds to an argument in the Terraform schema.
A Terraform attribute's name is obtained by snake casing the corresponding CloudFormation property's name. For example a property named GlobalReplicationGroupDescription
corresponds to an attribute named global_replication_group_description
.
Note
If a top-level attribute's name is one of the Terraform meta-arguments count
, depends_on
, for_each
, or lifecycle
then generation of the Terraform resource (and data sources) is suppressed.
If a top-level attribute's name is provider
it is renamed to provider_name
.
A Terraform attribute's type is derived from the corresponding CloudFormation property's type.
CloudFormation Type | Terraform Type |
---|---|
boolean |
Bool |
integer |
Int64 |
number |
Float64 |
string |
String 1 |
array |
List or Set 23 |
object |
Nested attribute or Map 4 |
insertionOrder | uniqueItems | Terraform Type |
---|---|---|
true |
false |
List |
false |
false |
List custom type with semantic equality |
true |
true |
List with UniqueValues validator |
false |
true |
Set |
A JSON Schema integer property's minimum
and maximum
values correspond to Terraform AtLeast
, AtMost
and Between
validators.
Any enum
value corresponds to the Terraform OneOf
validator.
A JSON Schema number property's minimum
and maximum
values correspond to Terraform AtLeast
, AtMost
and Between
validators.
A JSON Schema string property's minLength
and maxLength
values correspond to Terraform LengthAtLeast
, LengthAtMost
and LengthBetween
validators.
Any enum
value corresponds to the Terraform OneOf
validator.
Any pattern
value corresponds to the Terraform RegexMatches
validator. If the pattern value is valid for ECMA-262 but not for Go then an empty pattern (""
) is used in the validator, effectively allowing any string.
A JSON Schema array property's minItems
and maxItems
values correspond to Terraform SizeAtLeast
, SizeAtMost
and SizeBetween
validators (or their equivalents for sets).
A CloudFormation property's default
value corresponds to a Terraform attribute plan modifier which tailors the plan so that if the planned value is null
and there is a current value and the current value is the default then use the current value, else use the planned value.
A Terraform attribute's configurability defines how Terraform expects data to be set, whether from configuration or in the provider's logic (such as an API response value). At least one of three schema attribute flags must be set to true
:
Required
: The attribute must be configured to a known, non-null
value.Optional
: The attribute may be configured to a known value or its value isnull
.Computed
: The attribute's planned value is unknown and a known value must be set by provider logic.
The allowed combinations of these flags are Required
-only, Optional
-only, Computed
-only (no value is allowed to be configured), and Optional
+Computed
(a value may be configured; if the configured value is null
, a value may be set by provider logic).
A Terraform attribute's configurability is derived from the CloudFormation resource's semantic properties.
- If a CloudFormation property is
required
, the attribute isRequired
. - If a CloudFormation property is not required and not in the
readOnlyProperties
list, the attribute isOptional
. - If a CloudFormation property is in the
readOnlyProperties
list, the attribute isComputed
. - If a CloudFormation property has a default value, the attribute is
Computed
. A required property with a default value is switches the attribute toOptional
. - All
Optional
attributes are marked asComputed
. This is because CloudFormation only determines drift for property values that are explicitly set, whereas Terraform expects the value of an unset, non-Computed
attribute to always benull
(not present). AWS services will often return values that have not been specified as default values in the CloudFormation resource type schema for properties that are unset in configuration.
If a CloudFormation property is in the createOnlyProperties
list, the corresponding Terraform attribute is immutable. If the value of the attribute changes, in-place update is not possible and instead the resource is replaced for the change to occur.
The Terraform RequiresReplace
plan modified is used for this behavior.
Every Terraform schema generated from a CloudFormation resource schema includes a top-level attribute named id
. This attribute's value uniquely identifies the underlying AWS resource in the configured AWS account and Region and is used for Cloud Control API operations and in acceptance tests. The id
attribute is added during the Terraform resource generation process.
Note
If the CloudFormation resource schema does define a top-level Id
property then that property is mapped to a Terraform attribute named <type>_id
(e.g. flow_log_id
for the awscc_ec2_flow_log
resource).
The AWS Cloud Control API provides a standardized set of operations to create, read, update, delete, and list (CRUD-L) supported resources in an AWS account.
A resource type represents an infrastructure artifact whose lifecycle can be managed through the API. Each resource type is defined by its resource type schema, a JSON Schema-compliant document published to the AWS CloudFormation registry.
To create or update a resource using the Cloud Control API a program must specify a JSON document representing the resource's properties and their values. When the resource is being created, these values are the resource's desired state. When the resource is being updated, the values are a list of patches between the resource's current state and its desired state.
Reading a resource returns a JSON document representing its current state.
The Terraform AWS Cloud Control Provider maps Terraform data to and from these JSON documents and call Cloud Control API methods.
The provider's Create
method is called from terraform apply
when Terraform determines during planning that no resource with the configured module-local name exists or that an existing resource must be recreated. The provider converts the Terraform plan, which describes the expected values of the resource's attributes, into the Cloud Control desired state JSON document -- in the process reversing the snake casing described above.
The resource's desired state document and the CloudFormation resource type name are passed to the CreateResource
API and the provider then polls for completion of the operation.
If the operation fails, the error is returned to the Terraform CLI.
If the operation succeeds, the resource's current state document is used to populate unknown attribute values, including the id attribute
, and all attribute values are saved in Terraform state.
The provider's Read
method is called from terraform plan
, terraform apply
and terraform refresh
to obtain the current state of the resource. The provider uses the value of the id
attribute, stored in the resource's prior state, and the CloudFormation resource type name to call the GetResource
API.
If the operation fails, the error is returned to the Terraform CLI.
If the operation succeeds, the resource's current state document is used to populate the Terraform current state. The values of attributes corresponding to properties in the writeOnlyProperties
list are copied from prior state to current state.
The provider's Update
method is called from terraform apply
when Terraform determines during planning that an existing resource must be updated in-place. The provider converts the resource's prior state and planned new state into JSON documents and generates a JSON Patch document listing the operations required to reach the desired state from the current state of the resource.
The patch document and the CloudFormation resource type name are passed to the UpdateResource
API and the provider then polls for completion of the operation.
If the operation fails, the error is returned.
If the operation succeeds, the resource's current state document is used to populate unknown attribute values and all attribute values are saved in Terraform state.
The provider's Delete
method is called from terraform apply
when Terraform determines during planning that an existing resource has been removed from configuration or that an existing resource must be recreated. The provider uses the value of the id
attribute and the CloudFormation resource type name to call the DeleteResource
API and then polls for completion of the operation.
If the operation fails, the error is returned to the Terraform CLI and Terraform keeps the resource under management.
If the operation succeeds, the resource is removed from state.
The provider has no List
method. Instead when a plural data source's Read
method is called the provider uses the CloudFormation resource type name to call the ListResources
API.
If the operation fails, the error is returned to the Terraform CLI.
If the operation succeeds, a list of primary identifiers for all resources is returned and stored in state as the value of the ids
attribute.
Footnotes
-
JSON Schema string properties with a
format
value of"date-time"
correspond to the TerraformRFC3339
custom type. ↩ -
JSON Schema array properties correspond to either Terraform lists or sets depending on the values of
uniqueItems
andinsertionOrder
. ↩ -
An array's item type determines the Terraform list or set element type. See Array Types. ↩
-
JSON Schema object properties with pattern properties correspond to Terraform maps. Only the first pattern is considered. ↩