|
| 1 | +## Context |
| 2 | + |
| 3 | +TEO (EdgeOne) exposes a `CreatePlanForZone` API in the vendored SDK `teo/v20220901` (verified present — no SDK upgrade needed): |
| 4 | + |
| 5 | +- `CreatePlanForZone(request)` — purchases a plan for a zone that has not yet bound a plan. Request inputs: `ZoneId *string`, `PlanType *string`. Response outputs: `ResourceNames []*string`, `DealNames []*string`, `RequestId *string`. |
| 6 | +- The API is synchronous; no async task/polling is needed. |
| 7 | + |
| 8 | +This is a **one-time operation resource** (RESOURCE_KIND_OPERATION), following the style of `tencentcloud_teo_identify_zone_operation`: it has `Create`, `Read`, `Delete` (no `Update`), performs the action on Create, and treats Read/Delete as no-ops. Unlike `tencentcloud_teo_plan` (which uses the separate `CreatePlan` API and is a full CRUD resource), this resource targets a zone that has no bound plan and only performs the purchase action. |
| 9 | + |
| 10 | +## Goals / Non-Goals |
| 11 | + |
| 12 | +**Goals:** |
| 13 | +- Trigger plan purchase for a zone via `CreatePlanForZone` on create, with retry and nil-safe response handling. |
| 14 | +- Auto-generate the resource ID (per business rule), using `helper.BuildToken()`. |
| 15 | +- Surface the response's `ResourceNames` and `DealNames` as computed attributes. |
| 16 | +- Ship resource example `.md`, website docs, unit test, and provider registration. |
| 17 | + |
| 18 | +**Non-Goals:** |
| 19 | +- No revert/cancel of a purchased plan on delete (the API has no such capability); Delete is a no-op. |
| 20 | +- No Read API to query purchase status; Read is a no-op that returns nil. |
| 21 | +- No Timeouts block (synchronous call, no async status polling needed). |
| 22 | + |
| 23 | +## Decisions |
| 24 | + |
| 25 | +### Resource name and file layout |
| 26 | +- Resource: `tencentcloud_teo_plan_for_zone` |
| 27 | +- Files under `tencentcloud/services/teo/`: |
| 28 | + - `resource_tc_teo_plan_for_zone_operation.go` |
| 29 | + - `resource_tc_teo_plan_for_zone_operation.md` |
| 30 | + - `resource_tc_teo_plan_for_zone_operation_test.go` |
| 31 | +- Website doc: `website/docs/r/teo_plan_for_zone.html.markdown` |
| 32 | +- Constructor `ResourceTencentCloudTeoPlanForZone()`, registered in `provider.go`. |
| 33 | + |
| 34 | +### Schema |
| 35 | +- Required (ForceNew): |
| 36 | + - `zone_id` (TypeString): Zone ID. |
| 37 | + - `plan_type` (TypeString): Plan type to purchase. Valid values: `sta`, `sta_with_bot`, `sta_cm`, `sta_cm_with_bot`, `sta_global`, `sta_global_with_bot`, `ent`, `ent_with_bot`, `ent_cm`, `ent_cm_with_bot`, `ent_global`, `ent_global_with_bot`. |
| 38 | +- Computed: |
| 39 | + - `resource_names` (TypeList, element TypeString): List of purchased resource names returned by the API. |
| 40 | + - `deal_names` (TypeList, element TypeString): List of purchased order/deal names returned by the API. |
| 41 | + |
| 42 | +### CRUD mapping (operation-type, following `tencentcloud_teo_identify_zone_operation`) |
| 43 | +- **Create**: build `CreatePlanForZoneRequest` from `zone_id` and `plan_type`; call the service-layer `TeoPlanForZone` helper inside `resource.Retry(tccommon.ReadRetryTimeout, ...)`; on success `d.SetId(helper.BuildToken())`; then nil-safe set computed `resource_names` and `deal_names`; finally call Read. |
| 44 | +- **Read**: no-op, return nil (no query API for the purchase result). |
| 45 | +- **Delete**: no-op, return nil (state removal only). |
| 46 | + |
| 47 | +### Service-layer method |
| 48 | +- Add `TeoPlanForZone(zoneId, planType string) (resourceNames, dealNames []*string, errRet error)` to `service_tencentcloud_teo.go`, following the `TeoIdentifyZone` pattern: build request, ratelimit check, call `me.client.UseTeoV20220901Client().CreatePlanForZone(request)`, nil-safe access to `response.Response`. |
| 49 | + |
| 50 | +### Retry placement |
| 51 | +- Per the business rules, the retry wraps only the API call. The `d.SetId()` and `d.Set(...)` calls happen after the retry block (outside it), in the success path after the retry error handling. |
| 52 | + |
| 53 | +## Risks / Trade-offs |
| 54 | + |
| 55 | +- [Plan purchase is irreversible and account/billing-impacting] → Mitigation: document clearly that Delete only removes the resource from state and does not cancel the plan. The `plan_type` is ForceNew, so changing it forces recreation (a new purchase). |
| 56 | +- [No Read API to verify the purchase] → Mitigation: Read is a no-op; the computed `resource_names` and `deal_names` are set once at create time from the API response and persisted in state. |
| 57 | +- [Re-running create on a zone that already has a plan] → Mitigation: rely on the API's own behavior; `CreatePlanForZone` will surface an error (e.g., `InvalidParameter.ZoneHasBeenBound`) which the retry helper surfaces to the user. |
0 commit comments