Importing Existing Infrastructure
Relevant source files
The following files were used as context for generating this wiki page:
- internal/service/ec2/instance.go
- internal/service/s3/bucket.go
- internal/service/apigatewayv2/api_mapping_test.go
- internal/service/codecommit/approval_rule_template_test.go
- internal/service/apigateway/integration_response_test.go
- providerlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go
- ROADMAP.md
Importing is a core Terraform feature that allows pre-existing infrastructure to be brought under Terraform's management. For the AWS provider, this means that for a given resource (like an S3 bucket or an EC2 instance), there must be logic to read its current state from AWS and map it to a Terraform state file. This functionality is primarily defined and validated through the provider's acceptance testing framework.
The import process for each resource requires a unique identifier that Terraform can use to find the resource in AWS. After the import, a verification step is often performed to ensure the imported state matches the state of the resource when it was originally created by Terraform, confirming the import's accuracy. The provider's roadmap indicates that import functionality is an area of continuous improvement, with issues like incomplete attribute storage during import being addressed.
Sources: providerlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go, ROADMAP.md
The Import Testing Framework
The provider utilizes the Terraform Plugin SDK's testing framework to validate import functionality. This is accomplished within a resource.TestCase by defining a TestStep with specific import-related fields. The core logic for executing these test steps is found in the testStepNewImportState function.
Import Test Step Configuration
The TestStep struct contains several fields to control the import test.
| Field | Description |
|---|---|
ResourceName | The full name of the resource to be imported (e.g., aws_apigatewayv2_api_mapping.test). This is mandatory. |
ImportState | A boolean that, when set to true, enables the import test for this step. |
ImportStateId | A string providing the explicit ID to use for the import. |
ImportStateIdFunc | A function that generates the import ID dynamically from the existing Terraform state. This is used when the ID is complex or composed of multiple attributes. |
ImportStateVerify | A boolean that, when true, triggers a verification process. It compares the attributes of the newly imported state against the state before the import to ensure they are equivalent. |
ImportStateVerifyIgnore | A slice of attribute prefixes to ignore during the ImportStateVerify comparison. This is useful for attributes that are not set by the API or have values that change dynamically (e.g., timeouts). |
Import Test Execution Flow
The testStepNewImportState function orchestrates the import test by performing a series of actions to simulate a user importing a resource and then verifying the result.
The diagram below illustrates the high-level flow of an import acceptance test step.
Implementing Resource Import
While the framework is generic, each resource must provide its specific import logic, particularly how its unique ID is constructed for the terraform import command.
Generating the Import ID
Many AWS resources can be uniquely identified by a single ID. However, some resources, especially those that act as a link between other resources, require a composite ID for import. The ImportStateIdFunc is used for this purpose.
For example, the aws_api_gateway_integration_response requires the REST API ID, Resource ID, HTTP Method, and Status Code to be uniquely identified. The import ID is a /-separated string of these values.
Code Snippet: aws_api_gateway_integration_response Import ID Function
func testAccIntegrationResponseImportStateIdFunc(resourceName string) resource.ImportStateIdFunc {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("Not found: %s", resourceName)
}
return fmt.Sprintf("%s/%s/%s/%s", rs.Primary.Attributes["rest_api_id"], rs.Primary.Attributes["resource_id"], rs.Primary.Attributes["http_method"], rs.Primary.Attributes["status_code"]), nil
}
}
Sources: internal/service/apigateway/integration_response_test.go:210-220
Similarly, aws_apigatewayv2_api_mapping constructs its import ID from its ApiMappingId and DomainName.
Code Snippet: aws_apigatewayv2_api_mapping Import ID Function
func testAccAPIMappingImportStateIdFunc(resourceName string) resource.ImportStateIdFunc {
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("Not Found: %s", resourceName)
}
return fmt.Sprintf("%s/%s", rs.Primary.ID, rs.Primary.Attributes["domain_name"]), nil
}
}
Sources: internal/service/apigatewayv2/api_mapping_test.go:234-242
In contrast, a resource like aws_codecommit_approval_rule_template can be imported using its primary ID directly, so its acceptance test does not need to specify a custom ImportStateIdFunc.
Sources: internal/service/codecommit/approval_rule_template_test.go:44-48
State Verification
After a successful import, the ImportStateVerify flag triggers a comparison between the original resource state and the newly imported one. The testing framework iterates through the attributes of both states and checks for deep equality.
The verification logic automatically ignores certain empty container attributes (like list.# with a value of 0) to prevent false negatives. It also provides the ImportStateVerifyIgnore field to explicitly exclude attributes that are known to cause discrepancies, such as timeouts which are not always present in the final state. If the states do not match, the test fails and outputs the difference between the actual (imported) and expected (original) attribute maps.
Known Issues and Enhancements
The import functionality is not always perfect upon initial implementation. The project's roadmap highlights areas for improvement. For instance, an issue was noted where import aws_s3_bucket did not correctly store all important attributes, such as the acl. This indicates that ensuring complete and accurate state import is an ongoing effort.
Sources: ROADMAP.md
Summary
Importing existing infrastructure is a critical capability of the AWS provider, enabling users to adopt an Infrastructure as Code approach for resources not originally created by Terraform. The provider ensures the reliability of this feature through a robust acceptance testing framework that simulates the import process. This involves defining resource-specific import identifiers, executing the import, and verifying that the resulting Terraform state accurately reflects the live resource in AWS. The process is continuously refined to cover more attributes and edge cases, as shown by ongoing enhancements tracked in the project roadmap.