terraform-search-import

作者: hashicorp

使用 Terraform Search 查询发现现有云资源,并将其批量导入 Terraform 管理。适用于将未管理的基础设施纳入管理时…

npx skills add https://github.com/hashicorp/agent-skills --skill terraform-search-import

Terraform Search and Bulk Import

Discover existing cloud resources using declarative queries and generate configuration for bulk import into Terraform state.

References:

When to Use

  • Bringing unmanaged resources under Terraform control
  • Auditing existing cloud infrastructure
  • Migrating from manual provisioning to IaC
  • Discovering resources across multiple regions/accounts

IMPORTANT: Check Provider Support First

BEFORE starting, you MUST verify the target resource type is supported:

# Check what list resources are available
./scripts/list_resources.sh aws      # Specific provider
./scripts/list_resources.sh          # All configured providers

Decision Tree

  1. Identify target resource type (e.g., aws_s3_bucket, aws_instance)

  2. Check if supported: Run ./scripts/list_resources.sh <provider>

  3. Choose workflow:

    • ** If supported**: Check for terraform version available.
    • ** If terraform version is above 1.14.0** Use Terraform Search workflow (below)
    • ** If not supported or terraform version is below 1.14.0 **: Use Manual Discovery workflow (see references/MANUAL-IMPORT.md)

    Note: The list of supported resources is rapidly expanding. Always verify current support before using manual import.

Prerequisites

Before writing queries, verify the provider supports list resources for your target resource type.

Discover Available List Resources

Run the helper script to extract supported list resources from your provider:

# From a directory with provider configuration (runs terraform init if needed)
./scripts/list_resources.sh aws      # Specific provider
./scripts/list_resources.sh          # All configured providers

Or manually query the provider schema:

terraform providers schema -json | jq '.provider_schemas | to_entries | map({key: (.key | split("/")[-1]), value: (.value.list_resource_schemas // {} | keys)})'

Terraform Search requires an initialized working directory. Ensure you have a configuration with the required provider before running queries:

# terraform.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

Run terraform init to download the provider, then proceed with queries.

Terraform Search Workflow (Supported Resources Only)

  1. Create .tfquery.hcl files with list blocks defining search queries
  2. Run terraform query to discover matching resources
  3. Generate configuration with -generate-config-out=<file>
  4. Review and refine generated resource and import blocks
  5. Run terraform plan and terraform apply to import

Query File Structure

Query files use .tfquery.hcl extension and support:

  • provider blocks for authentication
  • list blocks for resource discovery
  • variable and locals blocks for parameterization
# discovery.tfquery.hcl
provider "aws" {
  region = "us-west-2"
}

list "aws_instance" "all" {
  provider = aws
}

List Block Syntax

list "<list_type>" "<symbolic_name>" {
  provider = <provider_reference>  # Required

  # Optional: filter configuration (provider-specific)
  # The `config` block schema is provider-specific. Discover available options using `terraform providers schema -json | jq '.provider_schemas."registry.terraform.io/hashicorp/<provider>".list_resource_schemas."<resource_type>"'`

  config {
    filter {
      name   = "<filter_name>"
      values = ["<value1>", "<value2>"]
    }
    region = "<region>"  # AWS-specific
  }
  # Optional: limit results
  limit = 100
}

Supported List Resources

Provider support for list resources varies by version. Always check what's available for your specific provider version using the discovery script.

Query Examples

Basic Discovery

# Find all EC2 instances in configured region
list "aws_instance" "all" {
  provider = aws
}

Filtered Discovery

# Find instances by tag
list "aws_instance" "production" {
  provider = aws
  
  config {
    filter {
      name   = "tag:Environment"
      values = ["production"]
    }
  }
}

# Find instances by type
list "aws_instance" "large" {
  provider = aws
  
  config {
    filter {
      name   = "instance-type"
      values = ["t3.large", "t3.xlarge"]
    }
  }
}

Multi-Region Discovery

provider "aws" {
  region = "us-west-2"
}

locals {
  regions = ["us-west-2", "us-east-1", "eu-west-1"]
}

list "aws_instance" "all_regions" {
  for_each = toset(local.regions)
  provider = aws
  
  config {
    region = each.value
  }
}

Parameterized Queries

variable "target_environment" {
  type    = string
  default = "staging"
}

list "aws_instance" "by_env" {
  provider = aws
  
  config {
    filter {
      name   = "tag:Environment"
      values = [var.target_environment]
    }
  }
}

Running Queries

# Execute queries and display results
terraform query

# Generate configuration file
terraform query -generate-config-out=imported.tf

# Pass variables
terraform query -var='target_environment=production'

Query Output Format

list.aws_instance.all   account_id=123456789012,id=i-0abc123,region=us-west-2   web-server

Columns: <query_address> <identity_attributes> <name_tag>

Generated Configuration

The -generate-config-out flag creates:

# __generated__ by Terraform
resource "aws_instance" "all_0" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  # ... all attributes
}

import {
  to       = aws_instance.all_0
  provider = aws
  identity = {
    account_id = "123456789012"
    id         = "i-0abc123"
    region     = "us-west-2"
  }
}

Post-Generation Cleanup

Generated configuration includes all attributes. Clean up by:

  1. Remove computed/read-only attributes
  2. Replace hardcoded values with variables
  3. Add proper resource naming
  4. Organize into appropriate files
# Before: generated
resource "aws_instance" "all_0" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = "t2.micro"
  arn                    = "arn:aws:ec2:..."  # Remove - computed
  id                     = "i-0abc123"        # Remove - computed
  # ... many more attributes
}

# After: cleaned
resource "aws_instance" "web_server" {
  ami           = var.ami_id
  instance_type = var.instance_type
  subnet_id     = var.subnet_id
  
  tags = {
    Name        = "web-server"
    Environment = var.environment
  }
}

Import by Identity

Generated imports use identity-based import (Terraform 1.12+):

import {
  to       = aws_instance.web
  provider = aws
  identity = {
    account_id = "123456789012"
    id         = "i-0abc123"
    region     = "us-west-2"
  }
}

Best Practices

Query Design

  • Start broad, then add filters to narrow results
  • Use limit to prevent overwhelming output
  • Test queries before generating configuration

Configuration Management

  • Review all generated code before applying
  • Remove unnecessary default values
  • Use consistent naming conventions
  • Add proper variable abstraction

Troubleshooting

IssueSolution
"No list resources found"Check provider version supports list resources
Query returns emptyVerify region and filter values
Generated config has errorsRemove computed attributes, fix deprecated arguments
Import failsEnsure resource not already in state

Complete Example

# main.tf - Initialize provider
terraform {
  required_version = ">= 1.14"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"  # Always use latest version
    }
  }
}

# discovery.tfquery.hcl - Define queries
provider "aws" {
  region = "us-west-2"
}

list "aws_instance" "team_instances" {
  provider = aws
  
  config {
    filter {
      name   = "tag:Owner"
      values = ["platform"]
    }
    filter {
      name   = "instance-state-name"
      values = ["running"]
    }
  }
  
  limit = 50
}
# Execute workflow
terraform init
terraform query
terraform query -generate-config-out=generated.tf
# Review and clean generated.tf
terraform plan
terraform apply

来自 hashicorp 的更多技能

provider-actions
hashicorp
使用插件框架实现Terraform Provider操作。在开发生命周期事件(之前/之后…)中执行的命令式操作时使用。
official
provider-docs
hashicorp
使用HashiCorp推荐的模式、tfplugindocs模板和schema创建、更新和审查Terraform Registry的Terraform provider文档。
official
aws-ami-builder
hashicorp
使用Packer的amazon-ebs构建器创建自定义Amazon Machine Images。通过HCL模板自动化从源AMI创建AMI的过程,并利用配置器(shell脚本、文件上传、配置管理)进行自定义。支持通过ami_regions实现多区域AMI分发,以及按名称、所有者和虚拟化类型灵活过滤源AMI。通过环境变量、AWS凭证文件或IAM实例配置文件进行身份验证;包含模板的验证和构建命令...
official
azure-image-builder
hashicorp
使用Packer构建Azure托管映像和Azure Compute Gallery映像。在创建Azure VM的自定义映像时使用。
official
azure-verified-modules
hashicorp
针对寻求AVM合规的Azure Terraform模块的认证要求与最佳实践。强制要求提供者版本约束(azurerm >= 4.0, < 5.0;azapi >= 2.0, < 3.0),禁止使用基于Git的模块引用,转而采用固定的Terraform注册表源。所有标识符必须使用小写下划线命名法,变量类型需精确指定,通过防腐层模式实现离散输出属性,本地变量需按字母顺序排列。新增资源需配置功能开关变量...
official
new-terraform-provider
hashicorp
使用Plugin Framework搭建一个新的Terraform provider。生成一个采用标准"terraform-provider-"命名约定的新Go模块工作区,并初始化所需依赖。提供一个遵循HashiCorp Plugin Framework模式的模板main.go文件,其中包含用于自定义的TODO标记。通过运行构建和测试命令来验证设置,确保provider能够编译并通过初始检查。通过创建新工作区前确认意图来处理工作区管理。
official
provider-actions
hashicorp
使用Plugin Framework在资源生命周期事件中实现命令式Terraform Provider操作。支持创建前/后和更新前/后的生命周期触发器(Terraform 1.14.0中不支持销毁事件)。需要正确的模式定义,包括框架类型、集合的ElementType以及输入验证的验证器。包含进度报告、超时管理和长时间运行操作的全面错误处理。实现轮询和...
official
provider-docs
hashicorp
使用HashiCorp推荐的模式、tfplugindocs模板和schema创建、更新和审查Terraform Registry的Terraform provider文档。
official