Skip to content

Commit 893aea1

Browse files
committed
feat(teo): add tencentcloud_teo_plan_for_zone resource to purchase a plan for a zone via CreatePlanForZone API
1 parent 2217e2c commit 893aea1

20 files changed

Lines changed: 3353 additions & 326 deletions

File tree

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ require (
4646
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.3.105
4747
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cloudaudit v1.0.1033
4848
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cls v1.3.131
49-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.132
49+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.136
5050
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/config v1.3.80
5151
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.3.130
5252
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp v1.3.30
@@ -93,7 +93,7 @@ require (
9393
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdcpg v1.0.533
9494
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113
9595
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578
96-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121
96+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.136
9797
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.3.107
9898
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/trocket v1.1.0
9999
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse v1.0.857

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -996,16 +996,16 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.112/go.mod
996996
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.113/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
997997
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
998998
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.118/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
999-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.121/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
1000999
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.122/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10011000
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.123/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10021001
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.124/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10031002
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.125/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10041003
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.127/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10051004
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.130/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10061005
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.131/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
1007-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.132 h1:42RfJnwzMprfKEJrM9fyhHu1jXyg8xvSJ1A1qb9Qun8=
10081006
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.132/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
1007+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.136 h1:06MPEiR1oZzRyNux2jshwMh67C0Zp4kRWvRfj46EcYs=
1008+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
10091009
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/config v1.3.80 h1:chnsNBeJn3MieFLki4hpbzoml5NiTvLVzOTqYRVxQho=
10101010
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/config v1.3.80/go.mod h1:B/ezGtlvDhZlleNM+2QdvZccrUi+J+fN6vMnDDsZnuM=
10111011
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/controlcenter v1.1.51 h1:pGwrfCBBCt1u+EDHwfNj9NLQpvk5MVKVMcsE7SvwqM4=
@@ -1121,8 +1121,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113 h1:2sulWz
11211121
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113/go.mod h1:uCUT6rfNap46k8JHzdPIz3WvYjiQPDkOBZ+b2GrIpUE=
11221122
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578 h1:vBpQhUroO+FAslUmsDWGi8nvczsqZBWVgQwlnyT0Aj8=
11231123
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578/go.mod h1:UlojGQh/9wb7/uXPNi7PvMral1CNAskVDNgqJEV83l0=
1124-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121 h1:SdW1CsEOUSABdz3YHXSw7nESExvD4fR43ZfBFYaD2OQ=
1125-
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121/go.mod h1:r8LzDVp59qZs+Pe65TiXnGKZSu05QB7cYd6XpK6XZ0s=
1124+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.136 h1:rgjFH09Z/PH6v7C6uum5pqli+d3AxzSH1gdhqLYiw1s=
1125+
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.136/go.mod h1:hROu6uk1E9l58lfZKQ15BEb9EF/rc3PP8Uxo1M7WdJg=
11261126
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/thpc v1.0.998 h1:f4/n0dVKQTD06xJ84B5asHViNJHrZmGojdAWEPIsITM=
11271127
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/thpc v1.0.998/go.mod h1:fyi/HUwCwVe2NCCCjz8k/C5GwPu3QazCZO+OBJ3MhLk=
11281128
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.3.107 h1:Yky7eL8FnkO89MvxERN3tniBQjstZzjIX8I91A4la/k=
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-07-20
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Why
2+
3+
EdgeOne (TEO) zones that have not yet purchased a plan cannot be fully managed via Terraform. Currently, users must purchase a plan for a zone manually in the console before they can manage the zone's configuration through Terraform. The `CreatePlanForZone` API exists to programmatically purchase a plan for an unbound zone, but there is no Terraform resource exposing this action. Adding a one-time operation resource lets users purchase a plan for a zone entirely from infrastructure-as-code.
4+
5+
## What Changes
6+
7+
- Add a new **operation-type** (one-time action) resource `tencentcloud_teo_plan_for_zone` that purchases a plan for a zone that has no bound plan, via the `CreatePlanForZone` API.
8+
- Create lifecycle calls `CreatePlanForZone` with `ZoneId` and `PlanType` inputs and exposes `ResourceNames` and `DealNames` from the response as computed attributes.
9+
- The resource unique ID is auto-generated (via `helper.BuildToken()`).
10+
- Read, Update, and Delete lifecycles are no-ops (one-time operation; no state to query or revert).
11+
- Provider registration, resource example doc (`.md`), website documentation, and unit test are added.
12+
13+
## Capabilities
14+
15+
### New Capabilities
16+
- `teo-plan-for-zone-operation`: A one-time operation resource that purchases a TEO plan for a zone via the `CreatePlanForZone` API.
17+
18+
### Modified Capabilities
19+
<!-- None: brand-new resource, no existing requirements change. -->
20+
21+
## Impact
22+
23+
- New file: `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation.go`
24+
- New file: `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation.md`
25+
- New file: `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation_test.go`
26+
- New file: `website/docs/r/teo_plan_for_zone.html.markdown` (generated via `make doc`)
27+
- Modified: `tencentcloud/provider.go` (register resource), `tencentcloud/provider.md`, `website/tencentcloud.erb`
28+
- SDK: uses existing `teo/v20220901` API `CreatePlanForZone` (already present in vendored SDK — no SDK changes required). The API is synchronous; no async polling is needed.
29+
- No breaking changes; purely additive.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Purchase a plan for a TEO zone
4+
5+
The resource `tencentcloud_teo_plan_for_zone` SHALL purchase a plan for a zone that has not yet bound a plan via the `CreatePlanForZone` API. As a one-time operation resource, it MUST auto-generate its unique ID. The `CreatePlanForZone` API accepts `ZoneId` and `PlanType` inputs and returns `ResourceNames` and `DealNames`.
6+
7+
#### Scenario: Purchase a plan for a zone
8+
9+
- **WHEN** the user applies the resource with `zone_id` and `plan_type` set
10+
- **THEN** the resource calls `CreatePlanForZone` wrapped in a retry mechanism with the provided `ZoneId` and `PlanType`
11+
- **AND** sets an auto-generated unique resource ID
12+
- **AND** populates the computed `resource_names` and `deal_names` attributes from the response in a nil-safe manner
13+
- **AND** then calls Read
14+
15+
#### Scenario: Plan purchase with empty response
16+
17+
- **WHEN** the `CreatePlanForZone` response is nil or `response.Response` is nil
18+
- **THEN** the resource SHALL return a NonRetryableError to avoid persisting an empty state
19+
20+
### Requirement: Resource schema definition
21+
22+
The system SHALL define the following schema for `tencentcloud_teo_plan_for_zone`:
23+
24+
Required parameters (ForceNew):
25+
- `zone_id` (TypeString): Zone ID
26+
- `plan_type` (TypeString): Plan type to purchase
27+
28+
Computed parameters:
29+
- `resource_names` (TypeList, element TypeString): List of purchased resource names returned by `CreatePlanForZone`
30+
- `deal_names` (TypeList, element TypeString): List of purchased order/deal names returned by `CreatePlanForZone`
31+
32+
#### Scenario: Schema validates required fields
33+
34+
- **WHEN** user omits `zone_id` or `plan_type` in the resource configuration
35+
- **THEN** Terraform SHALL produce a validation error indicating the missing required field
36+
37+
#### Scenario: All input parameters are ForceNew
38+
39+
- **WHEN** user changes `zone_id` or `plan_type` after creation
40+
- **THEN** Terraform SHALL force resource recreation
41+
42+
### Requirement: Empty Read/Update/Delete methods
43+
44+
The system SHALL implement empty Read, Update, and Delete methods for `tencentcloud_teo_plan_for_zone` resource, as this is a RESOURCE_KIND_OPERATION type. There is no query API for the purchase result, so Read is a no-op.
45+
46+
#### Scenario: Read method returns nil
47+
48+
- **WHEN** Terraform calls the Read method
49+
- **THEN** the system SHALL return nil without making any API calls
50+
51+
#### Scenario: Delete method returns nil
52+
53+
- **WHEN** Terraform calls the Delete method
54+
- **THEN** the system SHALL return nil without making any API calls, and the purchased plan is not reverted
55+
56+
### Requirement: Resource registration in provider
57+
58+
The system SHALL register `tencentcloud_teo_plan_for_zone` resource in `tencentcloud/provider.go` with the resource name "tencentcloud_teo_plan_for_zone" and add the corresponding entry in `tencentcloud/provider.md`.
59+
60+
#### Scenario: Resource available in provider
61+
62+
- **WHEN** user references `tencentcloud_teo_plan_for_zone` in Terraform configuration
63+
- **THEN** the provider SHALL recognize and process the resource
64+
65+
### Requirement: Unit tests with gomonkey mock
66+
67+
The system SHALL include unit tests in `resource_tc_teo_plan_for_zone_operation_test.go` using gomonkey to mock the TEO API client calls. Tests SHALL cover the Create operation with a successful response.
68+
69+
#### Scenario: Test successful plan purchase
70+
71+
- **WHEN** unit test runs with mocked `CreatePlanForZone` returning `ResourceNames` and `DealNames`
72+
- **THEN** the test SHALL verify the resource ID is set and computed fields are populated
73+
74+
### Requirement: Resource documentation
75+
76+
The system SHALL include a `resource_tc_teo_plan_for_zone_operation.md` documentation file with a description, and example usage. No Import section is needed for an OPERATION type resource.
77+
78+
#### Scenario: Documentation file exists
79+
80+
- **WHEN** the resource is added
81+
- **THEN** a corresponding .md file SHALL exist in the teo service directory with proper format following the gendoc README guidelines
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## 1. Service Layer
2+
3+
- [x] 1.1 Add `TeoPlanForZone(zoneId, planType string) (resourceNames, dealNames []*string, errRet error)` method to `tencentcloud/services/teo/service_tencentcloud_teo.go`, following the `TeoIdentifyZone` pattern: build `CreatePlanForZoneRequest`, set `ZoneId` and `PlanType`, ratelimit check, call `me.client.UseTeoV20220901Client().CreatePlanForZone(request)`, nil-safe access to `response.Response`
4+
5+
## 2. Resource Implementation
6+
7+
- [x] 2.1 Create `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation.go` with constructor `ResourceTencentCloudTeoPlanForZone()`, operation-type code style following `tencentcloud_teo_identify_zone_operation`
8+
- [x] 2.2 Define schema: required ForceNew `zone_id` (TypeString), required ForceNew `plan_type` (TypeString); computed `resource_names` (TypeList, elem TypeString), computed `deal_names` (TypeList, elem TypeString)
9+
- [x] 2.3 Implement Create: build `CreatePlanForZoneRequest` from `zone_id` and `plan_type`, call `TeoPlanForZone` inside `resource.Retry(tccommon.ReadRetryTimeout, ...)`, after retry success set `d.SetId(helper.BuildToken())` and nil-safe set computed `resource_names` and `deal_names`, then call Read
10+
- [x] 2.4 Implement Read: no-op (return nil)
11+
- [x] 2.5 Implement Delete: no-op (return nil)
12+
- [x] 2.6 Ensure nil-safe response access: if response or response.Response is nil, return NonRetryableError; all response-value access is nil-safe
13+
14+
## 3. Provider Registration
15+
16+
- [x] 3.1 Register `tencentcloud_teo_plan_for_zone` in `tencentcloud/provider.go` ResourcesMap
17+
- [x] 3.2 Add the resource entry to `tencentcloud/provider.md`
18+
19+
## 4. Documentation
20+
21+
- [x] 4.1 Create `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation.md` example file, format following `resource_tc_teo_identify_zone_operation.md` (description with TEO product name + Example Usage; no Import section for OPERATION type)
22+
- [ ] 4.2 Generate `website/docs/r/teo_plan_for_zone.html.markdown` via `make doc` (do not hand-write) and confirm `website/tencentcloud.erb` link entry
23+
24+
## 5. Unit Test
25+
26+
- [x] 5.1 Create `tencentcloud/services/teo/resource_tc_teo_plan_for_zone_operation_test.go`, using gomonkey to mock the TEO API client, naming/format following `resource_tc_teo_identify_zone_operation_test.go`; cover Create with successful response
27+
28+
## 6. Verification
29+
30+
- [ ] 6.1 Run `gofmt` on changed Go files
31+
- [x] 6.2 Run `go test -gcflags=all=-l ./tencentcloud/services/teo/ -run TestAccTencentCloudTeoPlanForZone` to confirm unit tests pass
32+
- [ ] 6.3 Run `make doc` and verify generated website doc is consistent with the `.md` example

0 commit comments

Comments
 (0)