Skip to content

Commit 7f7ccb9

Browse files
iac-agentVanHWZ
andauthored
feat(ckafka): [135985803]add delete_protection_enable param for ckafka instance (#4291)
* feat(ckafka): add delete_protection_enable param for ckafka instance --------- Co-authored-by: vincenthuangwz <van136682262@gmail.com>
1 parent cbb5a94 commit 7f7ccb9

11 files changed

Lines changed: 725 additions & 0 deletions

File tree

.changelog/4291.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_ckafka_instance: support `delete_protection_enable` parameter to manage instance delete-protection switch
3+
```
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-10
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
## Context
2+
3+
`tencentcloud_ckafka_instance` 是 CKafka 实例的通用资源(RESOURCE_KIND_GENERAL),封装了实例的创建、读取、更新、删除全生命周期。
4+
5+
当前状态:
6+
- 资源 schema 中未包含删除保护相关字段
7+
- Create 流程在实例创建完成后,会调用一次 `ModifyInstanceAttributes` 设置 `msg_retention_time``config``dynamic_retention_config``rebalance_time``public_network``max_message_byte` 等属性
8+
- Read 流程先调用 `DescribeInstancesDetail`(返回 `InstanceDetail`,不含 `DeleteProtectionEnable`),再调用 `DescribeInstanceAttributes`(返回 `InstanceAttributesResponse`,含 `DeleteProtectionEnable *int64`)回写属性
9+
- Update 流程通过 `ModifyInstanceAttributes` 修改可变属性,并通过 `InstanceScalingDown` / `ModifyInstancePre` 处理规格变更
10+
11+
云 API 能力确认(vendor `ckafka/v20190819`):
12+
- `ModifyInstanceAttributesRequest.DeleteProtectionEnable``*int64`,注释"实例删除保护开关: 1 开启 0 关闭" ✅
13+
- `InstanceAttributesResponse.DeleteProtectionEnable``*int64`,注释同上 ✅
14+
- `InstanceDetail``DescribeInstancesDetail` 响应项)**不含** `DeleteProtectionEnable`
15+
16+
约束:
17+
- Terraform Provider 向后兼容:未配置 `delete_protection_enable` 的既有配置不能产生 plan diff
18+
- 该字段为可选属性,未配置时应保留云端现有值(Computed 回填)
19+
20+
## Goals / Non-Goals
21+
22+
**Goals:**
23+
- 支持通过 Terraform 声明式开启/关闭 CKafka 实例的删除保护
24+
- 保持向后兼容:未配置时不触发 plan diff
25+
- Create / Update / Read 三条路径均正确处理 `delete_protection_enable`
26+
- 通过单元测试覆盖三条路径
27+
28+
**Non-Goals:**
29+
- 不改变 Delete 操作行为(删除保护开启时,云 API 会在 Delete 阶段返回错误,由云端拦截,provider 不做特殊处理)
30+
- 不修改 `DescribeInstancesDetail` 相关逻辑(该接口不返回该字段)
31+
- 不调整 `immutableArgs` 列表(`delete_protection_enable` 是可变属性)
32+
- 不新增独立资源
33+
34+
## Decisions
35+
36+
### Decision 1: 字段类型使用 TypeInt 而非 TypeBool
37+
38+
**选择**`delete_protection_enable` 使用 `schema.TypeInt`,取值 `1`(开启)/ `0`(关闭),与云 API `*int64` 类型一一对应。
39+
40+
**备选**:使用 `schema.TypeBool`,在 provider 层做 bool↔int64 转换。
41+
42+
**理由**
43+
- 与资源内同类型开关字段风格一致(如 `elastic_bandwidth_switch``dynamic_retention_config.enable` 等均为 TypeInt)
44+
- 避免引入额外的类型转换逻辑,降低出错概率
45+
- 云 API 直接接受 int64,无需转换
46+
47+
### Decision 2: 字段属性为 Optional + Computed
48+
49+
**选择**`Optional: true, Computed: true`
50+
51+
**理由**
52+
- `Optional` 允许用户显式配置;`Computed` 保证未配置时由 Read 回填云端值,不产生 plan diff
53+
- 这是 provider 处理"可选的、未配置时由云端回填"字段的标准模式
54+
55+
### Decision 3: Create 阶段在已有 ModifyInstanceAttributes 调用中顺带设置
56+
57+
**选择**:在 Create 末尾构造 `modifyRequest` 的现有逻辑中,新增对 `delete_protection_enable` 的判断与填充,复用同一次 `ModifyInstanceAttributes` 调用。
58+
59+
**备选**:Create 后单独发起一次 `ModifyInstanceAttributes` 调用。
60+
61+
**理由**
62+
- 现有 Create 流程已经在创建后调用一次 `ModifyInstanceAttributes` 设置其他属性,复用该调用减少 API 往返
63+
- 使用 `d.GetOk("delete_protection_enable")` 判断用户是否显式配置,仅在配置时填充,避免覆盖云端默认值
64+
65+
### Decision 4: Update 阶段在已有 ModifyInstanceAttributes 分支中扩展
66+
67+
**选择**:在 `resourceTencentCloudCkafkaInstanceUpdate``modifyInstanceAttributesFlag` 逻辑块中,新增 `if d.HasChange("delete_protection_enable")` 分支,填充 `request.DeleteProtectionEnable` 并置 `modifyInstanceAttributesFlag = true`
68+
69+
**理由**
70+
- 与现有 `instance_name``msg_retention_time``public_network``max_message_byte` 等可变字段的处理模式完全一致
71+
- `delete_protection_enable` 不加入 `immutableArgs`,允许原地更新
72+
73+
### Decision 5: Read 阶段从 DescribeInstanceAttributes 响应回填
74+
75+
**选择**:在 Read 流程调用 `DescribeInstanceAttributes` 后,判断 `attr.DeleteProtectionEnable != nil`,然后 `d.Set("delete_protection_enable", attr.DeleteProtectionEnable)`
76+
77+
**理由**
78+
- `DescribeInstanceAttributes` 的响应 `InstanceAttributesResponse` 已包含 `DeleteProtectionEnable` 字段
79+
- 遵循"set 前判 nil"的规范,避免 nil 指针问题
80+
- 不在 `DescribeInstancesDetail` 分支处理(该接口不返回此字段)
81+
82+
### Decision 6: 使用 d.GetOkExists 处理 0 值
83+
84+
**选择**:在 Create 中使用 `d.GetOkExists("delete_protection_enable")` 读取用户配置,确保用户显式设置 `0`(关闭)时也能正确传入。
85+
86+
**理由**
87+
- `d.GetOk` 在值为 `0` 时会返回 `ok=false`,会导致用户显式关闭删除保护时参数不被传入
88+
- `d.GetOkExists` 能区分"未配置"与"配置为 0",与现有 `max_message_byte` 字段处理方式一致
89+
90+
## Risks / Trade-offs
91+
92+
- **Risk**:用户在配置中设置 `delete_protection_enable = 1` 后执行 `terraform destroy`,云 API 会因删除保护开启而拒绝删除 → **Mitigation**:这是删除保护本身的预期行为,用户需先在配置中设为 `0` 并 apply 后再 destroy;provider 不绕过该保护。
93+
- **Risk**:旧 state 中无 `delete_protection_enable` 字段,首次 refresh 时由 Computed 回填 → **Mitigation**:Optional+Computed 模式保证无 plan diff,向后兼容。
94+
- **Trade-off**:Create 阶段复用同一次 `ModifyInstanceAttributes` 调用,若该调用失败会导致删除保护与其他属性一起未设置 → 可接受,Create 失败会整体报错并由用户重试。
95+
96+
## Migration Plan
97+
98+
- 纯加法变更(新增 Optional 字段),无 state 迁移需求
99+
- 存量资源:升级后 `terraform plan` 对未在 HCL 配置 `delete_protection_enable` 的资源不产生 diff
100+
- 文档更新:在 `resource_tc_ckafka_instance.md` 中补充字段说明和示例
101+
- 回滚:移除 schema 字段与 CRUD 分支即可,state 中多余字段会被 terraform 忽略
102+
103+
## Open Questions
104+
105+
-
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## Why
2+
3+
CKafka 实例在控制台支持"删除保护"开关,开启后可防止实例被误删除。当前 `tencentcloud_ckafka_instance` 资源未暴露该开关,用户无法通过 Terraform 声明式地管理删除保护状态,只能在控制台或 SDK 手动设置,导致 IaC 覆盖不完整。腾讯云 CKafka SDK 的 `ModifyInstanceAttributes` 接口已支持 `DeleteProtectionEnable` 入参(1 开启、0 关闭),且 `DescribeInstanceAttributes` 接口响应中返回该字段,具备完整支持条件。
4+
5+
## What Changes
6+
7+
-`tencentcloud_ckafka_instance` 资源 schema 中新增 `delete_protection_enable` 参数(`Optional + Computed`,TypeInt,取值 `1` 开启 / `0` 关闭),保持向后兼容(未配置时不触发 plan diff)。
8+
- 在 Create 流程末尾的 `ModifyInstanceAttributes` 调用中,当用户配置了 `delete_protection_enable` 时,填充 `request.DeleteProtectionEnable`
9+
- 在 Update 流程中新增 `d.HasChange("delete_protection_enable")` 分支,构造 `ModifyInstanceAttributesRequest` 并填充 `DeleteProtectionEnable`,调用 `ModifyCkafkaInstanceAttributes`
10+
- 在 Read 流程的 `DescribeInstanceAttributes` 响应处理中,当 `attr.DeleteProtectionEnable` 不为 nil 时回写 `d.Set("delete_protection_enable", ...)`
11+
- 补充 `resource_tc_ckafka_instance_test.go` 单元测试,使用 gomonkey mock 云 API,覆盖 Create/Update/Read 三个分支中 `delete_protection_enable` 的处理逻辑。
12+
- 更新 `resource_tc_ckafka_instance.md` 文档示例,展示 `delete_protection_enable` 字段用法。
13+
14+
## Capabilities
15+
16+
### New Capabilities
17+
- `ckafka-instance-resource`: `tencentcloud_ckafka_instance` 通用资源(RESOURCE_KIND_GENERAL)的能力定义,覆盖实例的创建、读取、更新、删除全生命周期,本次新增 `delete_protection_enable` 删除保护开关参数。
18+
19+
### Modified Capabilities
20+
<!-- 无已有 spec,本次为纯新增 -->
21+
22+
## Impact
23+
24+
- 代码:
25+
- `tencentcloud/services/ckafka/resource_tc_ckafka_instance.go`(schema 新增字段、Create/Update/Read 逻辑扩展)
26+
- `tencentcloud/services/ckafka/resource_tc_ckafka_instance_test.go`(新增 `delete_protection_enable` 相关单元测试用例)
27+
- `tencentcloud/services/ckafka/resource_tc_ckafka_instance.md`(示例补充 `delete_protection_enable`
28+
- 依赖:使用已 vendored 的 `tencentcloud-sdk-go``ckafka/v20190819.ModifyInstanceAttributesRequest.DeleteProtectionEnable``*int64`)及 `InstanceAttributesResponse.DeleteProtectionEnable``*int64`),无需变更 vendor。
29+
- 向后兼容:新增 Optional 字段,未配置时不影响已有 state 与 TF 配置,无 state 迁移需求。
30+
- 文档:需同步更新 website docs(由 `make doc` 自动生成流程读取 `.md` 文件)。
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
## ADDED Requirements
2+
3+
### Requirement: CKafka Instance Resource Schema
4+
The system SHALL define a Terraform resource `tencentcloud_ckafka_instance` (RESOURCE_KIND_GENERAL) covering the full CRUD lifecycle of a CKafka instance. The schema SHALL include a `delete_protection_enable` field with the following characteristics:
5+
- `delete_protection_enable` (Optional, Computed, TypeInt): 实例删除保护开关,取值 `1`(开启)/ `0`(关闭)。未显式配置时由云端回填,不触发 plan diff。
6+
7+
#### Scenario: delete_protection_enable is optional and computed
8+
- **WHEN** a user does not set `delete_protection_enable` in the Terraform configuration
9+
- **THEN** the system SHALL populate `delete_protection_enable` from the `DescribeInstanceAttributes` API response (Computed behavior) without triggering a plan diff
10+
11+
#### Scenario: delete_protection_enable accepts user input
12+
- **WHEN** a user sets `delete_protection_enable = 1` or `delete_protection_enable = 0` in the Terraform configuration
13+
- **THEN** the schema SHALL accept the integer value and mark it as a candidate for create/update
14+
15+
### Requirement: CKafka Instance Create Operation
16+
The system SHALL, after successfully creating a CKafka instance, call `ModifyInstanceAttributes` API to set instance attributes. When the user has explicitly configured `delete_protection_enable`, the system SHALL fill `request.DeleteProtectionEnable` with the configured int64 value (`1` or `0`) and include it in the same `ModifyInstanceAttributes` call that sets other post-creation attributes.
17+
18+
#### Scenario: Create with delete_protection_enable set to 1
19+
- **WHEN** the user sets `delete_protection_enable = 1` in the Terraform configuration and creates the instance
20+
- **THEN** the system SHALL call `ModifyInstanceAttributes` with `DeleteProtectionEnable = 1` after the instance is created
21+
22+
#### Scenario: Create with delete_protection_enable set to 0
23+
- **WHEN** the user sets `delete_protection_enable = 0` in the Terraform configuration and creates the instance
24+
- **THEN** the system SHALL call `ModifyInstanceAttributes` with `DeleteProtectionEnable = 0` (using GetOkExists so the explicit 0 value is not skipped)
25+
26+
#### Scenario: Create without delete_protection_enable configured
27+
- **WHEN** the user does not set `delete_protection_enable` in the Terraform configuration
28+
- **THEN** the system SHALL NOT fill `DeleteProtectionEnable` in the `ModifyInstanceAttributes` request, preserving the cloud-side default
29+
30+
### Requirement: CKafka Instance Update Operation
31+
The system SHALL, when `delete_protection_enable` changes in the Terraform configuration, call `ModifyInstanceAttributes` API with `InstanceId` and the updated `DeleteProtectionEnable` value. This field SHALL be mutable in-place (not ForceNew, not in `immutableArgs`).
32+
33+
#### Scenario: Update delete_protection_enable from 0 to 1
34+
- **WHEN** `delete_protection_enable` changes from `0` to `1` in the Terraform configuration
35+
- **THEN** the system SHALL call `ModifyInstanceAttributes` with `DeleteProtectionEnable = 1`
36+
- **AND** the update SHALL be performed in-place without resource recreation
37+
38+
#### Scenario: Update delete_protection_enable from 1 to 0
39+
- **WHEN** `delete_protection_enable` changes from `1` to `0` in the Terraform configuration
40+
- **THEN** the system SHALL call `ModifyInstanceAttributes` with `DeleteProtectionEnable = 0`
41+
42+
#### Scenario: delete_protection_enable not changed
43+
- **WHEN** `delete_protection_enable` is not changed during an update
44+
- **THEN** the system SHALL NOT include `DeleteProtectionEnable` in the `ModifyInstanceAttributes` request for this field
45+
46+
### Requirement: CKafka Instance Read Operation
47+
The system SHALL read the `delete_protection_enable` value from the `DescribeInstanceAttributes` API response (`InstanceAttributesResponse.DeleteProtectionEnable`). Before calling `d.Set("delete_protection_enable", ...)`, the system SHALL check that the response field is not nil; if nil, the system SHALL skip the set operation.
48+
49+
#### Scenario: Read delete_protection_enable from DescribeInstanceAttributes
50+
- **WHEN** the Read operation calls `DescribeInstanceAttributes` and the response `DeleteProtectionEnable` is not nil
51+
- **THEN** the system SHALL set `delete_protection_enable` in Terraform state to the returned value
52+
53+
#### Scenario: Read with nil DeleteProtectionEnable
54+
- **WHEN** the Read operation calls `DescribeInstanceAttributes` and the response `DeleteProtectionEnable` is nil
55+
- **THEN** the system SHALL skip `d.Set("delete_protection_enable", ...)` to avoid a nil pointer issue
56+
57+
### Requirement: CKafka Instance Unit Tests
58+
The system SHALL provide unit tests in `resource_tc_ckafka_instance_test.go` using gomonkey to mock cloud API calls, covering the `delete_protection_enable` handling in Create, Update, and Read operations.
59+
60+
#### Scenario: Unit tests pass
61+
- **WHEN** `go test` is run with `-gcflags=all=-l` on the test file
62+
- **THEN** all test cases for `delete_protection_enable` Create (set to 1 and 0), Update (change 0→1 and 1→0), and Read SHALL pass
63+
64+
#### Scenario: Create with delete_protection_enable test
65+
- **WHEN** a test simulates creating an instance with `delete_protection_enable = 1`
66+
- **THEN** the mocked `ModifyInstanceAttributes` SHALL be invoked with `DeleteProtectionEnable = 1`
67+
68+
#### Scenario: Update delete_protection_enable test
69+
- **WHEN** a test simulates updating `delete_protection_enable` from `0` to `1`
70+
- **THEN** the mocked `ModifyInstanceAttributes` SHALL be invoked with `DeleteProtectionEnable = 1`
71+
- **AND** the test SHALL assert the API was called
72+
73+
### Requirement: CKafka Instance Resource Documentation
74+
The system SHALL provide a markdown documentation file `resource_tc_ckafka_instance.md` with a one-line description mentioning CKafka, example usage, and import section. The example usage SHALL demonstrate the `delete_protection_enable` field.
75+
76+
#### Scenario: Documentation exists
77+
- **WHEN** the resource is created
78+
- **THEN** a `.md` file SHALL exist with a one-line description mentioning CKafka, example usage including `delete_protection_enable`, and import section showing the instance ID format
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## 1. Schema 定义
2+
3+
- [x] 1.1 在 `tencentcloud/services/ckafka/resource_tc_ckafka_instance.go``ResourceTencentCloudCkafkaInstance()` schema map 中新增 `delete_protection_enable` 字段:`Type: schema.TypeInt, Optional: true, Computed: true`,Description 说明"实例删除保护开关: 1 开启 0 关闭"
4+
- [x] 1.2 确认 `delete_protection_enable` 不加入 `immutableArgs` 列表(其为可变属性,允许原地更新)
5+
6+
## 2. Create 函数扩展
7+
8+
- [x] 2.1 在 `resourceTencentCloudCkafkaInstanceCreate` 末尾构造 `modifyRequest``ModifyInstanceAttributesRequest`)的现有逻辑块中,新增 `if v, ok := d.GetOkExists("delete_protection_enable"); ok { needModify = true; modifyRequest.DeleteProtectionEnable = helper.Int64(int64(v.(int))) }`,确保用户显式配置 `0` 时也能传入
9+
- [x] 2.2 复用已有的 `service.ModifyCkafkaInstanceAttributes(ctx, modifyRequest)` 调用,不新增额外 API 调用
10+
11+
## 3. Update 函数扩展
12+
13+
- [x] 3.1 在 `resourceTencentCloudCkafkaInstanceUpdate``modifyInstanceAttributesFlag` 逻辑块中,新增 `if d.HasChange("delete_protection_enable") { if v, ok := d.GetOkExists("delete_protection_enable"); ok { request.DeleteProtectionEnable = helper.Int64(int64(v.(int))); modifyInstanceAttributesFlag = true } }`
14+
- [x] 3.2 复用已有的 `service.ModifyCkafkaInstanceAttributes(ctx, request)` 调用
15+
- [x] 3.3 确认 Update 函数末尾仍调用 `resourceTencentCloudCkafkaInstanceRead(d, meta)` 回写最新状态
16+
17+
## 4. Read 函数扩展
18+
19+
- [x] 4.1 在 `resourceTencentCloudCkafkaInstanceRead` 调用 `DescribeInstanceAttributes` 的 retry 块内,处理 `attr := response.Response.Result` 后,新增 `if attr.DeleteProtectionEnable != nil { _ = d.Set("delete_protection_enable", attr.DeleteProtectionEnable) }`(set 前判 nil)
20+
21+
## 5. 单元测试
22+
23+
- [x] 5.1 在 `tencentcloud/services/ckafka/resource_tc_ckafka_instance_test.go` 中使用 gomonkey mock 云 API,新增 Create 时 `delete_protection_enable = 1` 的测试用例,断言 `ModifyInstanceAttributes` 被调用且 `DeleteProtectionEnable == 1`
24+
- [x] 5.2 新增 Create 时 `delete_protection_enable = 0` 的测试用例(验证 GetOkExists 能传入显式 0)
25+
- [x] 5.3 新增 Update 时 `delete_protection_enable``0` 变为 `1` 的测试用例,断言 `ModifyInstanceAttributes` 被调用且 `DeleteProtectionEnable == 1`
26+
- [x] 5.4 新增 Update 时 `delete_protection_enable``1` 变为 `0` 的测试用例
27+
- [x] 5.5 新增 Read 时 `DescribeInstanceAttributes` 返回 `DeleteProtectionEnable` 非 nil 的测试用例,断言 state 被正确回填
28+
- [x] 5.6 新增 Read 时 `DeleteProtectionEnable` 为 nil 的测试用例,断言不触发 panic 且跳过 set
29+
- [x] 5.7 使用 `go test ./tencentcloud/services/ckafka/ -run <TestFunc> -v -count=1 -gcflags=all=-l` 跑通涉及的单元测试文件
30+
31+
## 6. 文档同步
32+
33+
- [x] 6.1 在 `tencentcloud/services/ckafka/resource_tc_ckafka_instance.md` 的 Example Usage 中新增 `delete_protection_enable` 字段示例(取值 `1` 开启 / `0` 关闭)
34+
- [ ] 6.2 在收尾阶段执行 `make doc`,根据 provider 规范重新生成 `website/docs/` 下的 markdown 文档(禁止手改 website/ 目录)
35+
36+
## 7. 验证(收尾阶段执行)
37+
38+
- [ ] 7.1 在收尾阶段执行 `gofmt` 格式化变更的 Go 代码
39+
- [ ] 7.2 确认所有涉及的单元测试文件通过 `go test -gcflags=all=-l`

0 commit comments

Comments
 (0)