Skip to content

Instantly share code, notes, and snippets.

@automaticgiant
Created March 24, 2025 17:23
Show Gist options
  • Save automaticgiant/e36a95166309fe40fe13f653d99adf49 to your computer and use it in GitHub Desktop.
Save automaticgiant/e36a95166309fe40fe13f653d99adf49 to your computer and use it in GitHub Desktop.
simple tfstate "export" assistant

Basic usage

jq -f tf_extract.jq tfstate.json

List resources by provider

jq -f tf_extract.jq tfstate.json | jq 'group_by(.provider_namespace) | map({provider: .[0].provider_namespace, count: length})'

Get all resource addresses with their documentation links

jq -f tf_extract.jq tfstate.json | jq -r '"(.resource_address)\t(.tf_registry_doc)"' > resources_with_docs.txt

Filter resources by type

jq -f tf_extract.jq tfstate.json | jq 'select(.type | startswith("aws_iam_"))'

# Extract provider information from resource
def get_provider_info(resource):
if resource | has("provider") then
resource.provider | capture("provider\\[\"(?<registry>[^\"]+)/(?<namespace>[^/]+)/(?<name>[^\"]+)\"\\]") as $provider_parts |
{
"registry": $provider_parts.registry,
"namespace": $provider_parts.namespace,
"provider_name": $provider_parts.name
}
else
{"registry": "registry.terraform.io", "namespace": "hashicorp", "provider_name": "unknown"}
end;
# Extract common resource information
def extract_common(resource; type; name):
get_provider_info(resource) as $provider |
{
"resource_address": "\(type).\(name)",
"id": resource.instances[0].attributes.id,
"type": type,
"provider_namespace": $provider.namespace,
"provider_name": $provider.provider_name,
"tf_registry_doc": "https://\($provider.registry)/providers/\($provider.namespace)/\($provider.provider_name)/latest/docs/resources/\(type | sub("^[^_]+_"; ""))#import"
}
+ if resource.instances[0].attributes.arn then {"arn": resource.instances[0].attributes.arn} else {} end
+ if resource.instances[0].attributes.name then {"name": resource.instances[0].attributes.name} else {} end;
# Add resource-specific attributes based on resource type
def add_specific_attrs(resource; type):
if type == "aws_route53_record" then
{
"zone_id": resource.instances[0].attributes.zone_id,
"fqdn": resource.instances[0].attributes.fqdn,
"record_type": resource.instances[0].attributes.type
}
elif type == "aws_iam_role_policy" then
{
"role_name": resource.instances[0].attributes.role
}
elif type == "aws_s3_bucket" then
{
"bucket": resource.instances[0].attributes.bucket
}
else
{}
end;
# Main extraction logic
.resources[]
| select(.mode == "managed")
| extract_common(.; .type; .name) + add_specific_attrs(.; .type)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment