Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/4251.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/tencentcloud_teo_l7_acc_rule_v2: add new parameters for L7 acceleration rule configuration
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ require (
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdcpg v1.0.533
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.113
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.3.107
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/trocket v1.1.0
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse v1.0.857
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.112/go.mod
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.113/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.118/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.121/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.122 h1:jBKY11xe4t9284+OQPIA5v1wVwbp0Vton1UiXp2ar9c=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.122/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/config v1.3.80 h1:chnsNBeJn3MieFLki4hpbzoml5NiTvLVzOTqYRVxQho=
Expand Down Expand Up @@ -1120,8 +1121,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113 h1:2sulWz
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq v1.3.113/go.mod h1:uCUT6rfNap46k8JHzdPIz3WvYjiQPDkOBZ+b2GrIpUE=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578 h1:vBpQhUroO+FAslUmsDWGi8nvczsqZBWVgQwlnyT0Aj8=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tem v1.0.578/go.mod h1:UlojGQh/9wb7/uXPNi7PvMral1CNAskVDNgqJEV83l0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.113 h1:xt2M4V6RH44/EnM3B/3U62StvetV56i0LKIIphpMp4c=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.113/go.mod h1:CVqu/hQhzYGDc312djRPNvEyhmUSZ4gywcBDWv1DGAM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121 h1:SdW1CsEOUSABdz3YHXSw7nESExvD4fR43ZfBFYaD2OQ=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.121/go.mod h1:r8LzDVp59qZs+Pe65TiXnGKZSu05QB7cYd6XpK6XZ0s=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/thpc v1.0.998 h1:f4/n0dVKQTD06xJ84B5asHViNJHrZmGojdAWEPIsITM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/thpc v1.0.998/go.mod h1:fyi/HUwCwVe2NCCCjz8k/C5GwPu3QazCZO+OBJ3MhLk=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke v1.3.107 h1:Yky7eL8FnkO89MvxERN3tniBQjstZzjIX8I91A4la/k=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-06-25
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Context

The `tencentcloud_teo_l7_acc_rule_v2` resource already exists at `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.go` with the following schema fields: `zone_id`, `status`, `rule_name`, `description`, `branches`, `rule_id` (Computed), `rule_priority` (Computed).

The resource uses the TEO v20220901 SDK APIs:
- **Create**: `CreateL7AccRules` - takes `ZoneId` and `Rules` ([]*RuleEngineItem)
- **Read**: `DescribeL7AccRules` - takes `ZoneId` and `Filters` (with rule-id filter)
- **Update**: `ModifyL7AccRule` - takes `ZoneId` and `Rule` (*RuleEngineItem)
- **Delete**: `DeleteL7AccRules` - takes `ZoneId` and `RuleIds`

The `RuleEngineItem` struct contains: `Status`, `RuleId`, `RuleName`, `Description`, `Branches`, `RulePriority`.

The resource uses a composite ID format: `{zone_id}#{rule_id}` with `tccommon.FILED_SP` as separator.

## Goals / Non-Goals

**Goals:**
- Ensure the `tencentcloud_teo_l7_acc_rule_v2` resource has complete parameter coverage matching the cloud API
- Maintain backward compatibility with existing Terraform configurations
- Follow established patterns in the codebase (retry logic, error handling, composite IDs)

**Non-Goals:**
- Changing the existing schema structure or field types
- Adding support for batch rule operations (the resource manages a single rule)
- Modifying the `tencentcloud_teo_l7_acc_rule` (v1) resource

## Decisions

1. **Schema Design**: Use flat schema with individual fields (`zone_id`, `status`, `rule_name`, `description`, `branches`) rather than a nested `rules` block. This matches the existing implementation pattern and is more user-friendly for a single-rule resource.
- Alternative: Nested `rules` block wrapping all fields - rejected because it adds unnecessary nesting for a single-rule resource and would break backward compatibility.

2. **Composite ID**: Use `{zone_id}#FILED_SP#{rule_id}` format for resource ID, enabling import support.
- This is the established pattern in the codebase for resources with multiple identifying fields.

3. **Create API Mapping**: Construct a single `RuleEngineItem` from individual schema fields and wrap in a slice for the `CreateL7AccRules` API's `Rules` parameter.
- The API accepts a list but we only create one rule per resource instance.

4. **Read API Mapping**: Use `DescribeL7AccRules` with `Filters` containing `rule-id` filter to fetch the specific rule by ID.

5. **Error Handling**: Use `tccommon.RetryError()` for all API calls with appropriate retry timeouts (`WriteRetryTimeout` for CUD, `ReadRetryTimeout` for R).

## Risks / Trade-offs

- [Risk] API returns empty response during transient failures → Mitigation: Check for nil response and empty rules list before setting ID to empty; log the resource ID before clearing it.
- [Risk] Create API returns empty RuleIds → Mitigation: Check response, RuleIds length, and nil pointer before using the returned ID; return NonRetryableError if empty.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Why

The `tencentcloud_teo_l7_acc_rule_v2` resource needs to be fully implemented as a RESOURCE_KIND_GENERAL resource for the TEO (TencentCloud EdgeOne) product. This resource manages L7 acceleration rules with full CRUD lifecycle operations (CreateL7AccRules, DescribeL7AccRules, ModifyL7AccRule, DeleteL7AccRules), enabling users to create, read, update, and delete L7 acceleration rules within a TEO zone.

## What Changes

- Add the `tencentcloud_teo_l7_acc_rule_v2` resource with full CRUD support:
- `zone_id` (Required, ForceNew): Zone ID for the TEO site
- `rules` (Required): Rule content list containing rule engine items with status, rule_name, description, and branches
- `rule_id` (Computed): Rule ID returned after creation, used for update/delete/read operations
- `status` (Optional): Rule status (enable/disable)
- `rule_name` (Optional): Rule name with 255 character limit
- `description` (Optional): Rule annotations, supports multiple entries
- `branches` (Optional): Sub-rule branches for rule conditions and actions
- `rule_priority` (Computed): Rule priority, output only
- Register the resource in `provider.go` and `provider.md`
- Add service layer function `DescribeTeoL7AccRuleById` for reading rule details
- Add documentation and unit tests

## Capabilities

### New Capabilities
- `teo-l7-acc-rule-v2-resource`: Full CRUD lifecycle management for TEO L7 acceleration rules via CreateL7AccRules, ModifyL7AccRule, DeleteL7AccRules, and DescribeL7AccRules APIs

### Modified Capabilities

## Impact

- **Code**: `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.go`, `tencentcloud/services/teo/service_tencentcloud_teo.go`, `tencentcloud/provider.go`, `tencentcloud/provider.md`
- **APIs**: Uses `teo/v20220901` package APIs: `CreateL7AccRules`, `ModifyL7AccRule`, `DeleteL7AccRules`, `DescribeL7AccRules`
- **Dependencies**: `github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo/v20220901` (already in vendor)
- **Documentation**: `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.md`, `website/docs/r/teo_l7_acc_rule_v2.html.markdown`
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## ADDED Requirements

### Requirement: Resource manages TEO L7 acceleration rule lifecycle

The `tencentcloud_teo_l7_acc_rule_v2` resource SHALL manage the full CRUD lifecycle of a TEO L7 acceleration rule using the following APIs:
- Create: `CreateL7AccRules` with `ZoneId` and `Rules` parameters
- Read: `DescribeL7AccRules` with `ZoneId` and `Filters` (rule-id filter using `Values`)
- Update: `ModifyL7AccRule` with `ZoneId` and `Rule` (containing `RuleId`, `Status`, `RuleName`, `Description`, `Branches`)
- Delete: `DeleteL7AccRules` with `ZoneId` and `RuleIds`

The resource SHALL use a composite ID format `{zone_id}#{rule_id}` with `tccommon.FILED_SP` as separator.

#### Scenario: Create a new L7 acceleration rule
- **WHEN** user applies a Terraform configuration with `tencentcloud_teo_l7_acc_rule_v2` resource specifying `zone_id`, `status`, `rule_name`, `description`, and `branches`
- **THEN** the resource SHALL call `CreateL7AccRules` API with the zone ID and a single `RuleEngineItem` containing the specified fields, and store the returned `rule_id` in state with composite ID format

#### Scenario: Read an existing L7 acceleration rule
- **WHEN** Terraform performs a refresh on the resource
- **THEN** the resource SHALL call `DescribeL7AccRules` API with `zone_id` and a filter for `rule-id` with the stored `rule_id` as the filter value, and update state with the returned `status`, `rule_name`, `description`, `branches`, and `rule_priority`

#### Scenario: Update an existing L7 acceleration rule
- **WHEN** user modifies `status`, `rule_name`, `description`, or `branches` in the Terraform configuration
- **THEN** the resource SHALL call `ModifyL7AccRule` API with `zone_id` and a `RuleEngineItem` containing the `rule_id` and updated fields

#### Scenario: Delete an L7 acceleration rule
- **WHEN** user destroys the resource
- **THEN** the resource SHALL call `DeleteL7AccRules` API with `zone_id` and `rule_id`

#### Scenario: Import an existing rule
- **WHEN** user imports a resource using `terraform import` with ID format `{zone_id}#{rule_id}`
- **THEN** the resource SHALL parse the composite ID and read the rule details from the API

### Requirement: Resource schema defines correct field types and constraints

The resource schema SHALL define the following fields:
- `zone_id`: TypeString, Required, ForceNew - Zone ID for the TEO site
- `status`: TypeString, Optional - Rule status (enable/disable)
- `rule_name`: TypeString, Optional - Rule name (max 255 characters)
- `description`: TypeList of TypeString, Optional - Rule annotations
- `branches`: TypeList of Resource, Optional - Sub-rule branches with conditions and actions
- `rule_id`: TypeString, Computed - Rule ID returned by the API
- `rule_priority`: TypeInt, Computed - Rule priority (output only)

#### Scenario: Zone ID is immutable after creation
- **WHEN** user attempts to change `zone_id` after resource creation
- **THEN** Terraform SHALL plan to destroy and recreate the resource (ForceNew behavior)

#### Scenario: Optional fields can be omitted
- **WHEN** user creates a resource without specifying `status`, `rule_name`, `description`, or `branches`
- **THEN** the resource SHALL be created successfully with API defaults for those fields

### Requirement: Error handling follows provider patterns

The resource SHALL implement proper error handling:
- All API calls MUST be wrapped with retry logic using `tccommon.RetryError()`
- Create MUST verify the response is not nil and `RuleIds` is not empty before storing the ID
- Read MUST check for nil response and empty rules list, logging the resource ID before clearing state

#### Scenario: Create API returns empty response
- **WHEN** the `CreateL7AccRules` API returns a nil response or empty `RuleIds`
- **THEN** the resource SHALL return a `NonRetryableError` with a descriptive message

#### Scenario: Read API returns no matching rule
- **WHEN** the `DescribeL7AccRules` API returns an empty rules list
- **THEN** the resource SHALL log the resource ID for debugging and set the ID to empty string to remove from state
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## 1. Resource Implementation

- [x] 1.1 Update resource schema in `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.go` to ensure all parameters are correctly defined with proper types, constraints (Required/Optional/Computed/ForceNew), and descriptions
- [x] 1.2 Update Create function to properly validate API response (check nil response, empty RuleIds) and return NonRetryableError on empty ID
- [x] 1.3 Update Read function to log resource ID before clearing state when API returns empty response
- [x] 1.4 Verify Update function correctly handles HasChange detection and passes all modified fields to ModifyL7AccRule API
- [x] 1.5 Verify Delete function correctly passes zone_id and rule_id to DeleteL7AccRules API

## 2. Provider Registration

- [x] 2.1 Verify resource is registered in `tencentcloud/provider.go`
- [x] 2.2 Verify resource is listed in `tencentcloud/provider.md`

## 3. Testing

- [x] 3.1 Add unit tests in `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2_test.go` using gomonkey to mock cloud API calls, covering Create/Read/Update/Delete operations

## 4. Documentation

- [x] 4.1 Update `tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.md` with example usage showing all parameters including zone_id, status, rule_name, description, and branches
65 changes: 65 additions & 0 deletions openspec/specs/teo-l7-acc-rule-v2-resource/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## ADDED Requirements

### Requirement: Resource manages TEO L7 acceleration rule lifecycle

The `tencentcloud_teo_l7_acc_rule_v2` resource SHALL manage the full CRUD lifecycle of a TEO L7 acceleration rule using the following APIs:
- Create: `CreateL7AccRules` with `ZoneId` and `Rules` parameters
- Read: `DescribeL7AccRules` with `ZoneId` and `Filters` (rule-id filter using `Values`)
- Update: `ModifyL7AccRule` with `ZoneId` and `Rule` (containing `RuleId`, `Status`, `RuleName`, `Description`, `Branches`)
- Delete: `DeleteL7AccRules` with `ZoneId` and `RuleIds`

The resource SHALL use a composite ID format `{zone_id}#{rule_id}` with `tccommon.FILED_SP` as separator.

#### Scenario: Create a new L7 acceleration rule
- **WHEN** user applies a Terraform configuration with `tencentcloud_teo_l7_acc_rule_v2` resource specifying `zone_id`, `status`, `rule_name`, `description`, and `branches`
- **THEN** the resource SHALL call `CreateL7AccRules` API with the zone ID and a single `RuleEngineItem` containing the specified fields, and store the returned `rule_id` in state with composite ID format

#### Scenario: Read an existing L7 acceleration rule
- **WHEN** Terraform performs a refresh on the resource
- **THEN** the resource SHALL call `DescribeL7AccRules` API with `zone_id` and a filter for `rule-id` with the stored `rule_id` as the filter value, and update state with the returned `status`, `rule_name`, `description`, `branches`, and `rule_priority`

#### Scenario: Update an existing L7 acceleration rule
- **WHEN** user modifies `status`, `rule_name`, `description`, or `branches` in the Terraform configuration
- **THEN** the resource SHALL call `ModifyL7AccRule` API with `zone_id` and a `RuleEngineItem` containing the `rule_id` and updated fields

#### Scenario: Delete an L7 acceleration rule
- **WHEN** user destroys the resource
- **THEN** the resource SHALL call `DeleteL7AccRules` API with `zone_id` and `rule_id`

#### Scenario: Import an existing rule
- **WHEN** user imports a resource using `terraform import` with ID format `{zone_id}#{rule_id}`
- **THEN** the resource SHALL parse the composite ID and read the rule details from the API

### Requirement: Resource schema defines correct field types and constraints

The resource schema SHALL define the following fields:
- `zone_id`: TypeString, Required, ForceNew - Zone ID for the TEO site
- `status`: TypeString, Optional - Rule status (enable/disable)
- `rule_name`: TypeString, Optional - Rule name (max 255 characters)
- `description`: TypeList of TypeString, Optional - Rule annotations
- `branches`: TypeList of Resource, Optional - Sub-rule branches with conditions and actions
- `rule_id`: TypeString, Computed - Rule ID returned by the API
- `rule_priority`: TypeInt, Computed - Rule priority (output only)

#### Scenario: Zone ID is immutable after creation
- **WHEN** user attempts to change `zone_id` after resource creation
- **THEN** Terraform SHALL plan to destroy and recreate the resource (ForceNew behavior)

#### Scenario: Optional fields can be omitted
- **WHEN** user creates a resource without specifying `status`, `rule_name`, `description`, or `branches`
- **THEN** the resource SHALL be created successfully with API defaults for those fields

### Requirement: Error handling follows provider patterns

The resource SHALL implement proper error handling:
- All API calls MUST be wrapped with retry logic using `tccommon.RetryError()`
- Create MUST verify the response is not nil and `RuleIds` is not empty before storing the ID
- Read MUST check for nil response and empty rules list, logging the resource ID before clearing state

#### Scenario: Create API returns empty response
- **WHEN** the `CreateL7AccRules` API returns a nil response or empty `RuleIds`
- **THEN** the resource SHALL return a `NonRetryableError` with a descriptive message

#### Scenario: Read API returns no matching rule
- **WHEN** the `DescribeL7AccRules` API returns an empty rules list
- **THEN** the resource SHALL log the resource ID for debugging and set the ID to empty string to remove from state
24 changes: 17 additions & 7 deletions tencentcloud/services/teo/resource_tc_teo_l7_acc_rule_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,19 @@ func ResourceTencentCloudTeoL7AccRuleV2Create(d *schema.ResourceData, meta inter
result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTeoV20220901Client().CreateL7AccRules(request)
if e != nil {
return tccommon.RetryError(e)
} else {
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
}
if result.Response != nil && len(result.Response.RuleIds) > 0 && result.Response.RuleIds[0] != nil {
ruleId = *result.Response.RuleIds[0]
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
if result.Response == nil || len(result.Response.RuleIds) == 0 || result.Response.RuleIds[0] == nil || *result.Response.RuleIds[0] == "" {
return resource.NonRetryableError(fmt.Errorf("api[%s] returned empty rule id, response: %s", request.GetAction(), result.ToJsonString()))
}
ruleId = *result.Response.RuleIds[0]
return nil
})
if err != nil {
return err
}

log.Printf("[DEBUG]%s teo_l7_acc_rule_v2 created, logId: %s, id: %s\n", logId, logId, zoneId+tccommon.FILED_SP+ruleId)
d.SetId(zoneId + tccommon.FILED_SP + ruleId)

return ResourceTencentCloudTeoL7AccRuleV2Read(d, meta)
Expand Down Expand Up @@ -149,16 +150,25 @@ func ResourceTencentCloudTeoL7AccRuleV2Read(d *schema.ResourceData, meta interfa
}

if respData == nil || len(respData.Rules) == 0 {
log.Printf("[WARN]%s resource `teo_l7_acc_rule_v2` [%s] not found, please check if it has been deleted.\n", logId, d.Id())
d.SetId("")
log.Printf("[WARN]%s resource `teo_l7_acc_rule` [%s] not found, please check if it has been deleted.\n", logId, d.Id())
return nil
}
if len(respData.Rules) > 0 {
rule := respData.Rules[0]

rule := respData.Rules[0]
if rule.Status != nil {
_ = d.Set("status", rule.Status)
}
if rule.RuleName != nil {
_ = d.Set("rule_name", rule.RuleName)
}
if rule.Description != nil {
_ = d.Set("description", rule.Description)
}
if rule.RulePriority != nil {
_ = d.Set("rule_priority", rule.RulePriority)
}
if rule.Branches != nil {
_ = d.Set("branches", resourceTencentCloudTeoL7AccRuleSetBranchs(rule.Branches))
}

Expand Down
Loading
Loading