
Alibabacloud Terraform Code Generation
- 58 installs
- 208 repo stars
- Updated August 4, 2026
- aliyun/alibabacloud-aiops-skills
alibabacloud-terraform-code-generation is a Claude skill that generates validated Terraform HCL for the aliyun/alicloud provider from natural-language infrastructure requirements.
About
This skill turns natural-language Alibaba Cloud infrastructure requirements into validated Terraform HCL for the current aliyun/alicloud provider. A developer uses it to scaffold or extend infra like VPC, ECS, RDS, OSS, SLB/ALB, Function Compute and ACK, with resource details fetched from the provider docs at generation time. It runs fmt and validate, makes plan opt-in, and never runs terraform apply.
- Generates validated Terraform HCL for Alibaba Cloud (alicloud) infrastructure
- Pulls resource knowledge from the current alicloud provider docs at generation time
- Runs fmt/validate and never executes terraform apply
Alibabacloud Terraform Code Generation by the numbers
- 58 all-time installs (skills.sh)
- +9 installs in the week ending Jun 23, 2026 (Skillselion tracking)
- Ranked #667 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
alibabacloud-terraform-code-generation capabilities & compatibility
Free skill; requires Terraform locally and an Alibaba Cloud account (provisioned resources billed by Alibaba Cloud).
- Capabilities
- terraform generation · iac scaffolding · config validation
- Works with
- terraform
- Use cases
- devops · ci cd
- Runs
- Runs locally
- Pricing
- Bring your own API key
What alibabacloud-terraform-code-generation says it does
Turn natural-language Alibaba Cloud infrastructure requirements into validated Terraform for the current `aliyun/alicloud` provider.
This skill NEVER runs `terraform apply`. `plan` is opt-in (Step 8); `apply` is strictly the user's action.
npx skills add https://github.com/aliyun/alibabacloud-aiops-skills --skill alibabacloud-terraform-code-generationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 58 |
|---|---|
| repo stars | ★ 208 |
| Last updated | August 4, 2026 |
| Repository | aliyun/alibabacloud-aiops-skills ↗ |
What it does
Generate validated Terraform HCL for Alibaba Cloud infrastructure from natural-language requirements.
Who is it for?
Scaffolding or extending Alibaba Cloud infrastructure as validated Terraform HCL.
Skip if: AWS to Alicloud migration or importing existing resources into Terraform state (use a different skill).
When should I use this skill?
You want Terraform HCL generated for Alibaba Cloud resources like VPC, ECS, RDS or OSS.
What you get
Validated Terraform HCL for the requested alicloud resources is generated with fmt and validate run.
By the numbers
- Covers VPC, ECS, RDS, OSS, SLB/ALB, Function Compute v3 and ACK resource types
Files
Alibaba Cloud Terraform Code Generation
Turn natural-language Alibaba Cloud infrastructure requirements into validated Terraform for the current aliyun/alicloud provider. Resource knowledge is pulled from the provider's own docs at generation time — no local gold examples are maintained.
Hard rules (never violate)
1. Credentials — never leak, never require
NEVER read, print, ask for, or write AK/SK values anywhere — HCL, comments, env declarations, shell output, logs. The alicloud provider resolves credentials through seven mechanisms (env AK/SK, shared config.json, ECS instance RAM role, Assume Role, OIDC/RRSA, sidecar URI, static HCL) — see references/auth-and-network.md for the full chain. All read by the provider itself, never by this skill. Do NOT recommend the deprecated ALICLOUD_* / ALIBABACLOUD_* (no-underscore) env-var names — the current names are ALIBABA_CLOUD_ACCESS_KEY_ID / _ACCESS_KEY_SECRET / _SECURITY_TOKEN.
2. Honest reporting — never claim a step you didn't run
Never report fmt: ok / validate: ok / plan: ok unless the corresponding command actually executed AND returned that status. When a step is skipped (tool missing, user opt-out), state "SKIPPED" (or "FAILED") with a reason. Paraphrasing real output is fine; fabricating it is not.
3. terraform apply is off-limits
This skill NEVER runs terraform apply. plan is opt-in (Step 8); apply is strictly the user's action.
Environment (soft recommendations)
- Terraform ≥ 1.5 recommended. Do not install or download Terraform
automatically; Step 6 checks whether terraform is on PATH and reports the actual validation status.
- Network is required — Step 4.2 WebFetches each resource's provider doc.
Workflow
Step 1. Parse requirement
Extract:
region— defaultcn-hangzhou.resources[]—{ alicloud_type, quantity, attributes }.- Non-functional: multi-AZ, encryption, backup, HA, IOPS.
If ambiguous (e.g. "搭个数据库"), ask at most one clarifying question.
Step 2. Resolve target directory
Extract <target-dir> from the user's request (explicit path like myshop-infra/ or current working directory if unspecified). All subsequent fmt / init / validate commands run in this directory.
Before writing any .tf file, MUST create the directory:
mkdir -p <target-dir>All file writes MUST prefix paths with <target-dir>/ — never write to the current working directory directly, never write to a generic outputs/ parent. After generation completes, verify the structure:
ls -R <target-dir>Step 3. Sketch architecture
Before any HCL, sketch a dependency table — one row per resource:
| resource | depends on | AZ / placement |
|---|
- Expand
resources[]with implied infra (VPC → VSwitch → SecurityGroup
→ workload); user parse often skips these.
- The expanded list is the input to Step 4's gate.
Step 4. Pre-HCL gate (MANDATORY)
For every distinct alicloud_* type from Step 3 (resources and data sources), execute 4.1 → 4.2 → 4.3. The calls per type are independent — issue them in parallel across types.
4.1 Pre-doc lookup (catalog + patterns, in parallel)
Two local lookups; run them concurrently before going to WebFetch:
(a) Catalog lookup — confirm the resource exists and check deprecation. The catalog (references/alicloud-providers.md) is ~2600 lines; do NOT `Read` it whole — use grep, which returns just the row(s) you need:
grep "alicloud_<name>" references/alicloud-providers.mdThree outcomes:
- Row found, status column empty → note the
[doc](<url>)from the row;
proceed to 4.2.
- Row found, status `⚠️ 弃用 → `<new_name>` → switch the plan to
<new_name> and re-lookup. NEVER emit the deprecated name. Common catch: alicloud_fc_function → alicloud_fcv3_function.
- Row not found → stop. Ask the user whether the name was a typo;
don't invent an alicloud_<guess>.
(b) Pattern lookup (conditional) — if the user's requirement matches a product-specific idiom listed in references/resource-patterns.md (e.g. RDS cross-AZ HA, OSS lifecycle noncurrent, VPC peering), read the relevant section. These idioms are NOT in the provider doc's Required list but are what the user actually wants (e.g. zone_id_slave_a for RDS HA is optional per the doc but required for real cross-AZ placement). Missing them produces "validates but silently wrong" output.
When a matching pattern section is found, ALL attributes listed in that section's "Required attributes" table MUST appear in the generated HCL — treat them as mandatory even if the provider doc marks them Optional.
# Quick check whether a relevant pattern exists, then Read only the section:
grep -in "<keyword>" references/resource-patterns.md4.2 Fetch provider doc (WebFetch)
WebFetch the doc URL from 4.1. If it fails or returns no useful content, construct the raw URL directly from the catalog row's doc URL. Preserve the catalog kind: resources use website/docs/r/, data sources use website/docs/d/.
https://raw.githubusercontent.com/aliyun/terraform-provider-alicloud/master/website/docs/{r|d}/<doc_name>.html.markdownIf both fail, fall back to the local catalog row in references/alicloud-providers.md. Prefix the recitation header with doc unreachable: used local catalog. Do NOT fetch any other URL — only the two URLs above or the local catalog are trusted sources.
4.3 Recite (proof-of-read)
Before writing any HCL, emit and verify a complete per-resource brief:
- Required params (verbatim list from the doc, or from the local catalog
if the 4.2 fallback was taken)
- 2–5 key Optional params relevant to the user's requirement
- A minimal HCL snippet from the doc's "Example Usage" (omit with the note
no example available only when the fallback was taken)
If Required or Optional params are missing, return to 4.2. Skipping or using a partial recitation is a hard failure; WebFetch failure uses the 4.2 fallback, not memory.
Step 5. Generate
5.1 Write HCL from the recitations, not memory
Use ONLY the params established in 4.3. If you need a param that wasn't in the recited brief, re-fetch 4.2 with a deeper read; do not guess.
Before writing a field, look up the resource in references/deprecated-fields.md (see §5.6 for the four row-kinds and their handling rules):
grep '`alicloud_<resource>`' references/deprecated-fields.mdIf the user's requirement touches a product with a specific usage pattern (e.g. RDS cross-AZ HA, VPC peering, OSS lifecycle), also consult references/resource-patterns.md for the non-obvious attributes.
5.2 Data-source enforcement (MANDATORY — no hardcoded IDs)
Resolve via data blocks, never literals. These also pass Step 4's gate:
zone_id→data "alicloud_zones"(filter byavailable_resource_creation).image_id→data "alicloud_images"(filter byname_regex,owners = "system",most_recent = true).instance_type→data "alicloud_instance_types"(filter bycpu_core_count,memory_size, AZ).
5.4 Provider block (content contract)
Two Terraform blocks must appear somewhere in the project's *.tf files. Terraform merges all *.tf in a directory, so file organization is a style choice, not a contract — see "File organization" below.
Block 1 — `terraform { required_providers {} }`:
terraform {
required_version = ">= 1.5"
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.274"
}
}
}- Provider version: resolve the latest published stable
aliyun/alicloud1.x
version, then write a pessimistic minor constraint (1.278.0 -> ~> 1.278). Lookup sources, in order: 1. https://registry.terraform.io/v1/providers/aliyun/alicloud/versions 2. https://registry.terraform.io/providers/aliyun/alicloud/latest 3. https://github.com/aliyun/terraform-provider-alicloud/releases or https://github.com/aliyun/terraform-provider-alicloud/tags
- If lookup fails, fall back to
~> 1.274. Accepted form is~> 1.<minor>
from a confirmed published 1.x release. Do NOT write open-ended constraints (>= 1.x, >= 1.239.0) or bare version strings.
Block 2 — `provider "alicloud" {}` with BOTH region = var.region and configuration_source:
provider "alicloud" {
region = var.region
configuration_source = "AlibabaCloud-Agent-Skills/alibabacloud-terraform-code-generation"
}configuration_sourceis the attribution signature — required.regionMUST referencevar.region, not a hardcoded literal.
File organization (recommended, not required): conventional split is terraform.tf (Block 1) + providers.tf (Block 2). Also acceptable: a single versions.tf containing both blocks, or either block at the top of main.tf. Pick what fits the project — Terraform merges all *.tf equivalently. Do NOT add a filename check; run the content check below instead.
Post-generation verification (cross-file content grep):
# 1. required_providers has aliyun/alicloud with a ~> 1.<minor> version
awk '
/required_providers[[:space:]]*{/ { in_req=1 }
in_req && /alicloud[[:space:]]*=[[:space:]]*{/ { in_ali=1 }
in_ali && /source[[:space:]]*=[[:space:]]*"aliyun\/alicloud"/ { source=1 }
in_ali && /version[[:space:]]*=[[:space:]]*"~>[[:space:]]*1\.[0-9]+"/ { version=1 }
in_ali && /^[[:space:]]*}/ { in_ali=0 }
END { exit(source && version ? 0 : 1) }
' <target-dir>/*.tf \
&& echo OK_VERSION || echo BAD_OR_MISSING_VERSION
# 2. configuration_source attribution present somewhere
grep -Rq 'configuration_source = "AlibabaCloud-Agent-Skills/alibabacloud-terraform-code-generation"' \
<target-dir>/*.tf \
&& echo OK_CFG_SOURCE || echo MISSING_CFG_SOURCE
# 3. region uses variable, not hardcoded
grep -Rq 'region\s*=\s*var\.region' <target-dir>/*.tf \
&& echo OK_REGION_VAR || echo HARDCODED_REGIONAll three must return OK. If any fails, fix the offending content and re-run — do NOT proceed to Step 6 with failures.
5.5 Style baseline
- 2-space indent;
=aligned within a block; snake_case semantic resource labels
(alicloud_vswitch.app_a, not vsw1).
- Every tag-supporting resource should carry a non-empty
tagsblock for ops
hygiene — pick reasonable keys for the scenario (common choices: ManagedBy, Project, Environment, CreatedBy). Skill does not prescribe specific tag keys or values.
5.6 Deprecated-field audit — static grep pass (MANDATORY)
Run before terraform is needed — this is a pure-grep pass on the HCL you just wrote. For every resource in this generation, grep the project against references/deprecated-fields.md and handle each row-kind:
- rename row → if the old field name appears in HCL you just wrote,
replace it with the new field name. Examples that show up most often:
alicloud_ram_role:name→role_name,
document → assume_role_policy_document
alicloud_security_group:name→security_group_namealicloud_db_database:name→data_base_name- split / soft-split row → do NOT write the inline field on the parent.
Declare the replacement sub-resource only when the user's requirement needs that capability, or when references/resource-patterns.md says the sub-resource has an explicit safe default. Example: for OSS buckets, alicloud_oss_bucket_acl defaults to private, but logging/CORS/website sub-resources are omitted unless the user asks for those features.
- deprecated-no-replacement row → stop using the field, no substitute.
Applies only to files written in this generation — do NOT refactor pre-existing user files you weren't asked to touch.
Post-audit verification (bash grep — must return all OK):
# Walk deprecated-fields.md row by row and check whether any deprecated
# field that applies to a generated resource is still in use.
# Uses awk to extract individual resource blocks before field matching,
# so that short field names (name, document) don't falsely match
# substrings in compound field names (role_name, policy_document).
grep '| `alicloud_' references/deprecated-fields.md | while IFS='|' read _ resource field kind _; do
resource=$(echo "$resource" | tr -d ' `')
field=$(echo "$field" | tr -d ' ')
kind=$(echo "$kind" | tr -d ' ')
# Only check if this resource exists in the generated HCL
if grep -Rq "resource \"$resource\"" <target-dir>/*.tf; then
case "$kind" in
rename|deprecated-no-replacement)
awk -v res="$resource" -v fld="$field" '
$0 ~ "resource \"" res "\"" { in_block=1; next }
in_block && /^}/ { in_block=0 }
in_block && $0 ~ "(^|[^_[:alnum:]])" fld "([^_[:alnum:]]|$)" { found=1; exit }
END { exit found ? 0 : 1 }
' <target-dir>/*.tf \
&& echo "DEPRECATED: $resource.$field" || echo "OK: $resource.$field"
;;
split|soft-split)
grep -q "\b$field\b\s*=" <target-dir>/*.tf \
&& echo "DEPRECATED: $resource.$field (inline — use standalone sub-resource)" \
|| echo "OK: $resource.$field (not inline)"
;;
esac
fi
doneHARD GATE: must pass before Step 6 — If the script above produces any DEPRECATED: line:
1. Read each DEPRECATED: line — it names the resource and field. 2. Look up that resource+field in references/deprecated-fields.md to get the Action column (rename target, split sub-resource, etc.). 3. Apply the fix in the HCL. 4. Re-run the verification script. 5. Repeat until every line returns `OK:`. This is a blocking gate — do NOT proceed to Step 6 with any DEPRECATED: output. Do NOT claim "verified" unless the script produces all OK:.
Step 6. Validate + provider deprecation detection
If terraform is on PATH:
(cd <target-dir> \
&& terraform fmt -recursive \
&& terraform init -backend=false \
&& terraform validate -json)Loop until both conditions are met (max 3 fix attempts total):
1. Parse validate -json. If there are errors → fix the offending file, then go to step 3. 2. Scan validate -json diagnostics[].summary for [DEPRECATED] strings. The provider emits authoritative deprecation annotations (e.g. "document": "[DEPRECATED] … New field 'assume_role_policy_document' instead."). If found → fix the matching field, then go to step 3. 3. Re-run cd <target-dir> && terraform validate -json and go back to step 1.
Exit the loop only when validate reports no errors AND no `[DEPRECATED]` diagnostics. After 3 attempts without reaching this state: proceed to Step 7 with Validation: FAILED (<diagnostic excerpt>) and include the failing HCL verbatim in the optional notes.
If `init` fails with a network error (cannot reach registry.terraform.io): not a config bug. Point the user at the mirror-source configuration in references/auth-and-network.md, then proceed to Step 7 — the Summary MUST use Validation: SKIPPED (init failed — network/unreachable). Do not retry blindly, do not write ~/.terraformrc yourself.
If terraform is absent: SKIP this step and surface that fact in Step 7's summary (Hard rule §2) with Validation: SKIPPED (terraform binary not on PATH).
Step 7. Coverage check + summarize
MANDATORY — runs regardless of generation outcome. Even if earlier steps were interrupted (init network failure, validate loop exhausted, terraform not on PATH), this step MUST execute. The Files written: and Validation: lines are the final contract with downstream evaluators — skipping them is a hard failure.
Coverage check. Enumerate resource blocks in the generated HCL and compare with Step 3's sketch. If any sketch row is missing, return to Step 5 and add it — do not skip a row because "the user didn't explicitly name it".
Summary template — print in the user's language, using exactly this structure (fill <bracketed> placeholders, keep the two line labels Files written: and Validation: verbatim):
Files written:
<path/to/file1>
<path/to/file2>
...
Validation: <one-of-four-exact-strings-below>
Deprecation routing: <If re-routed: `<original_name>` → `<new_name>`; else: None>
<optional: architecture notes, design decisions, deploy hints — free-form
here is fine, but NOT inside the lines above>The Validation: line must be one of these exact strings, chosen from what actually happened in Step 6. Do NOT paraphrase or fold it into prose:
Validation: terraform fmt+validate: okValidation: SKIPPED (terraform binary not on PATH)Validation: SKIPPED (<reason>)Validation: FAILED (<diagnostic excerpt>)— after 3 retries hit the cap
Edge cases:
- Init timeout →
Validation: FAILED (init timed out — provider installation exceeded time limit) - Init network-unreachable →
Validation: SKIPPED (init failed — network/unreachable) - Init failed after fmt succeeded → use the root-cause string above, not a
hybrid status.
Step 8 (optional). terraform plan
Only when the user asks. Pre-flight probes all seven credential paths from references/auth-and-network.md without reading any value:
(
[[ -n "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ]] && [[ -n "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]] && echo "ready:env-ak-sk"
[[ -f "$HOME/.aliyun/config.json" ]] && echo "ready:shared-config"
{ [[ -n "${ALIBABA_CLOUD_CREDENTIALS_FILE:-}" ]] && [[ -f "${ALIBABA_CLOUD_CREDENTIALS_FILE}" ]]; } && echo "ready:custom-credentials-file"
[[ -n "${ALIBABA_CLOUD_ECS_METADATA:-}" ]] && echo "ready:ecs-ram-role"
[[ -n "${ALIBABA_CLOUD_ROLE_ARN:-}" ]] && echo "ready:assume-role"
[[ -n "${ALIBABA_CLOUD_CREDENTIALS_URI:-}" ]] && echo "ready:sidecar"
) | head -1- Any line of output → a credential path is available:
(cd <target-dir> && terraform init && terraform plan -out=tfplan); surface the output.
- Empty output →
NO_CREDENTIALS. Tell the user about all viable
paths (env AK/SK, shared ~/.aliyun/config.json + ALIBABA_CLOUD_PROFILE, ECS instance RAM role, Assume Role chain, OIDC/RRSA, sidecar URI) — do NOT just push env AK/SK. Point them at references/auth-and-network.md for the full setup. Then stop. Never read or print secret values.
References
| Source | When to read |
|---|---|
references/alicloud-providers.md (local) | Step 4.1 — resource existence, deprecation mark, doc URL |
| Provider doc (WebFetch of the URL from 4.1) | Step 4.2 — authoritative Required / Optional per resource |
references/deprecated-fields.md (local) | Step 5.1 — known field-level renames not flagged by terraform validate |
references/resource-patterns.md (local) | Step 5.1 — product-specific idioms not emphasized by the provider doc (RDS HA, …) |
references/auth-and-network.md (local) | Step 6 failure branch — mirror-source config; Step 8 pre-flight — full credential chain |
The local catalog is one markdown table row per alicloud_* resource and data source, with a [doc](<url>) cell and, for deprecated entries, a ⚠️ 弃用 → <new_name>` marker. It is generated from the upstream provider repo by scripts/build_alicloud_providers.py; re-run that script when a new aliyun/alicloud` release introduces or shifts deprecations.
Auth and network reference
Practical details for two environmental questions the generation workflow cannot ignore: how the alicloud provider finds credentials (SKILL Step 8) and what to do when `terraform init` can't reach the upstream registry (SKILL Step 6). SKILL.md references this file; it does not duplicate it.
1. Credential resolution chain
The alicloud provider (v1.228+) walks these seven mechanisms in order and adopts the first one that succeeds. SKILL never reads any credential value — it only checks whether each mechanism is _available_ so the user gets an accurate diagnosis.
| # | Mechanism | Detection signal |
|---|---|---|
| 1 | Static in HCL | access_key / secret_key in provider "alicloud" block — SKILL Hard Rule §1 forbids emitting this. |
| 2 | Env AK/SK | ALIBABA_CLOUD_ACCESS_KEY_ID + ALIBABA_CLOUD_ACCESS_KEY_SECRET both set. STS adds ALIBABA_CLOUD_SECURITY_TOKEN. |
| 3 | Shared credentials file | ~/.aliyun/config.json exists (or $ALIBABA_CLOUD_CREDENTIALS_FILE points at one). ALIBABA_CLOUD_PROFILE selects which profile. |
| 4 | ECS instance RAM role | Running on ECS with a role attached; $ALIBABA_CLOUD_ECS_METADATA names the role, or HCL has ecs_role_name = "...". |
| 5 | Assume RAM Role | $ALIBABA_CLOUD_ROLE_ARN + $ALIBABA_CLOUD_ROLE_SESSION_NAME set (layered on top of a base AK). |
| 6 | Assume Role with OIDC | HCL assume_role_with_oidc { oidc_token_file = "..." } — typical RRSA / Kubernetes ServiceAccount flow. No AK required. |
| 7 | Sidecar credentials | $ALIBABA_CLOUD_CREDENTIALS_URI set, or HCL credentials_uri = "...". Available since provider v1.141.0. |
Deprecated env-var names (do NOT recommend)
Provider 1.228.0 deprecated the following. If an earlier Agent output still uses them, update the recommendation:
| Old (deprecated) | Current |
|---|---|
ALICLOUD_ACCESS_KEY | ALIBABA_CLOUD_ACCESS_KEY_ID |
ALICLOUD_SECRET_KEY | ALIBABA_CLOUD_ACCESS_KEY_SECRET |
ALICLOUD_SECURITY_TOKEN | ALIBABA_CLOUD_SECURITY_TOKEN |
ALIBABACLOUD_ACCESS_KEY_ID (no underscore) | ALIBABA_CLOUD_ACCESS_KEY_ID (with underscore) |
ALIBABACLOUD_ACCESS_KEY_SECRET | ALIBABA_CLOUD_ACCESS_KEY_SECRET |
Step 8 probe (non-reading)
Inside SKILL Step 8's pre-flight check, probe presence of each mechanism without reading any value. Any one line of output = ready:
(
[[ -n "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ]] && [[ -n "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]] && echo "ready:env-ak-sk"
[[ -f "$HOME/.aliyun/config.json" ]] && echo "ready:shared-config"
{ [[ -n "${ALIBABA_CLOUD_CREDENTIALS_FILE:-}" ]] && [[ -f "${ALIBABA_CLOUD_CREDENTIALS_FILE}" ]]; } && echo "ready:custom-credentials-file"
[[ -n "${ALIBABA_CLOUD_ECS_METADATA:-}" ]] && echo "ready:ecs-ram-role"
[[ -n "${ALIBABA_CLOUD_ROLE_ARN:-}" ]] && echo "ready:assume-role"
[[ -n "${ALIBABA_CLOUD_CREDENTIALS_URI:-}" ]] && echo "ready:sidecar"
) | head -1If no line prints → NO_CREDENTIALS. The error message to the user must list all viable paths (not just env AK/SK) so they can pick the one that fits their real environment — STS token, RAM role chain, or OIDC are all legitimate and often preferred over long-lived AK.
2. terraform init network acceleration (Alibaba Cloud mirror)
Source: <https://help.aliyun.com/zh/terraform/terraform-init-acceleration-solution-configuration>
When it's needed
terraform init in China-mainland networks often can't reach registry.terraform.io. Signatures in the init output that indicate a network problem (not a config problem):
connection refusedTLS handshake timeoutnetwork is unreachableno such hostcontext deadline exceededfetchingregistry.terraform.io- any
i/o timeouton the provider download step
Configuration
Unlike most terraform knobs, the mirror is not an environment variable — it has to be a CLI config file.
File location (the one Terraform reads by default):
- Linux / macOS:
~/.terraformrc - Windows:
%APPDATA%/terraform.rc - Custom: point
TF_CLI_CONFIG_FILEat any*.tfrc.
Content (paste verbatim):
provider_installation {
network_mirror {
url = "https://mirrors.aliyun.com/terraform/"
include = ["registry.terraform.io/aliyun/alicloud",
"registry.terraform.io/hashicorp/alicloud"]
}
direct {
exclude = ["registry.terraform.io/aliyun/alicloud",
"registry.terraform.io/hashicorp/alicloud"]
}
}After writing the file, clear any stale state and re-init:
rm -rf <target-dir>/.terraform <target-dir>/.terraform.lock.hcl
(cd <target-dir> && terraform init -backend=false)SKILL contract: diagnose, don't write
~/.terraformrc is a user-global configuration file. SKILL's Step 6 failure branch MUST:
1. Recognize a network-class init failure from the signatures above. 2. Print the exact configuration block above and the file path. 3. Name the alternative TF_CLI_CONFIG_FILE=<project>/.terraformrc for users who prefer a project-scoped file. 4. Hand back to the user — do NOT write ~/.terraformrc autonomously.
<!-- Auto-generated by scripts/build_deprecated_fields.py. Do not edit by hand; re-run the script to refresh. Manual supplements via references/deprecated-fields-manual.yaml. -->
| Resource | Field | Kind | Action | Since |
|---|
| alicloud_actiontrail_trail | mns_topic_arn | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.118.0 | | alicloud_actiontrail_trail | name | rename | Use trail_name instead; value semantics unchanged. | v1.95.0 | | alicloud_actiontrail_trail | role_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.118.0 | | alicloud_adb_db_cluster | db_cluster_class | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.121.2 | | alicloud_adb_db_cluster | pay_type | rename | Use payment_type instead; value semantics unchanged. | v1.166.0 | | alicloud_alb_acl | acl_entries | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.166.0 | | alicloud_alb_listener | acl_config | split | Inline argument deprecated — declare separate alicloud_alb_listener_acl_attachment resource alongside the parent and remove inline acl_config = …. | v1.163.0 | | alicloud_alb_listener | xforwarded_for_config | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.161.0 | | alicloud_alidns_domain_group | group_name | rename | Use domain_group_name instead; value semantics unchanged. | v1.97.0 | | alicloud_alikafka_consumer_group | description | rename | Use remark instead; value semantics unchanged. | v1.268.0 | | alicloud_alikafka_instance | topic_quota | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.194.0 | | alicloud_api_gateway_access_control_list | acl_entrys | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.228.0 | | alicloud_cen_bandwidth_package | charge_type | rename | Use payment_type instead; value semantics unchanged. | v1.98.0 | | alicloud_cen_bandwidth_package | geographic_region_ids | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.98.0 | | alicloud_cen_bandwidth_package | name | rename | Use cen_bandwidth_package_name instead; value semantics unchanged. | v1.98.0 | | alicloud_cen_instance | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.98.0 | | alicloud_cen_transit_router_peer_attachment | route_table_association_enabled | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.230.0 | | alicloud_cen_transit_router_peer_attachment | route_table_propagation_enabled | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.230.0 | | alicloud_cen_transit_router_peer_attachment | transit_router_attachment_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.247.0 | | alicloud_cen_transit_router_vbr_attachment | route_table_association_enabled | split | Inline argument deprecated — declare separate alicloud_cen_transit_router_route_table_association resource alongside the parent and remove inline route_table_association_enabled = …. | v1.233.1 | | alicloud_cen_transit_router_vbr_attachment | route_table_propagation_enabled | split | Inline argument deprecated — declare separate alicloud_cen_transit_router_route_table_propagation resource alongside the parent and remove inline route_table_propagation_enabled = …. | v1.233.1 | | alicloud_cen_transit_router_vpc_attachment | route_table_association_enabled | split | Inline argument deprecated — declare separate alicloud_cen_transit_router_route_table_association resource alongside the parent and remove inline route_table_association_enabled = …. | v1.192.0 | | alicloud_cen_transit_router_vpc_attachment | route_table_propagation_enabled | split | Inline argument deprecated — declare separate alicloud_cen_transit_router_route_table_propagation resource alongside the parent and remove inline route_table_propagation_enabled = …. | v1.192.0 | | alicloud_cen_transit_router_vpc_attachment | transit_router_attachment_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.230.1 | | alicloud_cen_transit_router_vpn_attachment | transit_router_attachment_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.274.0 | | alicloud_click_house_account | total_databases | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.223.1 | | alicloud_click_house_account | total_dictionaries | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.223.1 | | alicloud_cloud_firewall_instance | renew_period | rename | Use renewal_duration instead; value semantics unchanged. | v1.209.1 | | alicloud_cms_alarm | dimensions | rename | Use metric_dimensions instead; value semantics unchanged. | v1.173.0 | | alicloud_cms_alarm | end_time | rename | Use effective_interval instead; value semantics unchanged. | v1.50.0 | | alicloud_cms_alarm | start_time | rename | Use effective_interval instead; value semantics unchanged. | v1.50.0 | | alicloud_cms_site_monitor | alert_ids | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.262.0 | | alicloud_cms_site_monitor | create_time | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.262.0 | | alicloud_cms_site_monitor | options_json | rename | Use option_json instead; value semantics unchanged. | v1.262.0 | | alicloud_cms_site_monitor | task_state | rename | Use status instead; value semantics unchanged. | v1.262.0 | | alicloud_cms_site_monitor | update_time | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.262.0 | | alicloud_common_bandwidth_package | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.120.0 | | alicloud_common_bandwidth_package_attachment | cancel_common_bandwidth_package_ip_bandwidth | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_config_aggregate_compliance_pack | config_rules | rename | Use config_rule_ids instead; value semantics unchanged. | v1.141.0 | | alicloud_config_compliance_pack | config_rules | rename | Use config_rule_ids instead; value semantics unchanged. | v1.141.0 | | alicloud_config_rule | scope_compliance_resource_types | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_config_rule | source_detail_message_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_config_rule | source_maximum_execution_frequency | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_cr_ee_instance | created_time | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.235.0 | | alicloud_cr_ee_sync_rule | name | rename | Use sync_rule_name instead; value semantics unchanged. | v1.240.0 | | alicloud_cr_ee_sync_rule | rule_id | rename | Use repo_sync_rule_id instead; value semantics unchanged. | v1.240.0 | | alicloud_cs_edge_kubernetes | certificate_authority | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_edge_kubernetes | client_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_edge_kubernetes | client_key | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_edge_kubernetes | cluster_ca_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_edge_kubernetes | kube_config | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.187.0 | | alicloud_cs_edge_kubernetes | log_config | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_cs_kubernetes | certificate_authority | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_kubernetes | client_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_kubernetes | client_key | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_kubernetes | cluster_ca_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_kubernetes | load_balancer_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.232.0 | | alicloud_cs_kubernetes | name_prefix | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_cs_kubernetes_addon | can_upgrade | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.273.0 | | alicloud_cs_kubernetes_addon | next_version | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.273.0 | | alicloud_cs_kubernetes_node_pool | cis_enabled | rename | Use security_hardening_os instead; value semantics unchanged. | v1.223.1 | | alicloud_cs_kubernetes_node_pool | max_unavailable | rename | Use max_parallelism instead; value semantics unchanged. | v1.185.0 | | alicloud_cs_kubernetes_node_pool | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.219.0 | | alicloud_cs_kubernetes_node_pool | platform | rename | Use image_type instead; value semantics unchanged. | v1.145.0 | | alicloud_cs_kubernetes_node_pool | rollout_policy | rename | Use rolling_policy instead; value semantics unchanged. | v1.185.0 | | alicloud_cs_kubernetes_node_pool | security_group_id | rename | Use security_group_ids instead; value semantics unchanged. | v1.145.0 | | alicloud_cs_kubernetes_node_pool | surge | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.219.0 | | alicloud_cs_kubernetes_node_pool | surge_percentage | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.219.0 | | alicloud_cs_managed_kubernetes | certificate_authority | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_managed_kubernetes | client_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_managed_kubernetes | client_key | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_managed_kubernetes | cluster_ca_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_managed_kubernetes | load_balancer_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.232.0 | | alicloud_cs_managed_kubernetes | worker_vswitch_ids | rename | Use vswitch_ids instead; value semantics unchanged. | v1.241.0 | | alicloud_cs_serverless_kubernetes | client_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_serverless_kubernetes | client_key | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_serverless_kubernetes | cluster_ca_cert | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_cs_serverless_kubernetes | kube_config | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.187.0 | | alicloud_cs_serverless_kubernetes | load_balancer_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.229.1 | | alicloud_cs_serverless_kubernetes | logging_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.229.1 | | alicloud_cs_serverless_kubernetes | private_zone | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.123.1 | | alicloud_cs_serverless_kubernetes | sls_project_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.229.1 | | alicloud_db_backup_policy | backup_period | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_db_backup_policy | backup_time | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_db_backup_policy | log_backup | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_db_backup_policy | log_retention_period | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_db_backup_policy | retention_period | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_db_database | name | rename | Use data_base_name instead; value semantics unchanged. | v1.267.0 | | alicloud_db_instance | security_group_id | rename | Use security_group_ids instead; value semantics unchanged. | | | alicloud_db_instance | upgrade_db_instance_kernel_version | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.198.0 | | alicloud_dbfs_instance | ecs_list | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.156.0 | | alicloud_dbfs_instance | instance_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.212.0 | | alicloud_ddosbgp_instance | name | rename | Use instance_name instead; value semantics unchanged. | v1.259.0 | | alicloud_ddosbgp_ip | resource_group_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.259.0 | | alicloud_disk_attachment | device_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_dms_enterprise_instance | instance_alias | rename | Use instance_name instead; value semantics unchanged. | v1.100.0 | | alicloud_dms_enterprise_instance | state | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_dms_enterprise_user | nick_name | rename | Use user_name instead; value semantics unchanged. | | | alicloud_eais_instance | force | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.246.0 | | alicloud_ebs_disk_replica_group | group_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.245.0 | | alicloud_ebs_disk_replica_pair | pair_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.245.0 | | alicloud_ecd_simple_office_site | bandwidth | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.142.0 | | alicloud_ecd_simple_office_site | enable_internet_access | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.142.0 | | alicloud_eci_container_group | eci_security_context | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.215.0 | | alicloud_ecs_auto_snapshot_policy | name | rename | Use auto_snapshot_policy_name instead; value semantics unchanged. | v1.236.0 | | alicloud_ecs_deployment_set | domain | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.243.0 | | alicloud_ecs_deployment_set | granularity | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.243.0 | | alicloud_ecs_disk | availability_zone | rename | Use zone_id instead; value semantics unchanged. | v1.122.0 | | alicloud_ecs_disk | name | rename | Use disk_name instead; value semantics unchanged. | v1.122.0 | | alicloud_ecs_key_pair | key_name | rename | Use key_pair_name instead; value semantics unchanged. | v1.121.0 | | alicloud_ecs_key_pair_attachment | key_name | rename | Use key_pair_name instead; value semantics unchanged. | v1.121.0 | | alicloud_ecs_launch_template | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_launch_template | system_disk_category | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_launch_template | system_disk_description | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_launch_template | system_disk_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_launch_template | system_disk_size | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_launch_template | userdata | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ecs_network_interface | name | rename | Use network_interface_name instead; value semantics unchanged. | v1.123.1 | | alicloud_ecs_network_interface | private_ip | rename | Use primary_ip_address instead; value semantics unchanged. | v1.123.1 | | alicloud_ecs_network_interface | private_ips | rename | Use private_ip_addresses instead; value semantics unchanged. | v1.123.1 | | alicloud_ecs_network_interface | private_ips_count | rename | Use secondary_private_ip_address_count instead; value semantics unchanged. | v1.123.1 | | alicloud_ecs_network_interface | security_groups | rename | Use security_group_ids instead; value semantics unchanged. | v1.123.1 | | alicloud_ecs_snapshot | instant_access | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.231.0 | | alicloud_ecs_snapshot | instant_access_retention_days | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.231.0 | | alicloud_ecs_snapshot | name | rename | Use snapshot_name instead; value semantics unchanged. | v1.120.0 | | alicloud_edas_k8s_application | internet_slb_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.194.0 | | alicloud_edas_k8s_application | internet_slb_port | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.194.0 | | alicloud_edas_k8s_application | internet_slb_protocol | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.194.0 | | alicloud_edas_k8s_application | internet_target_port | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.194.0 | | alicloud_eflo_node | computing_server | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.265.0 | | alicloud_eip | name | rename | Use address_name instead; value semantics unchanged. | | | alicloud_eip_address | instance_charge_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.126.0 | | alicloud_eip_address | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.126.0 | | alicloud_elasticsearch_instance | client_node_amount | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | client_node_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_amount | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_disk_encrypted | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_disk_performance_level | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_disk_size | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_disk_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | data_node_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | instance_charge_type | rename | Use payment_type instead; value semantics unchanged. | v1.261.0 | | alicloud_elasticsearch_instance | kibana_node_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | master_node_disk_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | master_node_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | warm_node_amount | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | warm_node_disk_encrypted | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.261.0 | | alicloud_elasticsearch_instance | warm_node_disk_size | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_elasticsearch_instance | warm_node_disk_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_elasticsearch_instance | warm_node_spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_emrv2_cluster | node_group_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.227.0 | | alicloud_emrv2_cluster | node_group_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.227.0 | | alicloud_emrv2_cluster | priority | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.227.0 | | alicloud_ess_scaling_configuration | device | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ess_scaling_configuration | instance_ids | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ess_scaling_configuration | io_optimized | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ess_scaling_group | vswitch_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_express_connect_router_interface | auto_pay | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.263.0 | | alicloud_express_connect_router_interface | opposite_interface_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.263.1 | | alicloud_express_connect_virtual_border_router | associated_physical_connections | split | Inline argument deprecated — declare separate alicloud_express_connect_vbr_pconn_association resource alongside the parent and remove inline associated_physical_connections = …. | v1.263.0 | | alicloud_fcv3_function | acceleration_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.228.0 | | alicloud_fcv3_function | acr_instance_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.228.0 | | alicloud_forward_entry | name | rename | Use forward_entry_name instead; value semantics unchanged. | v1.119.1 | | alicloud_ga_acl | acl_entries | split | Inline argument deprecated — declare separate alicloud_ga_acl_entry_attachment resource alongside the parent and remove inline acl_entries = …. | v1.190.0 | | alicloud_gpdb_instance | availability_zone | rename | Use zone_id instead; value semantics unchanged. | v1.187.0 | | alicloud_gpdb_instance | instance_charge_type | rename | Use payment_type instead; value semantics unchanged. | v1.187.0 | | alicloud_gpdb_instance | master_node_num | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.213.0 | | alicloud_gpdb_instance | private_ip_address | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.213.0 | | alicloud_gpdb_instance | security_ip_list | rename | Use ip_whitelist instead; value semantics unchanged. | v1.187.0 | | alicloud_havip | havip_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_havip_attachment | havip_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.259.0 | | alicloud_hbr_ecs_backup_plan | update_paths | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.139.0 | | alicloud_hbr_nas_backup_plan | create_time | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_hbr_ots_backup_plan | schedule | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_image | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.227.0 | | alicloud_instance | allocate_public_ip | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.7.0 | | alicloud_instance | internet_max_bandwidth_in | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.121.2 | | alicloud_instance | role_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.275.0 | | alicloud_kms_key | deletion_window_in_days | rename | Use pending_window_in_days instead; value semantics unchanged. | v1.85.0 | | alicloud_kms_key | is_enabled | rename | Use status instead; value semantics unchanged. | v1.85.0 | | alicloud_kms_key | key_state | rename | Use status instead; value semantics unchanged. | v1.123.1 | | alicloud_kvstore_instance | availability_zone | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | connection_string | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | connection_string_prefix | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | enable_public | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | instance_charge_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | instance_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_kvstore_instance | node_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.120.1 | | alicloud_kvstore_instance | parameters | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.101.0 | | alicloud_lindorm_instance | time_serires_engine_specification | rename | Use time_series_engine_specification instead; value semantics unchanged. | v1.182.0 | | alicloud_log_alert | condition | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | dashboard | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | notification_list | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | notify_threshold | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | schedule_interval | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | schedule_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_alert | throttling | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_log_project | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.223.0 | | alicloud_log_store | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.215.0 | | alicloud_log_store | project | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.215.0 | | alicloud_message_service_topic | logging_enabled | rename | Use enable_logging instead; value semantics unchanged. | v1.241.0 | | alicloud_nas_access_group | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.218.0 | | alicloud_nas_access_group | type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.218.0 | | alicloud_nat_gateway | instance_charge_type | rename | Use payment_type instead; value semantics unchanged. | v1.121.0 | | alicloud_nat_gateway | name | rename | Use nat_gateway_name instead; value semantics unchanged. | v1.121.0 | | alicloud_network_acl | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.122.0 | | alicloud_nlb_server_group | connection_drain | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.231.0 | | alicloud_ons_instance | name | rename | Use instance_name instead; value semantics unchanged. | v1.97.0 | | alicloud_ons_topic | perm | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_ons_topic | topic | rename | Use topic_name instead; value semantics unchanged. | v1.97.0 | | alicloud_oss_bucket | access_monitor | soft-split | Inline field still works, but conflicts with the standalone alicloud_oss_bucket_access_monitor resource (drift loop on every apply). Prefer declaring alicloud_oss_bucket_access_monitor and dropping the inline field; if the inline field is kept, add lifecycle { ignore_changes = [access_monitor] } to the parent. | | | alicloud_oss_bucket | acl | split | Inline argument deprecated — declare separate alicloud_oss_bucket_acl resource alongside the parent and remove inline acl = …. | v1.220.0 | | alicloud_oss_bucket | logging | soft-split | Inline field still works, but conflicts with the standalone alicloud_oss_bucket_logging resource (drift loop on every apply). Prefer declaring alicloud_oss_bucket_logging and dropping the inline field; if the inline field is kept, add lifecycle { ignore_changes = [logging] } to the parent. | | | alicloud_oss_bucket | logging_isenable | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.37.0 | | alicloud_oss_bucket | policy | split | Inline argument deprecated — declare separate alicloud_oss_bucket_policy resource alongside the parent and remove inline policy = …. | v1.220.0 | | alicloud_oss_bucket | referer_config | split | Inline argument deprecated — declare separate alicloud_oss_bucket_referer resource alongside the parent and remove inline referer_config = …. | v1.220.0 | | alicloud_oss_bucket | transfer_acceleration | soft-split | Inline field still works, but conflicts with the standalone alicloud_oss_bucket_transfer_acceleration resource (drift loop on every apply). Prefer declaring alicloud_oss_bucket_transfer_acceleration and dropping the inline field; if the inline field is kept, add lifecycle { ignore_changes = [transfer_acceleration] } to the parent. | | | alicloud_oss_bucket | versioning | soft-split | Inline field still works, but conflicts with the standalone alicloud_oss_bucket_versioning resource (drift loop on every apply). Prefer declaring alicloud_oss_bucket_versioning and dropping the inline field; if the inline field is kept, add lifecycle { ignore_changes = [versioning] } to the parent. | | | alicloud_oss_bucket | website | soft-split | Inline field still works, but conflicts with the standalone alicloud_oss_bucket_website resource (drift loop on every apply). Prefer declaring alicloud_oss_bucket_website and dropping the inline field; if the inline field is kept, add lifecycle { ignore_changes = [website] } to the parent. | | | alicloud_ots_instance | accessed_by | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.221.0 | | alicloud_polardb_cluster | security_ips | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_polardb_parameter_group | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.263.0 | | alicloud_pvtz_zone | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.107.0 | | alicloud_pvtz_zone_record | resource_record | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.109.0 | | alicloud_ram_group | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.120.0 | | alicloud_ram_policy | action | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.49.0 | | alicloud_ram_policy | document | rename | Use policy_document instead; value semantics unchanged. | v1.114.0 | | alicloud_ram_policy | effect | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.49.0 | | alicloud_ram_policy | name | rename | Use policy_name instead; value semantics unchanged. | v1.114.0 | | alicloud_ram_policy | resource | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.49.0 | | alicloud_ram_policy | statement | rename | Use document instead; value semantics unchanged. | v1.49.0 | | alicloud_ram_policy | version | rename | Use document instead; value semantics unchanged. | v1.49.0 | | alicloud_ram_role | document | rename | Use assume_role_policy_document instead; value semantics unchanged. | v1.252.0 | | alicloud_ram_role | name | rename | Use role_name instead; value semantics unchanged. | v1.252.0 | | alicloud_ram_role | ram_users | rename | Use document instead; value semantics unchanged. | v1.49.0 | | alicloud_ram_role | services | rename | Use document instead; value semantics unchanged. | v1.49.0 | | alicloud_ram_role | version | rename | Use document instead; value semantics unchanged. | v1.49.0 | | alicloud_ram_security_preference | enforce_mfa_for_login | rename | Use mfa_operation_for_login instead; value semantics unchanged. | v1.248.0 | | alicloud_rds_account | description | rename | Use account_description instead; value semantics unchanged. | v1.120.0 | | alicloud_rds_account | instance_id | rename | Use db_instance_id instead; value semantics unchanged. | v1.120.0 | | alicloud_rds_account | name | rename | Use account_name instead; value semantics unchanged. | v1.120.0 | | alicloud_rds_account | password | rename | Use account_password instead; value semantics unchanged. | v1.120.0 | | alicloud_rds_account | type | rename | Use account_type instead; value semantics unchanged. | v1.120.0 | | alicloud_reserved_instance | name | rename | Use reserved_instance_name instead; value semantics unchanged. | v1.194.0 | | alicloud_resource_manager_account | abandon_able_check_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.249.0 | | alicloud_resource_manager_policy | default_version | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_resource_manager_policy_version | is_default_version | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_resource_manager_resource_group | name | rename | Use resource_group_name instead; value semantics unchanged. | v1.114.0 | | alicloud_rocketmq_instance | ip_whitelist | rename | Use ip_whitelists instead; value semantics unchanged. | v1.245.0 | | alicloud_rocketmq_instance | vswitch_id | rename | Use vswitches instead; value semantics unchanged. | v1.231.0 | | alicloud_route_entry | router_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_route_table | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.119.1 | | alicloud_router_interface | access_point_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_router_interface | opposite_access_point_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_router_interface | opposite_interface_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_router_interface | opposite_interface_owner_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_router_interface | opposite_router_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_router_interface | opposite_router_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_sae_application | command_args | rename | Use command_args_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | config_map_mount_desc | rename | Use config_map_mount_desc_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | custom_host_alias | rename | Use custom_host_alias_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | liveness | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.211.0 | | alicloud_sae_application | oss_mount_descs | rename | Use oss_mount_descs_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | post_start | rename | Use post_start_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | pre_stop | rename | Use pre_stop_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_sae_application | readiness | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.211.0 | | alicloud_sae_application | tomcat_config | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.211.0 | | alicloud_sae_application | update_strategy | rename | Use update_strategy_v2 instead; value semantics unchanged. | v1.211.0 | | alicloud_scdn_domain | biz_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | | | alicloud_security_group | inner_access | rename | Use inner_access_policy instead; value semantics unchanged. | v1.55.3 | | alicloud_security_group | name | rename | Use security_group_name instead; value semantics unchanged. | v1.239.0 | | alicloud_selectdb_db_instance | upgraded_engine_minor_version | rename | Use engine_minor_version instead; value semantics unchanged. | v1.248.0 | | alicloud_slb | name | rename | Use load_balancer_name instead; value semantics unchanged. | v1.123.1 | | alicloud_slb | specification | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.123.1 | | alicloud_slb_acl | entry_list | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.162.0 | | alicloud_slb_ca_certificate | name | rename | Use ca_certificate_name instead; value semantics unchanged. | | | alicloud_slb_listener | acl_id | rename | Use acl_ids instead; value semantics unchanged. | v1.249.0 | | alicloud_slb_listener | ssl_certificate_id | rename | Use server_certificate_id instead; value semantics unchanged. | v1.59.0 | | alicloud_slb_load_balancer | internet | rename | Use address_type instead; value semantics unchanged. | v1.124.0 | | alicloud_slb_load_balancer | name | rename | Use load_balancer_name instead; value semantics unchanged. | v1.123.1 | | alicloud_slb_load_balancer | specification | rename | Use load_balancer_spec instead; value semantics unchanged. | v1.123.1 | | alicloud_slb_server_group | servers | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.163.0 | | alicloud_ssl_certificates_service_certificate | lang | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.260.1 | | alicloud_ssl_certificates_service_certificate | name | rename | Use certificate_name instead; value semantics unchanged. | v1.129.0 | | alicloud_threat_detection_instance | container_image_scan | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.247.0 | | alicloud_threat_detection_instance | post_pay_module_switch | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.269.0 | | alicloud_vpc | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.119.0 | | alicloud_vpc | router_table_id | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.227.1 | | alicloud_vpc | secondary_cidr_blocks | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.185.0 | | alicloud_vpc | secondary_cidr_mask | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.248.0 | | alicloud_vpc_dhcp_options_set | associate_vpcs | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.153.0 | | alicloud_vpc_ha_vip | havip_name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.259.0 | | alicloud_vpc_ipv6_gateway | spec | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.205.0 | | alicloud_vpc_traffic_mirror_filter_egress_rule | rule_action | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.211.0 | | alicloud_vpc_traffic_mirror_filter_ingress_rule | rule_action | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.211.0 | | alicloud_vpn_connection | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.216.0 | | alicloud_vpn_customer_gateway | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.216.0 | | alicloud_vpn_gateway | instance_charge_type | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.216.0 | | alicloud_vpn_gateway | name | deprecated-no-replacement | Deprecated without a documented replacement — stop using this field. | v1.216.0 | | alicloud_vswitch | availability_zone | rename | Use zone_id instead; value semantics unchanged. | v1.119.0 | | alicloud_vswitch | name | rename | Use vswitch_name instead; value semantics unchanged. | v1.119.0 | | alicloud_waf_domain | domain | rename | Use domain_name instead; value semantics unchanged. | v1.94.0 |
Product-specific resource patterns
Positive patterns — "when the user asks X, use these attributes or multi-resource idioms". This complements:
alicloud-providers.md(catalog: does this resource exist? any
deprecation?)
deprecated-fields.md(field-level renames / splits / soft-splits)
Entries here are product-specific conventions that the provider doc technically documents but does not emphasize, leading agents to miss them. Consult this file during Step 5.1 whenever the user's requirement touches a product listed below.
---
RDS cross-AZ primary/secondary HA
Trigger phrases: "高可用 / HA / 主从架构 / 多可用区 / 跨可用区 / primary-secondary / master-slave" applied to alicloud_db_instance.
Non-obvious requirement: the provider doc lists zone_id_slave_a as optional. Agents often set category = "HighAvailability" alone and assume alicloud places the standby automatically in a different AZ. It does not — without zone_id_slave_a, primary and standby land in the same AZ, defeating the user's cross-AZ intent.
Required attributes on `alicloud_db_instance`:
| Attribute | Value | Why |
|---|---|---|
category | "HighAvailability" | Switches the edition. multi_az = true and ha_config = "Auto" do not replace this. |
zone_id | data.alicloud_db_zones.<n>.zones[0].id | Primary AZ. |
zone_id_slave_a | data.alicloud_db_zones.<n>.zones[1].id | Secondary AZ. MUST differ from zone_id. |
Sketch:
data "alicloud_db_zones" "mysql_ha" {
engine = "MySQL"
engine_version = "8.0"
category = "HighAvailability"
db_instance_storage_type = "cloud_essd"
}
resource "alicloud_db_instance" "this" {
engine = "MySQL"
engine_version = "8.0"
category = "HighAvailability"
db_instance_storage_type = "cloud_essd"
instance_type = var.rds_instance_type
instance_storage = 100
zone_id = data.alicloud_db_zones.mysql_ha.zones[0].id
zone_id_slave_a = data.alicloud_db_zones.mysql_ha.zones[1].id
# ... vswitch_id, security_group_ids, security_ips, etc.
}---
OSS lifecycle — current vs noncurrent versions
Trigger phrases: "旧版本 / historical versions / noncurrent / old object versions / N 天后(转 IA|归档)" applied to an alicloud_oss_bucket with a lifecycle rule.
Non-obvious requirement: the lifecycle_rule block has TWO transition sub-blocks with different targets — picking the wrong one transitions the wrong objects.
| Sub-block | Targets | When to use |
|---|---|---|
transition { days = N, storage_class = … } (or transitions) | Current object version | User says "文件 N 天后转 IA" (current objects) |
noncurrent_version_transition { days = N, storage_class = … } | Older / noncurrent versions | User says "旧版本 / 历史版本 / noncurrent …" |
Versioning MUST be enabled on the bucket (via alicloud_oss_bucket_versioning, see deprecated-fields.md) for noncurrent_version_transition to have any effect.
Sketch:
resource "alicloud_oss_bucket" "this" {
bucket = var.bucket_name
lifecycle_rule {
id = "archive-old-versions"
prefix = ""
enabled = true
# user said "旧版本 90 天后转 IA" → use noncurrent_version_transition
noncurrent_version_transition {
days = 90
storage_class = "IA"
}
}
}
resource "alicloud_oss_bucket_versioning" "this" {
bucket = alicloud_oss_bucket.this.bucket
status = "Enabled"
}---
OSS bucket — split sub-resource defaults
Trigger phrases: writing alicloud_oss_bucket where a split/soft-split sub-resource is needed by user intent or by the safe-default table below (acl, logging, versioning, website, cors, etc. — see deprecated-fields.md for the full list).
Non-obvious requirement: do not generate every split sub-resource just because it exists. Generate the safe defaults below only where listed; otherwise create the sub-resource only when the user asks for that feature. For ACL, never pick public-read without public-access intent — default to private.
| Sub-resource | Default value when no user intent specified |
|---|---|
alicloud_oss_bucket_acl | acl = "private" |
alicloud_oss_bucket_versioning | status = "Suspended" |
alicloud_oss_bucket_logging | Omit the sub-resource (logging disabled) |
alicloud_oss_bucket_cors | Omit the sub-resource (no CORS) |
alicloud_oss_bucket_website | Omit the sub-resource (no static website) |
Only use permissive values (public-read, Enabled, etc.) when the user explicitly described a public-access scenario: "静态网站 / 托管网站 / public / CDN / CORS / website / 版本控制".
---
FCv3 function — mandatory RAM role + service access policy
Trigger phrases: any alicloud_fcv3_function (or its deprecated name alicloud_fc_function) where the function needs to access other Alibaba Cloud services — OSS, RDS, LogService, VPC resources, etc. Also triggers when the user mentions permissions like "读写 / read-write / access / 访问 / 权限".
Non-obvious requirement: the agent often generates only the function resource and skips the RAM role because the user never said "create a role". BUT — without a RAM role with sts:AssumeRole for fc.aliyuncs.com, the function has no identity outside itself and cannot reach any other service. This is NOT a style preference; it is a functional requirement for any function that talks to OSS, RDS, or any other alicloud resource.
Required additional resources on the Step 3 sketch: When the FC function accesses another service, you MUST add these two resources to the sketch, even if the user didn't name them:
| Resource | Purpose |
|---|---|
alicloud_ram_role | Identity the function assumes. Trust policy: Principal.Service = ["fc.aliyuncs.com"], Action: sts:AssumeRole. |
alicloud_ram_role_policy_attachment | Binds the access policy to the role. Use the policy name AliyunOSSFullAccess, AliyunRDSFullAccess, etc., or attach a custom alicloud_ram_policy. |
Attach without a previous alicloud_ram_role → skip the role and policy attachment is a generation defect, not "clean minimal code". The role attribute on alicloud_fcv3_function accepts either alicloud_ram_role.<n>.arn (preferred) or alicloud_ram_role.<n>.role_name — both resolve correctly.
Note on deprecated fields on alicloud_ram_role:
name→ userole_nameinstead (seedeprecated-fields.md)document→ useassume_role_policy_documentinstead
Sketch:
resource "alicloud_ram_role" "fc" {
role_name = "${var.project_name}-fc-role"
assume_role_policy_document = jsonencode({
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = { Service = ["fc.aliyuncs.com"] }
}]
Version = "1"
})
}
resource "alicloud_ram_role_policy_attachment" "fc_oss" {
role_name = alicloud_ram_role.fc.role_name
policy_name = "AliyunOSSFullAccess"
policy_type = "System"
}
resource "alicloud_fcv3_function" "this" {
function_name = "${var.project_name}-fn"
runtime = "python3.10"
memory_size = 256
role = alicloud_ram_role.fc.arn # preferred
# role = alicloud_ram_role.fc.role_name # also works
# ... code, handler, etc.
}---
How to extend
Add a new ## section per product when you find a pattern that:
1. Is a real product idiom (not a workaround for a bug). 2. Is not obvious from the provider doc alone — the doc technically documents it but does not emphasize it, so agents miss it. 3. Is NOT already captured as a rename / split / soft-split in deprecated-fields.md — that file owns deprecation-style patterns.
Each entry: trigger phrases → non-obvious requirement → table of attributes → short HCL sketch.
#!/usr/bin/env python3
"""Build references/alicloud-providers.md from the terraform-provider-alicloud repo.
Clones (or reuses) the provider repo, walks website/docs/{r,d}/*.html.markdown,
extracts subcategory + deprecation status, and writes a subcategory-grouped
markdown catalog to references/alicloud-providers.md.
Usage:
scripts/build_alicloud_providers.py # clone or pull, regenerate
scripts/build_alicloud_providers.py --no-refresh # reuse existing clone as-is
scripts/build_alicloud_providers.py --repo PATH # use an existing checkout
scripts/build_alicloud_providers.py --out PATH # override output path
The SKILL's Step 4.1 reads the generated file. Re-run this script when
`aliyun/terraform-provider-alicloud` publishes a new release or when deprecation
marks shift (check the provider CHANGELOG).
"""
from __future__ import annotations
import argparse
import re
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
PROVIDER_REPO = "https://github.com/aliyun/terraform-provider-alicloud.git"
DEFAULT_CLONE = "/tmp/terraform-provider-alicloud"
BLOB_PREFIX = "https://github.com/aliyun/terraform-provider-alicloud/blob/master/website/docs"
FRONTMATTER_RE = re.compile(r"\A---\n(.*?)\n---\n(.*)", re.DOTALL)
SUBCAT_RE = re.compile(r'^subcategory:\s*["\']?([^"\'\n]+?)["\']?\s*$', re.MULTILINE)
DEPRECATED_MARKER_RE = re.compile(
r"->\s*\*\*DEPRECAT[A-Z]+(?:\s+NOTICE)?\*?[:\s\*]",
re.IGNORECASE,
)
# Replacement extraction: cascade (a)→(d), first non-self match wins.
# (a) `[alicloud_X](...)` — markdown link text carrying the prefix.
LINK_TEXT_RE = re.compile(r"\[(alicloud_[a-z0-9_]+)\]")
# (b) link to terraform docs whose URL slug names the replacement (no prefix in
# link text, e.g. `[emrv2_cluster](https://registry.terraform.io/.../resources/emrv2_cluster)`).
REGISTRY_LINK_SLUG_RE = re.compile(
r"\]\([^)]*/(?:resources|data-sources|r|d)/([a-z0-9_]+)"
)
# (c) inline code `alicloud_X`.
BACKTICK_REF_RE = re.compile(r"`(alicloud_[a-z0-9_]+)`")
# (d) last-resort bare token.
BARE_REF_RE = re.compile(r"\b(alicloud_[a-z0-9_]+)\b")
def ensure_repo(clone_dir: Path) -> None:
if (clone_dir / ".git").exists():
print(f"[info] refreshing existing clone at {clone_dir}", file=sys.stderr)
subprocess.run(
["git", "-C", str(clone_dir), "pull", "--ff-only"],
check=False,
timeout=300,
)
return
clone_dir.parent.mkdir(parents=True, exist_ok=True)
print(f"[info] cloning provider repo to {clone_dir}", file=sys.stderr)
subprocess.run(
[
"git", "clone", "--depth", "1", "--filter=blob:none", "--sparse",
PROVIDER_REPO, str(clone_dir),
],
check=True,
timeout=600,
)
subprocess.run(
["git", "-C", str(clone_dir), "sparse-checkout", "set", "website/docs"],
check=True,
timeout=60,
)
def parse_doc(path: Path, kind: str) -> dict:
"""kind is 'r' (resource) or 'd' (data source)."""
text = path.read_text(encoding="utf-8", errors="replace")
subcategory = "Other"
body = text
m = FRONTMATTER_RE.match(text)
if m:
body = m.group(2)
sm = SUBCAT_RE.search(m.group(1))
if sm and sm.group(1).strip():
subcategory = sm.group(1).strip()
name_stem = path.name[: -len(".html.markdown")]
name = f"alicloud_{name_stem}"
deprecated = False
replacement: str | None = None
dm = DEPRECATED_MARKER_RE.search(body)
if dm:
deprecated = True
# Scope the search to the DEPRECATED admonition paragraph only — stop at
# the next markdown H2 or the next `-> **<WORD>:` admonition so Example
# Usage and unrelated NOTE blocks (e.g. field-level deprecation hints)
# can't contribute false positives.
start = dm.end()
stops = [body.find("\n## ", start), body.find("\n\n-> **", start)]
stops = [s for s in stops if s != -1]
region = body[start:min(stops)] if stops else body[start:]
def _first_non_self(iterator, transform=lambda m: m.group(1)):
for m in iterator:
candidate = transform(m)
if not candidate.startswith("alicloud_"):
candidate = f"alicloud_{candidate}"
if candidate != name:
return candidate
return None
replacement = (
_first_non_self(LINK_TEXT_RE.finditer(region))
or _first_non_self(REGISTRY_LINK_SLUG_RE.finditer(region))
or _first_non_self(BACKTICK_REF_RE.finditer(region))
or _first_non_self(BARE_REF_RE.finditer(region))
)
return {
"name": name,
"subcategory": subcategory,
"deprecated": deprecated,
"replacement": replacement,
"kind": "resource" if kind == "r" else "data source",
"url": f"{BLOB_PREFIX}/{kind}/{path.name}",
}
def emit_markdown(entries: list[dict], out_path: Path) -> None:
by_cat: dict[str, list[dict]] = defaultdict(list)
for entry in entries:
by_cat[entry["subcategory"]].append(entry)
for cat_entries in by_cat.values():
cat_entries.sort(key=lambda e: (e["kind"], e["name"]))
total = len(entries)
res_count = sum(1 for e in entries if e["kind"] == "resource")
data_count = total - res_count
dep_count = sum(1 for e in entries if e["deprecated"])
lines: list[str] = [
"# Alibaba Cloud Terraform provider catalog",
"",
f"Total entries: **{total}** "
f"(resources: {res_count}, data sources: {data_count}; "
f"deprecated: {dep_count}).",
"",
"Built from `aliyun/terraform-provider-alicloud@master` by "
"`scripts/build_alicloud_providers.py`. Re-run the script to refresh.",
"",
"Columns — **type** (resource / data source), **name** (`alicloud_*`), "
"**status** (empty = supported; `⚠️ 弃用 → alicloud_X` = deprecated, "
"use X; `⚠️ 弃用` = deprecated without a direct replacement), "
"**doc** (GitHub source, used by Step 4.2 WebFetch).",
"",
]
for cat in sorted(by_cat):
lines.append(f"## {cat}")
lines.append("")
lines.append("| type | name | status | doc |")
lines.append("| --- | --- | --- | --- |")
for entry in by_cat[cat]:
status = ""
if entry["deprecated"]:
status = (
f"⚠️ 弃用 → `{entry['replacement']}`"
if entry["replacement"]
else "⚠️ 弃用"
)
lines.append(
f"| {entry['kind']} | `{entry['name']}` | {status} "
f"| [doc]({entry['url']}) |"
)
lines.append("")
out_path.parent.mkdir(parents=True, exist_ok=True)
out_path.write_text("\n".join(lines), encoding="utf-8")
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"--repo",
default=DEFAULT_CLONE,
help=f"Local clone path (default: {DEFAULT_CLONE}).",
)
parser.add_argument(
"--out",
default=None,
help="Output markdown path (default: <skill_root>/references/alicloud-providers.md).",
)
parser.add_argument(
"--no-refresh",
action="store_true",
help="Skip git clone/pull; use the existing repo as-is.",
)
args = parser.parse_args()
repo = Path(args.repo).expanduser().resolve()
if not args.no_refresh:
ensure_repo(repo)
docs_r = repo / "website" / "docs" / "r"
docs_d = repo / "website" / "docs" / "d"
if not docs_r.is_dir() or not docs_d.is_dir():
print(
f"[error] docs dirs missing under {repo}; expected website/docs/{{r,d}}. "
f"Re-clone with: rm -rf {repo} && python scripts/build_alicloud_providers.py",
file=sys.stderr,
)
sys.exit(1)
entries: list[dict] = []
for md in sorted(docs_r.glob("*.html.markdown")):
entries.append(parse_doc(md, "r"))
for md in sorted(docs_d.glob("*.html.markdown")):
entries.append(parse_doc(md, "d"))
skill_root = Path(__file__).resolve().parent.parent
out_path = (
Path(args.out).expanduser().resolve()
if args.out
else skill_root / "references" / "alicloud-providers.md"
)
emit_markdown(entries, out_path)
dep = sum(1 for e in entries if e["deprecated"])
print(
f"[ok] wrote {out_path} ({len(entries)} entries, {dep} deprecated)",
file=sys.stderr,
)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# ruff: noqa
r"""Build references/deprecated-fields.md from the terraform-provider-alicloud repo.
Scans website/docs/r/*.html.markdown for three kinds of field-level
deprecations and emits a merged markdown table.
Categories detected:
1. **Rename** — field's Argument Reference line has `(Deprecated since vX.Y.Z)`
and a description like `New field \`<Y>\` instead.` → emit `field → Y`.
2. **Hard split** — field's Argument Reference line has `(Deprecated since …)`
and description like `please use the resource \`alicloud_<X>\` instead` →
emit `field → alicloud_<X>` (separate resource).
3. **Soft split** — field is NOT marked deprecated in its own Argument
Reference line, BUT the parent resource has a NOTE block like
`-> **NOTE:** ... standalone sub-resources ... (alicloud_X_Y, …)` AND
`alicloud_<parent>_<field>` exists as a separate resource file. Typical
example: `alicloud_oss_bucket.logging` / `alicloud_oss_bucket.versioning`
(the doc never uses the word "Deprecated" for these fields, but the NOTE
tells users to use the standalone resources instead).
Case 4 — unclassified `Deprecated since` lines with no clear replacement —
is emitted in a tail section so maintainers can hand-curate.
Hand-curated supplement (optional):
references/deprecated-fields-manual.yaml
If present, its entries are merged into the output. Structure:
entries:
- resource: alicloud_X
field: Y
replacement: Z # optional; either a field name or alicloud_Z
kind: rename|split|soft # optional; defaults based on replacement
since: v1.A.B # optional
note: free-form # optional
Usage:
scripts/build_deprecated_fields.py # clone or pull, regen
scripts/build_deprecated_fields.py --no-refresh # reuse existing clone
scripts/build_deprecated_fields.py --repo PATH
scripts/build_deprecated_fields.py --out PATH
"""
from __future__ import annotations
import argparse
import re
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
PROVIDER_REPO = "https://github.com/aliyun/terraform-provider-alicloud.git"
DEFAULT_CLONE = "/tmp/terraform-provider-alicloud"
DOC_URL_PREFIX = (
"https://github.com/aliyun/terraform-provider-alicloud/blob/master/website/docs/r"
)
SUFFIX = ".html.markdown"
# Field line in Argument Reference, e.g.:
# * `name` - (Optional, Deprecated since v1.239.0) Field `name` has been ...
FIELD_LINE_RE = re.compile(
r"^\*\s+`([a-z_][a-z0-9_]*)`\s*-\s*\(([^)]*)\)\s*(.*)$",
re.MULTILINE,
)
# Version inside the parentheses, e.g. "Deprecated since v1.239.0", or
# "Deprecated since 1.220.0", "Deprecated from 1.37.0", "Deprecated from v1.166.0+"
DEPRECATED_VER_RE = re.compile(
r"Deprecated\s+(?:since|from)\s+v?(\d+\.\d+(?:\.\d+)?)",
re.IGNORECASE,
)
# Replacement extraction from the description text:
# (a) "New field `<X>` instead" / "New attribute `<X>` instead" — rename
NEW_FIELD_RE = re.compile(
r"[Nn]ew\s+(?:field|attribute)\s+`([a-z_][a-z0-9_]*)`\s+(?:and\s+)?instead",
re.IGNORECASE,
)
# (b) Hard split — field → separate resource. Covers:
# "please use the resource `alicloud_X` instead"
# "please use the new resource `alicloud_X`"
# "please use resource alicloud_X"
HARD_SPLIT_RE = re.compile(
r"[Pp]lease\s+use\s+(?:the\s+)?(?:new\s+)?(?:standalone\s+)?resource\s+"
r"`?(alicloud_[a-z0-9_]+)`?",
re.IGNORECASE,
)
# (c) Generic rename fallbacks:
# "use `<X>` instead" / "using `<X>` instead" / "Use `X` and instead"
# "Please use `<X>` instead"
# "Please use `<X>` to (instead|replace|managed ...)"
# "replaced by `<X>`"
USE_FIELD_RE = re.compile(
r"(?:[Pp]lease\s+)?[Uu]s(?:e|ing)\s+`([a-z_][a-z0-9_]*)`\s+(?:and\s+)?instead",
re.IGNORECASE,
)
USE_TO_RE = re.compile(
r"[Pp]lease\s+use\s+`([a-z_][a-z0-9_]*)`\s+to\s+(?:instead|replace|managed?)",
re.IGNORECASE,
)
REPLACED_BY_RE = re.compile(
r"replaced\s+by\s+`([a-z_][a-z0-9_]*)`",
re.IGNORECASE,
)
# NOTE block mentioning standalone sub-resources. We match the whole
# paragraph then extract `alicloud_*` tokens from it.
NOTE_STANDALONE_RE = re.compile(
r"->\s*\*\*NOTE:\*\*[^\n]*standalone\s+(?:sub-)?resource[^\n]*",
re.IGNORECASE,
)
ALICLOUD_TOKEN_RE = re.compile(r"`(alicloud_[a-z0-9_]+)`")
def ensure_repo(clone_dir: Path) -> None:
if (clone_dir / ".git").exists():
print(f"[info] refreshing existing clone at {clone_dir}", file=sys.stderr)
subprocess.run(
["git", "-C", str(clone_dir), "pull", "--ff-only"], check=False,
timeout=300,
)
return
clone_dir.parent.mkdir(parents=True, exist_ok=True)
print(f"[info] cloning provider repo to {clone_dir}", file=sys.stderr)
subprocess.run(
[
"git", "clone", "--depth", "1", "--filter=blob:none", "--sparse",
PROVIDER_REPO, str(clone_dir),
],
check=True,
timeout=600,
)
subprocess.run(
["git", "-C", str(clone_dir), "sparse-checkout", "set", "website/docs"],
check=True,
timeout=60,
)
def extract_fields(path: Path) -> list[dict]:
"""Return list of {field, annots, desc} for every Argument Reference field."""
text = path.read_text(encoding="utf-8", errors="replace")
out = []
for m in FIELD_LINE_RE.finditer(text):
out.append({
"field": m.group(1),
"annots": m.group(2),
"desc": m.group(3) or "",
"_text_start": m.start(),
})
return out
def extract_note_standalone(path: Path) -> list[str]:
"""Return list of alicloud_* resource names referenced in NOTE-standalone blocks."""
text = path.read_text(encoding="utf-8", errors="replace")
tokens: list[str] = []
for m in NOTE_STANDALONE_RE.finditer(text):
# Take a window of ~1500 chars after the NOTE start to capture the list
window = text[m.start(): m.start() + 1500]
# Stop at next heading or blank-line-separated paragraph
# Simple approach: collect all alicloud_X in the window up to first "\n\n" or "\n##"
stop = min(
(s for s in [window.find("\n\n"), window.find("\n##")] if s != -1),
default=len(window),
)
chunk = window[:stop]
for tm in ALICLOUD_TOKEN_RE.finditer(chunk):
tokens.append(tm.group(1))
return tokens
def build_entries(docs_r: Path, all_resources: set[str]) -> list[dict]:
"""Emit a flat list of entries classified by kind."""
entries: list[dict] = []
for md in sorted(docs_r.glob(f"*{SUFFIX}")):
parent = md.name[: -len(SUFFIX)]
parent_full = f"alicloud_{parent}"
text = md.read_text(encoding="utf-8", errors="replace")
fields = extract_fields(md)
hard_deprecated_field_names: set[str] = set()
# Pass A — field lines marked Deprecated
for f in fields:
if "Deprecated" not in f["annots"]:
continue
hard_deprecated_field_names.add(f["field"])
ver_m = DEPRECATED_VER_RE.search(f["annots"])
version = f"v{ver_m.group(1)}" if ver_m else None
# Prefer hard-split phrasing first (more specific), then rename.
split_m = HARD_SPLIT_RE.search(f["desc"])
rename_m = NEW_FIELD_RE.search(f["desc"])
fallback_m = (
USE_FIELD_RE.search(f["desc"])
or USE_TO_RE.search(f["desc"])
or REPLACED_BY_RE.search(f["desc"])
)
if split_m:
entries.append({
"resource": parent_full,
"field": f["field"],
"replacement": split_m.group(1),
"kind": "split",
"since": version,
"source": "doc:field-annotation",
})
elif rename_m:
entries.append({
"resource": parent_full,
"field": f["field"],
"replacement": rename_m.group(1),
"kind": "rename",
"since": version,
"source": "doc:field-annotation",
})
elif fallback_m:
entries.append({
"resource": parent_full,
"field": f["field"],
"replacement": fallback_m.group(1),
"kind": "rename",
"since": version,
"source": "doc:field-annotation",
})
else:
entries.append({
"resource": parent_full,
"field": f["field"],
"replacement": None,
"kind": "deprecated-no-replacement",
"since": version,
"source": "doc:field-annotation",
})
# Pass B — soft splits. Trigger when the parent doc has ANY
# "NOTE: ... standalone (sub-)resource ..." block. Within such
# a parent, any non-deprecated field whose name matches an existing
# `{parent}_{field}` resource is flagged as a soft-split candidate.
# This catches cases the NOTE explicitly names AND adjacent cases
# the NOTE happens to omit (e.g. alicloud_oss_bucket.access_monitor).
note_tokens = extract_note_standalone(md)
has_standalone_note = bool(NOTE_STANDALONE_RE.search(text))
note_named = {t for t in note_tokens if t.startswith(f"{parent_full}_")}
if has_standalone_note:
for f in fields:
if f["field"] in hard_deprecated_field_names:
continue # already covered as hard deprecation
sub_guess = f"{parent_full}_{f['field']}"
if sub_guess in all_resources:
entries.append({
"resource": parent_full,
"field": f["field"],
"replacement": sub_guess,
"kind": "soft-split",
"since": None,
"source": (
"doc:NOTE-standalone"
if sub_guess in note_named
else "doc:NOTE-standalone+collision"
),
})
return entries
# --- manual supplement ---------------------------------------------------
def load_manual(manual_path: Path) -> list[dict]:
if not manual_path.exists():
return []
try:
import yaml # type: ignore
except ImportError:
print(
f"[warn] pyyaml not installed; skipping {manual_path}. "
f"Install with: pip install pyyaml",
file=sys.stderr,
)
return []
data = yaml.safe_load(manual_path.read_text()) or {}
entries = []
for e in data.get("entries", []):
kind = e.get("kind")
if not kind:
repl = e.get("replacement", "")
if repl.startswith("alicloud_"):
kind = "split"
else:
kind = "rename" if repl else "deprecated-no-replacement"
entries.append({
"resource": e["resource"],
"field": e["field"],
"replacement": e.get("replacement"),
"kind": kind,
"since": e.get("since"),
"source": f"manual:{manual_path.name}",
"note": e.get("note"),
})
return entries
# --- rendering -----------------------------------------------------------
# This file is consumed via grep, not read front-to-back. One line per
# (resource, field) — the "Action" column is self-contained so any matched
# row tells the reader exactly what to do.
HEADER_V2 = (
"<!-- Auto-generated by scripts/build_deprecated_fields.py. "
"Do not edit by hand; re-run the script to refresh. "
"Manual supplements via references/deprecated-fields-manual.yaml. -->\n"
"\n"
"| Resource | Field | Kind | Action | Since |\n"
"| --- | --- | --- | --- | --- |\n"
)
def _action_cell(e: dict) -> str:
"""Self-contained instruction that tells you what to do when this row grep-matches."""
kind = e.get("kind")
repl = e.get("replacement")
field = e.get("field")
note = (e.get("note") or "").strip()
if kind == "rename" and repl:
msg = f"Use `{repl}` instead; value semantics unchanged."
elif kind == "split" and repl:
msg = (
f"Inline argument deprecated — declare separate `{repl}` resource "
f"alongside the parent and remove inline `{field} = …`."
)
elif kind == "soft-split" and repl:
msg = (
f"Inline field still works, but conflicts with the standalone "
f"`{repl}` resource (drift loop on every apply). Prefer declaring "
f"`{repl}` and dropping the inline field; if the inline field is "
f"kept, add `lifecycle {{ ignore_changes = [{field}] }}` to the parent."
)
elif kind == "deprecated-no-replacement":
msg = "Deprecated without a documented replacement — stop using this field."
else:
msg = "Deprecated."
if note:
msg += f" — {note}"
return msg
def render(entries: list[dict]) -> str:
# Deduplicate by (resource, field); first occurrence wins.
seen: dict[tuple[str, str], dict] = {}
for e in entries:
key = (e["resource"], e["field"])
if key in seen:
existing = seen[key]
if not existing.get("note") and e.get("note"):
existing["note"] = e["note"]
continue
seen[key] = dict(e)
rows = sorted(seen.values(), key=lambda x: (x["resource"], x["field"]))
out: list[str] = [HEADER_V2]
for e in rows:
since = e.get("since") or ""
kind = e.get("kind", "")
action = _action_cell(e)
out.append(
f"| `{e['resource']}` | `{e['field']}` | {kind} | {action} | {since} |"
)
return "\n".join(out) + "\n"
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--repo", default=DEFAULT_CLONE)
parser.add_argument("--out", default=None)
parser.add_argument("--no-refresh", action="store_true")
args = parser.parse_args()
repo = Path(args.repo).expanduser().resolve()
if not args.no_refresh:
ensure_repo(repo)
docs_r = repo / "website" / "docs" / "r"
if not docs_r.is_dir():
print(f"[error] {docs_r} not found", file=sys.stderr)
sys.exit(1)
all_resources = {f"alicloud_{p.name[:-len(SUFFIX)]}" for p in docs_r.glob(f"*{SUFFIX}")}
entries = build_entries(docs_r, all_resources)
skill_root = Path(__file__).resolve().parent.parent
manual_path = skill_root / "references" / "deprecated-fields-manual.yaml"
entries.extend(load_manual(manual_path))
out_path = (
Path(args.out).expanduser().resolve()
if args.out
else skill_root / "references" / "deprecated-fields.md"
)
out_path.parent.mkdir(parents=True, exist_ok=True)
out_path.write_text(render(entries), encoding="utf-8")
by_kind: dict[str, int] = defaultdict(int)
for e in entries:
by_kind[e["kind"]] += 1
print(
f"[ok] wrote {out_path} "
f"({len(entries)} entries: "
f"{by_kind.get('rename', 0)} rename, "
f"{by_kind.get('split', 0)} split, "
f"{by_kind.get('soft-split', 0)} soft-split, "
f"{by_kind.get('deprecated-no-replacement', 0)} no-replacement)",
file=sys.stderr,
)
if __name__ == "__main__":
main()