From f74a1ef8c66ed91b7a9cbaa5c95b015c3d45da80 Mon Sep 17 00:00:00 2001 From: iac-agent Date: Wed, 2 Sep 2026 15:52:23 +0800 Subject: [PATCH] feat(dlc): add tencentcloud_dlc_internal_table resource --- .changelog/4478.txt | 3 + go.mod | 2 +- go.sum | 4 +- .../.openspec.yaml | 2 + .../design.md | 44 + .../proposal.md | 32 + .../specs/dlc-internal-table/spec.md | 71 + .../tasks.md | 27 + openspec/specs/dlc-internal-table/spec.md | 74 + tencentcloud/provider.go | 1 + tencentcloud/provider.md | 1 + .../dlc/resource_tc_dlc_internal_table.go | 1714 +++++++++++++++++ .../dlc/resource_tc_dlc_internal_table.md | 113 ++ .../resource_tc_dlc_internal_table_test.go | 517 +++++ .../services/dlc/service_tencentcloud_dlc.go | 45 + .../tencentcloud/dlc/v20210125/client.go | 88 +- .../tencentcloud/dlc/v20210125/errors.go | 15 + .../tencentcloud/dlc/v20210125/models.go | 393 +++- vendor/modules.txt | 2 +- .../docs/r/dlc_internal_table.html.markdown | 306 +++ website/tencentcloud.erb | 3 + 21 files changed, 3385 insertions(+), 72 deletions(-) create mode 100644 .changelog/4478.txt create mode 100644 openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/.openspec.yaml create mode 100644 openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/design.md create mode 100644 openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/proposal.md create mode 100644 openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/specs/dlc-internal-table/spec.md create mode 100644 openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/tasks.md create mode 100644 openspec/specs/dlc-internal-table/spec.md create mode 100644 tencentcloud/services/dlc/resource_tc_dlc_internal_table.go create mode 100644 tencentcloud/services/dlc/resource_tc_dlc_internal_table.md create mode 100644 tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go create mode 100644 website/docs/r/dlc_internal_table.html.markdown diff --git a/.changelog/4478.txt b/.changelog/4478.txt new file mode 100644 index 0000000000..6a6d0e15cd --- /dev/null +++ b/.changelog/4478.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +tencentcloud_dlc_internal_table +``` diff --git a/go.mod b/go.mod index 2b609f57d8..92cb29b1c2 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dbbrain v1.3.26 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dc v1.0.633 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dcdb v1.0.673 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.156 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.170 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.124 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/domain v1.0.414 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dts v1.3.153 diff --git a/go.sum b/go.sum index 248d73ef22..77c7d2c838 100644 --- a/go.sum +++ b/go.sum @@ -1028,8 +1028,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dc v1.0.633 h1:Ul5iNhXo github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dc v1.0.633/go.mod h1:tc6Hvf03M1cBtMC1IKSa5mlOn3kpxWOwhWU1fRy+KEE= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dcdb v1.0.673 h1:YyjGLjvPDKNlpbGt89WLFif7TjId0fHzcrGOaHSQRNQ= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dcdb v1.0.673/go.mod h1:hXPMop1kJFqAvHj+7TyxxxXS/HGUP4SuKx5gGoAl0Zc= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.156 h1:78OGMhGeGrjml9AAqmeqPfCQXiLz/tM9EjoR3+dVPL0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.156/go.mod h1:/CbfEeeufmoAvXiehDi34baOOE9j/tewKIEq69PxxGY= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.170 h1:VsoGS3U0Fk7wBBlnoUb2GPtEqD98rEVd0l6bYKfYfWw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.170/go.mod h1:LE2EeLNcCSlSHFP8WuPBtZLPsGmZOEKqEokr/WXxiNQ= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.124 h1:atQm8S0BLrr3E+Yn2383KQUEEXpQ6z31MsprAKzMDDE= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.124/go.mod h1:zxlW9EAn0Hqx6Eub6MMocnHZz/gHundkyI7CdbIhU3o= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/domain v1.0.414 h1:egwjvOEUKBaxsoRVn/YSEhp2E8qdh77Ous9A/wftDo0= diff --git a/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/.openspec.yaml b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/.openspec.yaml new file mode 100644 index 0000000000..032461ff9f --- /dev/null +++ b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-02 diff --git a/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/design.md b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/design.md new file mode 100644 index 0000000000..ade604c7f6 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/design.md @@ -0,0 +1,44 @@ +## Context + +The DLC (Data Lake Compute) product exposes `GenerateInternalTable` to create a managed/internal table (Iceberg, Hive, etc.) and `DeleteTable` / `AlterTableComment` / `DescribeTable` to manage it. There is no single "table id" returned by the create API; a table is uniquely identified within a datasource by `DatabaseName` + `TableName` (and optionally `DatasourceConnectionName`). The provider already hosts DLC resources under `tencentcloud/services/dlc/` (e.g. `tencentcloud_dlc_data_engine`, `tencentcloud_dlc_user`), so the new resource follows the same package and the established `tencentcloud_igtm_strategy` code style. + +All four APIs are synchronous: `GenerateInternalTable` returns the generated SQL (`Execution.SQL`) and an `IsTIcebergSql` flag, but no task/job id. No async polling is required. + +## Goals / Non-Goals + +**Goals:** +- Provide a `tencentcloud_dlc_internal_table` resource with full CRUD: create via `GenerateInternalTable`, read via `DescribeTable`, update via `AlterTableComment`, delete via `DeleteTable`. +- Surface every cloud-API parameter mapped in the proposal as a Terraform schema field, including the deeply nested smart-governance policy tree (`smart_policy` → `base_info` / `policy` → `resources` / `written` / `lifecycle` / `index` / `change_table` / `table_expiration`). +- Support import using the composite `database_name#table_name` id. +- Keep the implementation consistent with provider conventions: `tccommon` retry on reads, nil-checks before `d.Set`, `NonRetryableError` on empty create results, composite id with `tccommon.FILED_SP`. + +**Non-Goals:** +- No support for altering columns/partitions/properties after creation. `AlterTableComment` only updates `TableBaseInfo` (comment/type/format/etc.); structural changes (columns, partitions, properties, smart policy) are therefore `ForceNew` to avoid drift, because no cloud API exists to update them in place. (This matches the code-gen requirement: only fields present in the update API are mutable; the rest are immutable.) +- No async-job polling (no async APIs involved). +- No data-source variant in this change. + +## Decisions + +### 1. Composite resource ID = `database_name#table_name` +**Rationale**: `GenerateInternalTable` does not return an opaque id; `DescribeTable` queries by `DatabaseName` + `TableName`. Joining them with `tccommon.FILED_SP` (`#`) gives a stable, import-friendly id. +**Alternative considered**: Including `datasource_connection_name` in the id. Rejected because it is optional and frequently empty; keeping the id to the two required keys is simpler and matches how `DescribeTable` is typically called. `datasource_connection_name` remains a regular (non-id) schema field passed to each API. + +### 2. Update scope limited to `AlterTableComment`-editable fields +**Rationale**: The only update API is `AlterTableComment`, which accepts a `TableBaseInfo`. Only the scalar `TableBaseInfo` fields that the cloud API actually honors for an alter are mutable in Update; everything else (columns, partitions, properties, upsert_keys, smart_policy, primary_keys) is `ForceNew`. Per the code-gen rules, fields not supported by the update API must not appear in the update path. +**Alternative considered**: Calling `GenerateInternalTable` again to "recreate". Rejected — that would be delete+create, which Terraform already does via `ForceNew`. + +### 3. Read populates read-only computed fields from `DescribeTable` +`DescribeTable` returns extra computed-only fields (`location`, `modified_time`, `create_time`, `input_format`, `storage_size`, `record_count`, `map_materialized_view_name`, `heat_value`, `input_format_short`, per-column `nullable`/`create_time`/`modified_time`/`data_mask_strategy_info`/`type_text`, per-partition `create_time`, and the create-response `execution`/`is_t_iceberg_sql`). These are exposed as `Computed` schema attributes so users can reference them, but they are never sent on create/update. + +### 4. Schema structure follows the JsonPath mapping (flattened, not re-nested) +The `table_base_info` object is flattened to top-level scalars (`database_name`, `table_name`, `datasource_connection_name`, `table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, `govern_policy.*`, `db_govern_policy_is_disable`, `smart_policy.*`, `primary_keys`). `columns`, `partitions`, `properties`, `upsert_keys` are top-level lists. This matches the provider convention of flattening nested request objects and avoids redundant wrapper blocks. The deprecated `govern_policy` / `db_govern_policy_is_disable` fields are still exposed (optional) because the cloud API accepts them. + +### 5. Smart-governance policy tree modeled with `TypeList`/`MaxItems: 1` blocks +`smart_policy`, `base_info`, `policy`, `resources` (list, since the API uses `[]*ResourceInfo`), `favor` (list), `resource_conf`, `written`, `advance_policy`, `sort_orders` (list), `lifecycle`, `index`, `change_table`, `table_expiration` are nested `TypeList` blocks with `MaxItems: 1` where the API field is a single struct, and plain `TypeList` where the API field is a slice. Required sub-fields (`base_info.uin`, `table_expiration.enabled`, `table_expiration.expiration`) are `Required` inside their blocks. + +## Risks / Trade-offs + +- **[Risk] Structural changes require recreation** → Mitigation: documented as `ForceNew` for columns/partitions/properties/smart_policy/primary_keys/upsert_keys; the `AlterTableComment` path handles only the mutable `TableBaseInfo` scalars. Acceptable because the cloud API offers no in-place column/partition update. +- **[Risk] `datasource_connection_name` not in id may collide across datasources** → Mitigation: rare in practice; documented in the `.md` import section that the id is `database_name#table_name` and that cross-datasource tables should rely on distinct database names. If needed later, the id scheme can be extended without breaking existing state (the two-part id remains a valid prefix). +- **[Risk] Deprecated fields (`govern_policy`, `db_govern_policy_is_disable`, `drop_table`) may be removed by the cloud API** → Mitigation: kept optional and clearly documented as deprecated; their absence from a response is handled by nil-checks before `d.Set`. +- **[Trade-off] Large nested schema** → The smart-policy tree is deep, but flattening would lose the API's structure and make the HCL harder to write. Nested blocks are the lesser evil and match the JsonPath mapping exactly. diff --git a/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/proposal.md b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/proposal.md new file mode 100644 index 0000000000..4974578814 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/proposal.md @@ -0,0 +1,32 @@ +## Why + +Tencent Cloud DLC (Data Lake Compute) supports creating internal tables (e.g. Iceberg/Hive managed tables) via the `GenerateInternalTable` API, but there is currently no Terraform resource to manage the full lifecycle of an internal table. Users who manage their lakehouse schema through Terraform have no way to declare DLC internal tables as code, forcing them to use the console or ad-hoc SQL. Adding a `tencentcloud_dlc_internal_table` resource closes this gap and lets DLC tables be version-controlled, drift-detected, and destroyed alongside other infrastructure. + +## What Changes + +- Add a new RESOURCE_KIND_GENERAL resource `tencentcloud_dlc_internal_table` under `tencentcloud/services/dlc/`. +- Implement Create (`GenerateInternalTable`), Read (`DescribeTable`), Update (`AlterTableComment`), and Delete (`DeleteTable`) handlers. +- Expose the table base info, columns, partitions, properties, upsert keys, and the (optional) smart-governance policy tree as schema fields, matching the cloud API parameter mapping. +- Register the resource in `tencentcloud/provider.go` and document it in `tencentcloud/provider.md` + a `resource_tc_dlc_internal_table.md` example. +- Add unit tests (`resource_tc_dlc_internal_table_test.go`) using gomonkey mocks (no Terraform acc suite). + +## Capabilities + +### New Capabilities +- `dlc-internal-table`: Manages the full CRUD lifecycle of a DLC internal table (base info, columns, partitions, properties, smart governance policy). + +### Modified Capabilities + + +## Impact + +- **New files**: + - `tencentcloud/services/dlc/resource_tc_dlc_internal_table.go` + - `tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go` + - `tencentcloud/services/dlc/resource_tc_dlc_internal_table.md` +- **Modified files**: + - `tencentcloud/provider.go` (register resource in `resourcesMap`) + - `tencentcloud/provider.md` (auto-generated doc entry, produced via `make doc`) +- **Cloud APIs** (dlc v20210125): `GenerateInternalTable`, `DescribeTable`, `AlterTableComment`, `DeleteTable`. All four are synchronous (no async polling required). +- **Resource ID**: composite `database_name#table_name` (joined with `tccommon.FILED_SP`), since `GenerateInternalTable` does not return a single unique ID and `DescribeTable` queries by `DatabaseName` + `TableName` (+ optional `DatasourceConnectionName`). Supports import via the composite ID. +- **Backward compatibility**: Pure addition; no existing schema or state is affected. diff --git a/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/specs/dlc-internal-table/spec.md b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/specs/dlc-internal-table/spec.md new file mode 100644 index 0000000000..cdd59eea91 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/specs/dlc-internal-table/spec.md @@ -0,0 +1,71 @@ +## ADDED Requirements + +### Requirement: Resource manages DLC internal table lifecycle +The provider SHALL provide a `tencentcloud_dlc_internal_table` resource that manages the full lifecycle (create, read, update, delete) of a Tencent Cloud DLC internal table via the `GenerateInternalTable`, `DescribeTable`, `AlterTableComment`, and `DeleteTable` cloud APIs (dlc v20210125). + +#### Scenario: Create a new internal table +- **WHEN** a user applies a `tencentcloud_dlc_internal_table` configuration with required fields `database_name`, `table_name`, and `columns` (each column with `name` and `type`) +- **THEN** the provider SHALL call `GenerateInternalTable` with `TableBaseInfo`, `Columns`, and any provided `Partitions`/`Properties`/`UpsertKeys`, and SHALL set the Terraform resource id to `database_name#table_name` (joined with `tccommon.FILED_SP`) + +#### Scenario: Read an existing internal table +- **WHEN** the provider reads the resource state +- **THEN** the provider SHALL call `DescribeTable` using `TableName`, `DatabaseName`, and (if set) `DatasourceConnectionName` derived from the composite id and schema, and SHALL populate all schema fields from the returned `Table` object after nil-checking each field + +#### Scenario: Table not found during read +- **WHEN** `DescribeTable` returns an empty response (no `Table` / `TableBaseInfo`) +- **THEN** the provider SHALL log `log.Printf("[CRUD] dlc_internal_table id=%s", d.Id())` preserving the id, then call `d.SetId("")` to remove the resource from state + +#### Scenario: Delete an internal table +- **WHEN** the user destroys the resource +- **THEN** the provider SHALL call `DeleteTable` with a `TableBaseInfo` populated from the composite id (`database_name`, `table_name`) and the `datasource_connection_name` if set + +#### Scenario: Empty create result is rejected +- **WHEN** `GenerateInternalTable` succeeds but returns an empty response (nil `Response` or empty result) +- **THEN** the provider SHALL return a `NonRetryableError` rather than writing an empty id, after logging the current logId and `d.Id()` + +### Requirement: Resource id is a composite of database and table name +The resource id SHALL be the composite `database_name#table_name` joined with `tccommon.FILED_SP`, because `GenerateInternalTable` returns no opaque id and `DescribeTable` is queried by `DatabaseName` + `TableName`. + +#### Scenario: Import by composite id +- **WHEN** a user runs `terraform import tencentcloud_dlc_internal_table.foo #` +- **THEN** the provider SHALL split the id on `tccommon.FILED_SP` to recover `database_name` and `table_name` and SHALL populate the schema from a subsequent `DescribeTable` read + +### Requirement: Update is limited to AlterTableComment-editable fields +The provider SHALL handle updates by calling `AlterTableComment` with the updated `TableBaseInfo`. Only the scalar `TableBaseInfo` fields accepted by `AlterTableComment` (`table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, `datasource_connection_name`, and the smart-governance policy tree rooted at `table_base_info`) SHALL be mutable in place. + +#### Scenario: Update mutable table base info +- **WHEN** a user changes `table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, or the `govern_policy`/`smart_policy` subtree +- **THEN** the provider SHALL call `AlterTableComment` with the new `TableBaseInfo` and SHALL refresh state from `DescribeTable` + +#### Scenario: Structural change forces recreation +- **WHEN** a user changes `database_name`, `table_name`, `columns`, `partitions`, `properties`, `upsert_keys`, or `primary_keys` +- **THEN** the provider SHALL treat the change as `ForceNew` (destroy + create), because no cloud API supports in-place structural updates + +### Requirement: Schema exposes all mapped cloud-API parameters +The resource schema SHALL expose every cloud-API parameter mapped in the proposal: the flattened `table_base_info` scalars (`database_name`, `table_name`, `datasource_connection_name`, `table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, `govern_policy.*`, `db_govern_policy_is_disable`, `smart_policy.*`, `primary_keys`), the `columns` list (`name`, `type`, `comment`, `default`, `not_null`, `precision`, `scale`, `position`, `is_partition`), the `partitions` list, the `properties` list (`key`, `value`), and `upsert_keys`. + +#### Scenario: Required fields enforced +- **WHEN** a user omits `database_name`, `table_name`, or `columns` (or a column's `name`/`type`), or `smart_policy.base_info.uin`, or `smart_policy.policy.table_expiration.enabled`/`expiration` +- **THEN** Terraform SHALL reject the configuration before apply because these fields are `Required` + +#### Scenario: Optional fields default to unset +- **WHEN** a user omits optional fields such as `partitions`, `properties`, `upsert_keys`, `datasource_connection_name`, or any optional smart-policy sub-field +- **THEN** the provider SHALL not send those fields to the cloud API on create + +### Requirement: Read populates computed-only fields from DescribeTable +The resource schema SHALL expose computed-only attributes returned by `DescribeTable` but never sent on create/update: `location`, `modified_time`, `create_time`, `input_format`, `storage_size`, `record_count`, `map_materialized_view_name`, `heat_value`, `input_format_short`, per-column `nullable`/`create_time`/`modified_time`/`data_mask_strategy_info`/`type_text`, per-partition `create_time`, and the create response `execution`/`is_t_iceberg_sql`. + +#### Scenario: Computed fields populated after read +- **WHEN** `DescribeTable` returns a `Table` with `Location`, `StorageSize`, `RecordCount`, etc. +- **THEN** the provider SHALL set the corresponding computed schema fields, after nil-checking each, so they are available in state + +### Requirement: Retry and error handling follow provider conventions +All cloud-API calls in Read SHALL be wrapped with `tccommon.ReadRetryTimeout` retry; failures SHALL be wrapped with `tccommon.RetryError()`. Setting ids/state SHALL happen outside the retry block. Create SHALL check the API result for emptiness and return `NonRetryableError` when empty. + +#### Scenario: Transient read failure is retried +- **WHEN** `DescribeTable` fails with a transient error +- **THEN** the provider SHALL retry up to `tccommon.ReadRetryTimeout` before surfacing the error wrapped in `tccommon.RetryError()` + +#### Scenario: Id/state set outside retry +- **WHEN** a Read succeeds inside the retry block +- **THEN** the provider SHALL perform `d.SetId()` and `d.Set()` calls outside the retry block, after the retry returns diff --git a/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/tasks.md b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/tasks.md new file mode 100644 index 0000000000..e55bc40d70 --- /dev/null +++ b/openspec/changes/archive/2026-09-02-add-dlc-internal-table-resource/tasks.md @@ -0,0 +1,27 @@ +## 1. Resource Schema & CRUD Implementation + +- [x] 1.1 Create `tencentcloud/services/dlc/resource_tc_dlc_internal_table.go` with `ResourceTencentCloudDlcInternalTable()` schema: flattened `table_base_info` scalars (`database_name` Required+ForceNew, `table_name` Required+ForceNew, `datasource_connection_name` Optional, `table_comment` Optional, `type` Optional, `table_format` Optional, `user_alias` Optional, `user_sub_uin` Optional, `db_govern_policy_is_disable` Optional), `govern_policy` block (Optional, `rule_type`, `govern_engine`), `smart_policy` nested block tree (Optional; `base_info` with Required `uin`, `policy_type`, `catalog`, `database`, `table`, `app_id`; `policy` with `inherit`, `resources` list, `written`/`advance_policy`/`sort_orders`, `lifecycle`, `index`, `change_table`, `table_expiration` with Required `enabled`/`expiration`), `primary_keys` (Optional+ForceNew), `columns` (Required+ForceNew; `name`/`type` Required, `comment`/`default`/`not_null`/`precision`/`scale`/`position`/`is_partition` Optional), `partitions` (Optional+ForceNew), `properties` (Optional+ForceNew; `key`/`value` Required), `upsert_keys` (Optional+ForceNew), plus computed fields (`location`, `modified_time`, `create_time`, `input_format`, `storage_size`, `record_count`, `map_materialized_view_name`, `heat_value`, `input_format_short`, per-column computed `nullable`/`create_time`/`modified_time`/`data_mask_strategy_info`/`type_text`, per-partition `create_time`, `execution`, `is_t_iceberg_sql`) +- [x] 1.2 Implement `resourceTencentCloudDlcInternalTableCreate`: build `GenerateInternalTableRequest` from schema (`TableBaseInfo`, `Columns` as `[]*TColumn`, `Partitions` as `[]*TPartition`, `Properties`, `UpsertKeys`), call API with retry, check empty result → `NonRetryableError` (log logId + d.Id() first), set `d.SetId(database_name#table_name)` outside retry, then call Read +- [x] 1.3 Implement `resourceTencentCloudDlcInternalTableRead`: split composite id into `database_name`/`table_name`, call `DescribeTable` (with `DatasourceConnectionName` if set) inside `tccommon.ReadRetryTimeout` retry; on empty response log `[CRUD] dlc_internal_table id=%s` then `d.SetId("")`; otherwise nil-check each field before `d.Set`; populate computed fields from `TableResponseInfo`; set state outside retry +- [x] 1.4 Implement `resourceTencentCloudDlcInternalTableUpdate`: diff mutable `TableBaseInfo` scalars + `govern_policy`/`smart_policy` subtree; call `AlterTableComment` with updated `TableBaseInfo`; then call Read. `database_name`/`table_name`/`columns`/`partitions`/`properties`/`upsert_keys`/`primary_keys` are `ForceNew` so they never reach Update +- [x] 1.5 Implement `resourceTencentCloudDlcInternalTableDelete`: build `TableBaseInfo` from id + `datasource_connection_name`, call `DeleteTable` with retry +- [x] 1.6 Add `Importer: schema.ImportStatePassthrough` to support `terraform import` via composite id + +## 2. Provider Registration + +- [x] 2.1 Register `"tencentcloud_dlc_internal_table": dlc.ResourceTencentCloudDlcInternalTable()` in `tencentcloud/provider.go` `resourcesMap` +- [ ] 2.2 Add the resource entry to `tencentcloud/provider.md` (via `make doc` in the finalize phase; do NOT hand-edit `website/`) + +## 3. Documentation + +- [x] 3.1 Create `tencentcloud/services/dlc/resource_tc_dlc_internal_table.md` with one-line description (mentioning DLC), Example Usage (use `jsonencode()` for any JSON-string fields), and an Import section documenting the composite `database_name#table_name` id + +## 4. Unit Tests + +- [x] 4.1 Create `tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go` using gomonkey mocks for the DLC SDK client (no Terraform acc suite): mock `GenerateInternalTable`, `DescribeTable`, `AlterTableComment`, `DeleteTable`; cover create-then-read, update mutable fields, delete, empty-create-result error, and table-not-found read-clears-id paths + +## 5. Finalize (deferred to tfpacer-finalize) + +- [ ] 5.1 Run `gofmt` on changed Go files +- [ ] 5.2 Run `make doc` to generate `website/docs/` docs and update `provider.md` +- [ ] 5.3 Generate `.changelog/` entry diff --git a/openspec/specs/dlc-internal-table/spec.md b/openspec/specs/dlc-internal-table/spec.md new file mode 100644 index 0000000000..0d2d945969 --- /dev/null +++ b/openspec/specs/dlc-internal-table/spec.md @@ -0,0 +1,74 @@ +# dlc-internal-table Specification + +## Purpose +TBD - created by archiving change add-dlc-internal-table-resource. Update Purpose after archive. +## Requirements +### Requirement: Resource manages DLC internal table lifecycle +The provider SHALL provide a `tencentcloud_dlc_internal_table` resource that manages the full lifecycle (create, read, update, delete) of a Tencent Cloud DLC internal table via the `GenerateInternalTable`, `DescribeTable`, `AlterTableComment`, and `DeleteTable` cloud APIs (dlc v20210125). + +#### Scenario: Create a new internal table +- **WHEN** a user applies a `tencentcloud_dlc_internal_table` configuration with required fields `database_name`, `table_name`, and `columns` (each column with `name` and `type`) +- **THEN** the provider SHALL call `GenerateInternalTable` with `TableBaseInfo`, `Columns`, and any provided `Partitions`/`Properties`/`UpsertKeys`, and SHALL set the Terraform resource id to `database_name#table_name` (joined with `tccommon.FILED_SP`) + +#### Scenario: Read an existing internal table +- **WHEN** the provider reads the resource state +- **THEN** the provider SHALL call `DescribeTable` using `TableName`, `DatabaseName`, and (if set) `DatasourceConnectionName` derived from the composite id and schema, and SHALL populate all schema fields from the returned `Table` object after nil-checking each field + +#### Scenario: Table not found during read +- **WHEN** `DescribeTable` returns an empty response (no `Table` / `TableBaseInfo`) +- **THEN** the provider SHALL log `log.Printf("[CRUD] dlc_internal_table id=%s", d.Id())` preserving the id, then call `d.SetId("")` to remove the resource from state + +#### Scenario: Delete an internal table +- **WHEN** the user destroys the resource +- **THEN** the provider SHALL call `DeleteTable` with a `TableBaseInfo` populated from the composite id (`database_name`, `table_name`) and the `datasource_connection_name` if set + +#### Scenario: Empty create result is rejected +- **WHEN** `GenerateInternalTable` succeeds but returns an empty response (nil `Response` or empty result) +- **THEN** the provider SHALL return a `NonRetryableError` rather than writing an empty id, after logging the current logId and `d.Id()` + +### Requirement: Resource id is a composite of database and table name +The resource id SHALL be the composite `database_name#table_name` joined with `tccommon.FILED_SP`, because `GenerateInternalTable` returns no opaque id and `DescribeTable` is queried by `DatabaseName` + `TableName`. + +#### Scenario: Import by composite id +- **WHEN** a user runs `terraform import tencentcloud_dlc_internal_table.foo #` +- **THEN** the provider SHALL split the id on `tccommon.FILED_SP` to recover `database_name` and `table_name` and SHALL populate the schema from a subsequent `DescribeTable` read + +### Requirement: Update is limited to AlterTableComment-editable fields +The provider SHALL handle updates by calling `AlterTableComment` with the updated `TableBaseInfo`. Only the scalar `TableBaseInfo` fields accepted by `AlterTableComment` (`table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, `datasource_connection_name`, and the smart-governance policy tree rooted at `table_base_info`) SHALL be mutable in place. + +#### Scenario: Update mutable table base info +- **WHEN** a user changes `table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, or the `govern_policy`/`smart_policy` subtree +- **THEN** the provider SHALL call `AlterTableComment` with the new `TableBaseInfo` and SHALL refresh state from `DescribeTable` + +#### Scenario: Structural change forces recreation +- **WHEN** a user changes `database_name`, `table_name`, `columns`, `partitions`, `properties`, `upsert_keys`, or `primary_keys` +- **THEN** the provider SHALL treat the change as `ForceNew` (destroy + create), because no cloud API supports in-place structural updates + +### Requirement: Schema exposes all mapped cloud-API parameters +The resource schema SHALL expose every cloud-API parameter mapped in the proposal: the flattened `table_base_info` scalars (`database_name`, `table_name`, `datasource_connection_name`, `table_comment`, `type`, `table_format`, `user_alias`, `user_sub_uin`, `govern_policy.*`, `db_govern_policy_is_disable`, `smart_policy.*`, `primary_keys`), the `columns` list (`name`, `type`, `comment`, `default`, `not_null`, `precision`, `scale`, `position`, `is_partition`), the `partitions` list, the `properties` list (`key`, `value`), and `upsert_keys`. + +#### Scenario: Required fields enforced +- **WHEN** a user omits `database_name`, `table_name`, or `columns` (or a column's `name`/`type`), or `smart_policy.base_info.uin`, or `smart_policy.policy.table_expiration.enabled`/`expiration` +- **THEN** Terraform SHALL reject the configuration before apply because these fields are `Required` + +#### Scenario: Optional fields default to unset +- **WHEN** a user omits optional fields such as `partitions`, `properties`, `upsert_keys`, `datasource_connection_name`, or any optional smart-policy sub-field +- **THEN** the provider SHALL not send those fields to the cloud API on create + +### Requirement: Read populates computed-only fields from DescribeTable +The resource schema SHALL expose computed-only attributes returned by `DescribeTable` but never sent on create/update: `location`, `modified_time`, `create_time`, `input_format`, `storage_size`, `record_count`, `map_materialized_view_name`, `heat_value`, `input_format_short`, per-column `nullable`/`create_time`/`modified_time`/`data_mask_strategy_info`/`type_text`, per-partition `create_time`, and the create response `execution`/`is_t_iceberg_sql`. + +#### Scenario: Computed fields populated after read +- **WHEN** `DescribeTable` returns a `Table` with `Location`, `StorageSize`, `RecordCount`, etc. +- **THEN** the provider SHALL set the corresponding computed schema fields, after nil-checking each, so they are available in state + +### Requirement: Retry and error handling follow provider conventions +All cloud-API calls in Read SHALL be wrapped with `tccommon.ReadRetryTimeout` retry; failures SHALL be wrapped with `tccommon.RetryError()`. Setting ids/state SHALL happen outside the retry block. Create SHALL check the API result for emptiness and return `NonRetryableError` when empty. + +#### Scenario: Transient read failure is retried +- **WHEN** `DescribeTable` fails with a transient error +- **THEN** the provider SHALL retry up to `tccommon.ReadRetryTimeout` before surfacing the error wrapped in `tccommon.RetryError()` + +#### Scenario: Id/state set outside retry +- **WHEN** a Read succeeds inside the retry block +- **THEN** the provider SHALL perform `d.SetId()` and `d.Set()` calls outside the retry block, after the retry returns diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index 25efc11436..e492d33aef 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -2551,6 +2551,7 @@ func Provider() *schema.Provider { "tencentcloud_dlc_standard_engine_resource_group_config_info": dlc.ResourceTencentCloudDlcStandardEngineResourceGroupConfigInfo(), "tencentcloud_dlc_datasource_house_attachment": dlc.ResourceTencentCloudDlcDatasourceHouseAttachment(), "tencentcloud_dlc_attach_user_policy_attachment": dlc.ResourceTencentCloudDlcAttachUserPolicyAttachment(), + "tencentcloud_dlc_internal_table": dlc.ResourceTencentCloudDlcInternalTable(), "tencentcloud_waf_custom_rule": waf.ResourceTencentCloudWafCustomRule(), "tencentcloud_waf_custom_white_rule": waf.ResourceTencentCloudWafCustomWhiteRule(), "tencentcloud_waf_clb_domain": waf.ResourceTencentCloudWafClbDomain(), diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index b3c1a8578a..a8d1d2d0a5 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -2348,6 +2348,7 @@ tencentcloud_dlc_attach_data_mask_policy tencentcloud_dlc_standard_engine_resource_group_config_info tencentcloud_dlc_datasource_house_attachment tencentcloud_dlc_attach_user_policy_attachment +tencentcloud_dlc_internal_table Web Application Firewall(WAF) Data Source diff --git a/tencentcloud/services/dlc/resource_tc_dlc_internal_table.go b/tencentcloud/services/dlc/resource_tc_dlc_internal_table.go new file mode 100644 index 0000000000..b40ded91ae --- /dev/null +++ b/tencentcloud/services/dlc/resource_tc_dlc_internal_table.go @@ -0,0 +1,1714 @@ +package dlc + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + dlc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125" + + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func ResourceTencentCloudDlcInternalTable() *schema.Resource { + return &schema.Resource{ + Create: resourceTencentCloudDlcInternalTableCreate, + Read: resourceTencentCloudDlcInternalTableRead, + Update: resourceTencentCloudDlcInternalTableUpdate, + Delete: resourceTencentCloudDlcInternalTableDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "database_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the database to which the internal table belongs.", + }, + + "table_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the internal table.", + }, + + "datasource_connection_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the datasource connection to which the table belongs.", + }, + + "table_comment": { + Type: schema.TypeString, + Optional: true, + Description: "The comment of the table.", + }, + + "type": { + Type: schema.TypeString, + Optional: true, + Description: "The type of the table, table or view.", + }, + + "table_format": { + Type: schema.TypeString, + Optional: true, + Description: "The format of the table, such as hive, iceberg, etc.", + }, + + "user_alias": { + Type: schema.TypeString, + Optional: true, + Description: "The alias of the user who creates the table.", + }, + + "user_sub_uin": { + Type: schema.TypeString, + Optional: true, + Description: "The sub UIN of the user who creates the table.", + }, + + "db_govern_policy_is_disable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether the database data governance is disabled. true: disabled, false: enabled. Deprecated, use smart_policy instead.", + }, + + "govern_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Data governance policy. Deprecated, use smart_policy instead.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_type": { + Type: schema.TypeString, + Optional: true, + Description: "Governance rule type. Customize: custom; Intelligence: intelligent governance.", + }, + "govern_engine": { + Type: schema.TypeString, + Optional: true, + Description: "Governance engine.", + }, + }, + }, + }, + + "smart_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Smart data governance policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "base_info": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Base info of the smart policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "uin": { + Type: schema.TypeString, + Required: true, + Description: "User UIN.", + }, + "policy_type": { + Type: schema.TypeString, + Optional: true, + Description: "Policy type: Catalog/Database/Table.", + }, + "catalog": { + Type: schema.TypeString, + Optional: true, + Description: "Catalog name.", + }, + "database": { + Type: schema.TypeString, + Optional: true, + Description: "Database name.", + }, + "table": { + Type: schema.TypeString, + Optional: true, + Description: "Table name.", + }, + "app_id": { + Type: schema.TypeString, + Optional: true, + Description: "User APP ID.", + }, + }, + }, + }, + "policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Smart optimizer policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "inherit": { + Type: schema.TypeString, + Optional: true, + Description: "Whether to inherit.", + }, + "resources": { + Type: schema.TypeList, + Optional: true, + Description: "Data governance resources.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attribution_type": { + Type: schema.TypeString, + Optional: true, + Description: "Attribution type.", + }, + "resource_type": { + Type: schema.TypeString, + Optional: true, + Description: "Resource type.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Engine name.", + }, + "instance": { + Type: schema.TypeString, + Optional: true, + Description: "Instance name.", + }, + "status": { + Type: schema.TypeInt, + Optional: true, + Description: "Status.", + }, + "resource_group_name": { + Type: schema.TypeString, + Optional: true, + Description: "Standard engine resource group name.", + }, + "favor": { + Type: schema.TypeList, + Optional: true, + Description: "Affinity info list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "priority": { + Type: schema.TypeInt, + Optional: true, + Description: "Priority.", + }, + "catalog": { + Type: schema.TypeString, + Optional: true, + Description: "Catalog name.", + }, + "data_base": { + Type: schema.TypeString, + Optional: true, + Description: "Database name.", + }, + "table": { + Type: schema.TypeString, + Optional: true, + Description: "Table name.", + }, + }, + }, + }, + "resource_conf": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Resource configuration.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parallelism": { + Type: schema.TypeInt, + Optional: true, + Description: "The parallelism of the optimization task.", + }, + }, + }, + }, + }, + }, + }, + "written": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Data rewrite policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "written_enable": { + Type: schema.TypeString, + Optional: true, + Description: "none/enable/disable/default.", + }, + "advance_policy": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Advanced rewrite policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "compact_enable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether to enable compaction.", + }, + "delete_enable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether to enable history data cleanup.", + }, + "min_input_files": { + Type: schema.TypeInt, + Optional: true, + Description: "The minimum number of files to trigger compaction.", + }, + "target_file_size_bytes": { + Type: schema.TypeInt, + Optional: true, + Description: "Target file size in bytes for compaction.", + }, + "retain_last": { + Type: schema.TypeInt, + Optional: true, + Description: "Number of snapshots to retain.", + }, + "before_days": { + Type: schema.TypeInt, + Optional: true, + Description: "Snapshot expiration time in days.", + }, + "expired_snapshots_interval_min": { + Type: schema.TypeInt, + Optional: true, + Description: "Snapshot expiration execution interval in minutes.", + }, + "remove_orphan_interval_min": { + Type: schema.TypeInt, + Optional: true, + Description: "Orphan file removal execution interval in minutes.", + }, + "cow_compact_enable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether to enable COW table compaction.", + }, + "compact_strategy": { + Type: schema.TypeString, + Optional: true, + Description: "File compaction strategy.", + }, + "sort_orders": { + Type: schema.TypeList, + Optional: true, + Description: "Sort compaction strategy rules.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column": { + Type: schema.TypeString, + Optional: true, + Description: "Column name for sorting.", + }, + "sort_direction": { + Type: schema.TypeString, + Optional: true, + Description: "Sort direction: ascending or descending.", + }, + "null_order": { + Type: schema.TypeString, + Optional: true, + Description: "Null order: at the beginning or end.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "lifecycle": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Data lifecycle policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lifecycle_enable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether lifecycle is enabled.", + }, + "expiration": { + Type: schema.TypeInt, + Optional: true, + Description: "Expiration time.", + }, + "drop_table": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether to drop the table. Deprecated, use table_expiration instead.", + }, + "expired_field": { + Type: schema.TypeString, + Optional: true, + Description: "Expired field.", + }, + "expired_field_format": { + Type: schema.TypeString, + Optional: true, + Description: "Expired field format.", + }, + }, + }, + }, + "index": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Index policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "index_enable": { + Type: schema.TypeString, + Optional: true, + Description: "Whether to enable index.", + }, + }, + }, + }, + "change_table": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Change table policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_retention_time": { + Type: schema.TypeInt, + Optional: true, + Description: "Data retention time in days for the change table.", + }, + }, + }, + }, + "table_expiration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Table expiration policy.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: "Whether the policy is enabled.", + }, + "expiration": { + Type: schema.TypeInt, + Required: true, + Description: "Table expiration time in days.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "primary_keys": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Primary keys of the T-ICEBERG table.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "columns": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Description: "Column information of the table.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "Column name.", + }, + "type": { + Type: schema.TypeString, + Required: true, + Description: "Column type.", + }, + "comment": { + Type: schema.TypeString, + Optional: true, + Description: "Column comment.", + }, + "default": { + Type: schema.TypeString, + Optional: true, + Description: "Column default value.", + }, + "not_null": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether the column is not null.", + }, + "precision": { + Type: schema.TypeInt, + Optional: true, + Description: "The precision of the numeric type.", + }, + "scale": { + Type: schema.TypeInt, + Optional: true, + Description: "The scale of the numeric type.", + }, + "position": { + Type: schema.TypeInt, + Optional: true, + Description: "Column position, smaller is earlier.", + }, + "is_partition": { + Type: schema.TypeBool, + Optional: true, + Description: "Whether the column is a partition field.", + }, + "nullable": { + Type: schema.TypeString, + Computed: true, + Description: "Whether the column is nullable.", + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: "Column creation time.", + }, + "modified_time": { + Type: schema.TypeString, + Computed: true, + Description: "Column modification time.", + }, + "data_mask_strategy_info": { + Type: schema.TypeList, + Computed: true, + Description: "Data mask strategy info.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "strategy_name": { + Type: schema.TypeString, + Computed: true, + Description: "Strategy name.", + }, + "strategy_type": { + Type: schema.TypeString, + Computed: true, + Description: "Strategy type.", + }, + "strategy_desc": { + Type: schema.TypeString, + Computed: true, + Description: "Strategy description.", + }, + "users": { + Type: schema.TypeString, + Computed: true, + Description: "User sub UIN list separated by semicolons.", + }, + "strategy_id": { + Type: schema.TypeString, + Computed: true, + Description: "Strategy ID.", + }, + }, + }, + }, + "type_text": { + Type: schema.TypeString, + Computed: true, + Description: "Data field description.", + }, + }, + }, + }, + + "partitions": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Partition information of the table.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Description: "Partition column name.", + }, + "type": { + Type: schema.TypeString, + Optional: true, + Description: "Partition type.", + }, + "comment": { + Type: schema.TypeString, + Optional: true, + Description: "Partition comment.", + }, + "transform": { + Type: schema.TypeString, + Optional: true, + Description: "Implicit partition transform strategy.", + }, + "transform_args": { + Type: schema.TypeList, + Optional: true, + Description: "Transform strategy arguments.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "create_time": { + Type: schema.TypeInt, + Computed: true, + Description: "Partition creation time.", + }, + }, + }, + }, + + "properties": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Property information of the table.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + Description: "Property key.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "Property value.", + }, + }, + }, + }, + + "upsert_keys": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: "Upsert keys for V2 upsert table.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "location": { + Type: schema.TypeString, + Computed: true, + Description: "Data storage path.", + }, + + "modified_time": { + Type: schema.TypeString, + Computed: true, + Description: "Table modification time, in ms.", + }, + + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: "Table creation time, in ms.", + }, + + "input_format": { + Type: schema.TypeString, + Computed: true, + Description: "Data format.", + }, + + "storage_size": { + Type: schema.TypeInt, + Computed: true, + Description: "Table storage size in bytes.", + }, + + "record_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Table row count.", + }, + + "map_materialized_view_name": { + Type: schema.TypeString, + Computed: true, + Description: "Materialized view name mapping.", + }, + + "heat_value": { + Type: schema.TypeInt, + Computed: true, + Description: "Access heat value.", + }, + + "input_format_short": { + Type: schema.TypeString, + Computed: true, + Description: "Abbreviation of InputFormat.", + }, + + "execution": { + Type: schema.TypeString, + Computed: true, + Description: "The auto-generated SQL statement from create.", + }, + + "is_t_iceberg_sql": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether it is T-ICEBERG SQL.", + }, + }, + } +} + +func resourceTencentCloudDlcInternalTableCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_dlc_internal_table.create")() + defer tccommon.InconsistentCheck(d, meta)() + + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + request = dlc.NewGenerateInternalTableRequest() + response = dlc.NewGenerateInternalTableResponse() + ) + + tableBaseInfo := &dlc.TableBaseInfo{} + if v, ok := d.GetOk("database_name"); ok { + tableBaseInfo.DatabaseName = helper.String(v.(string)) + } + if v, ok := d.GetOk("table_name"); ok { + tableBaseInfo.TableName = helper.String(v.(string)) + } + if v, ok := d.GetOk("datasource_connection_name"); ok { + tableBaseInfo.DatasourceConnectionName = helper.String(v.(string)) + } + if v, ok := d.GetOk("table_comment"); ok { + tableBaseInfo.TableComment = helper.String(v.(string)) + } + if v, ok := d.GetOk("type"); ok { + tableBaseInfo.Type = helper.String(v.(string)) + } + if v, ok := d.GetOk("table_format"); ok { + tableBaseInfo.TableFormat = helper.String(v.(string)) + } + if v, ok := d.GetOk("user_alias"); ok { + tableBaseInfo.UserAlias = helper.String(v.(string)) + } + if v, ok := d.GetOk("user_sub_uin"); ok { + tableBaseInfo.UserSubUin = helper.String(v.(string)) + } + if v, ok := d.GetOk("db_govern_policy_is_disable"); ok { + tableBaseInfo.DbGovernPolicyIsDisable = helper.String(v.(string)) + } + + if v, ok := d.GetOk("govern_policy"); ok { + for _, item := range v.([]interface{}) { + governPolicyMap := item.(map[string]interface{}) + dataGovernPolicy := &dlc.DataGovernPolicy{} + if v, ok := governPolicyMap["rule_type"].(string); ok && v != "" { + dataGovernPolicy.RuleType = helper.String(v) + } + if v, ok := governPolicyMap["govern_engine"].(string); ok && v != "" { + dataGovernPolicy.GovernEngine = helper.String(v) + } + tableBaseInfo.GovernPolicy = dataGovernPolicy + } + } + + if v, ok := d.GetOk("smart_policy"); ok { + tableBaseInfo.SmartPolicy = buildSmartPolicy(v.([]interface{})) + } + + if v, ok := d.GetOk("primary_keys"); ok { + primaryKeys := make([]*string, 0, len(v.([]interface{}))) + for _, item := range v.([]interface{}) { + primaryKeys = append(primaryKeys, helper.String(item.(string))) + } + tableBaseInfo.PrimaryKeys = primaryKeys + } + + request.TableBaseInfo = tableBaseInfo + + if v, ok := d.GetOk("columns"); ok { + for _, item := range v.([]interface{}) { + columnMap := item.(map[string]interface{}) + tColumn := &dlc.TColumn{} + if v, ok := columnMap["name"].(string); ok && v != "" { + tColumn.Name = helper.String(v) + } + if v, ok := columnMap["type"].(string); ok && v != "" { + tColumn.Type = helper.String(v) + } + if v, ok := columnMap["comment"].(string); ok && v != "" { + tColumn.Comment = helper.String(v) + } + if v, ok := columnMap["default"].(string); ok && v != "" { + tColumn.Default = helper.String(v) + } + if v, ok := columnMap["not_null"].(bool); ok { + tColumn.NotNull = helper.Bool(v) + } + if v, ok := columnMap["precision"].(int); ok && v != 0 { + tColumn.Precision = helper.Int64(int64(v)) + } + if v, ok := columnMap["scale"].(int); ok && v != 0 { + tColumn.Scale = helper.Int64(int64(v)) + } + if v, ok := columnMap["position"].(int); ok && v != 0 { + tColumn.Position = helper.Int64(int64(v)) + } + if v, ok := columnMap["is_partition"].(bool); ok { + tColumn.IsPartition = helper.Bool(v) + } + request.Columns = append(request.Columns, tColumn) + } + } + + if v, ok := d.GetOk("partitions"); ok { + for _, item := range v.([]interface{}) { + partitionMap := item.(map[string]interface{}) + tPartition := &dlc.TPartition{} + if v, ok := partitionMap["name"].(string); ok && v != "" { + tPartition.Name = helper.String(v) + } + if v, ok := partitionMap["type"].(string); ok && v != "" { + tPartition.Type = helper.String(v) + } + if v, ok := partitionMap["comment"].(string); ok && v != "" { + tPartition.Comment = helper.String(v) + } + if v, ok := partitionMap["transform"].(string); ok && v != "" { + tPartition.Transform = helper.String(v) + } + if v, ok := partitionMap["transform_args"].([]interface{}); ok { + transformArgs := make([]*string, 0, len(v)) + for _, arg := range v { + transformArgs = append(transformArgs, helper.String(arg.(string))) + } + tPartition.TransformArgs = transformArgs + } + request.Partitions = append(request.Partitions, tPartition) + } + } + + if v, ok := d.GetOk("properties"); ok { + for _, item := range v.([]interface{}) { + propertyMap := item.(map[string]interface{}) + property := &dlc.Property{} + if v, ok := propertyMap["key"].(string); ok && v != "" { + property.Key = helper.String(v) + } + if v, ok := propertyMap["value"].(string); ok && v != "" { + property.Value = helper.String(v) + } + request.Properties = append(request.Properties, property) + } + } + + if v, ok := d.GetOk("upsert_keys"); ok { + upsertKeys := make([]*string, 0, len(v.([]interface{}))) + for _, item := range v.([]interface{}) { + upsertKeys = append(upsertKeys, helper.String(item.(string))) + } + request.UpsertKeys = upsertKeys + } + + reqErr := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseDlcClient().GenerateInternalTableWithContext(ctx, 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 == nil || result.Response == nil { + return resource.NonRetryableError(fmt.Errorf("Create dlc_internal_table failed, Response is nil.")) + } + + response = result + return nil + }) + + if reqErr != nil { + log.Printf("[CRITAL]%s create dlc_internal_table failed, reason:%+v", logId, reqErr) + return reqErr + } + + log.Printf("[CRUD]%s api[%s] dlc_internal_table response: %s, logId=%s, d.Id()=%s", logId, request.GetAction(), response.ToJsonString(), logId, d.Id()) + + if response.Response.Execution == nil { + return fmt.Errorf("dlc_internal_table create response Execution is nil") + } + + databaseName := "" + tableName := "" + if v, ok := d.GetOk("database_name"); ok { + databaseName = v.(string) + } + if v, ok := d.GetOk("table_name"); ok { + tableName = v.(string) + } + d.SetId(strings.Join([]string{databaseName, tableName}, tccommon.FILED_SP)) + + if response.Response.Execution != nil && response.Response.Execution.SQL != nil { + _ = d.Set("execution", response.Response.Execution.SQL) + } + if response.Response.IsTIcebergSql != nil { + _ = d.Set("is_t_iceberg_sql", response.Response.IsTIcebergSql) + } + + return resourceTencentCloudDlcInternalTableRead(d, meta) +} + +func resourceTencentCloudDlcInternalTableRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_dlc_internal_table.read")() + defer tccommon.InconsistentCheck(d, meta)() + + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + service = DlcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + ) + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + + databaseName := idSplit[0] + tableName := idSplit[1] + + datasourceConnectionName := "" + if v, ok := d.GetOk("datasource_connection_name"); ok { + datasourceConnectionName = v.(string) + } + + tableInfo, err := service.DescribeDlcInternalTableById(ctx, databaseName, tableName, datasourceConnectionName) + if err != nil { + return err + } + + if tableInfo == nil { + log.Printf("[CRUD] dlc_internal_table id=%s", d.Id()) + d.SetId("") + return nil + } + + if tableInfo.TableBaseInfo != nil { + if tableInfo.TableBaseInfo.DatabaseName != nil { + _ = d.Set("database_name", tableInfo.TableBaseInfo.DatabaseName) + } + if tableInfo.TableBaseInfo.TableName != nil { + _ = d.Set("table_name", tableInfo.TableBaseInfo.TableName) + } + if tableInfo.TableBaseInfo.DatasourceConnectionName != nil { + _ = d.Set("datasource_connection_name", tableInfo.TableBaseInfo.DatasourceConnectionName) + } + if tableInfo.TableBaseInfo.TableComment != nil { + _ = d.Set("table_comment", tableInfo.TableBaseInfo.TableComment) + } + if tableInfo.TableBaseInfo.Type != nil { + _ = d.Set("type", tableInfo.TableBaseInfo.Type) + } + if tableInfo.TableBaseInfo.TableFormat != nil { + _ = d.Set("table_format", tableInfo.TableBaseInfo.TableFormat) + } + if tableInfo.TableBaseInfo.UserAlias != nil { + _ = d.Set("user_alias", tableInfo.TableBaseInfo.UserAlias) + } + if tableInfo.TableBaseInfo.UserSubUin != nil { + _ = d.Set("user_sub_uin", tableInfo.TableBaseInfo.UserSubUin) + } + if tableInfo.TableBaseInfo.DbGovernPolicyIsDisable != nil { + _ = d.Set("db_govern_policy_is_disable", tableInfo.TableBaseInfo.DbGovernPolicyIsDisable) + } + + if tableInfo.TableBaseInfo.GovernPolicy != nil { + governPolicyList := make([]map[string]interface{}, 0, 1) + governPolicyMap := map[string]interface{}{} + if tableInfo.TableBaseInfo.GovernPolicy.RuleType != nil { + governPolicyMap["rule_type"] = tableInfo.TableBaseInfo.GovernPolicy.RuleType + } + if tableInfo.TableBaseInfo.GovernPolicy.GovernEngine != nil { + governPolicyMap["govern_engine"] = tableInfo.TableBaseInfo.GovernPolicy.GovernEngine + } + governPolicyList = append(governPolicyList, governPolicyMap) + _ = d.Set("govern_policy", governPolicyList) + } + + if tableInfo.TableBaseInfo.SmartPolicy != nil { + smartPolicyList := flattenSmartPolicy(tableInfo.TableBaseInfo.SmartPolicy) + if len(smartPolicyList) > 0 { + _ = d.Set("smart_policy", smartPolicyList) + } + } + + if tableInfo.TableBaseInfo.PrimaryKeys != nil { + primaryKeys := make([]string, 0, len(tableInfo.TableBaseInfo.PrimaryKeys)) + for _, pk := range tableInfo.TableBaseInfo.PrimaryKeys { + if pk != nil { + primaryKeys = append(primaryKeys, *pk) + } + } + _ = d.Set("primary_keys", primaryKeys) + } + } + + if tableInfo.Columns != nil { + columnsList := make([]map[string]interface{}, 0, len(tableInfo.Columns)) + for _, column := range tableInfo.Columns { + columnMap := map[string]interface{}{} + if column.Name != nil { + columnMap["name"] = column.Name + } + if column.Type != nil { + columnMap["type"] = column.Type + } + if column.Comment != nil { + columnMap["comment"] = column.Comment + } + if column.Precision != nil { + columnMap["precision"] = column.Precision + } + if column.Scale != nil { + columnMap["scale"] = column.Scale + } + if column.Nullable != nil { + columnMap["nullable"] = column.Nullable + } + if column.Position != nil { + columnMap["position"] = column.Position + } + if column.CreateTime != nil { + columnMap["create_time"] = column.CreateTime + } + if column.ModifiedTime != nil { + columnMap["modified_time"] = column.ModifiedTime + } + if column.IsPartition != nil { + columnMap["is_partition"] = column.IsPartition + } + if column.TypeText != nil { + columnMap["type_text"] = column.TypeText + } + if column.DataMaskStrategyInfo != nil { + dataMaskList := make([]map[string]interface{}, 0, 1) + dataMaskMap := map[string]interface{}{} + if column.DataMaskStrategyInfo.StrategyName != nil { + dataMaskMap["strategy_name"] = column.DataMaskStrategyInfo.StrategyName + } + if column.DataMaskStrategyInfo.StrategyType != nil { + dataMaskMap["strategy_type"] = column.DataMaskStrategyInfo.StrategyType + } + if column.DataMaskStrategyInfo.StrategyDesc != nil { + dataMaskMap["strategy_desc"] = column.DataMaskStrategyInfo.StrategyDesc + } + if column.DataMaskStrategyInfo.Users != nil { + dataMaskMap["users"] = column.DataMaskStrategyInfo.Users + } + if column.DataMaskStrategyInfo.StrategyId != nil { + dataMaskMap["strategy_id"] = column.DataMaskStrategyInfo.StrategyId + } + dataMaskList = append(dataMaskList, dataMaskMap) + columnMap["data_mask_strategy_info"] = dataMaskList + } + columnsList = append(columnsList, columnMap) + } + _ = d.Set("columns", columnsList) + } + + if tableInfo.Partitions != nil { + partitionsList := make([]map[string]interface{}, 0, len(tableInfo.Partitions)) + for _, partition := range tableInfo.Partitions { + partitionMap := map[string]interface{}{} + if partition.Name != nil { + partitionMap["name"] = partition.Name + } + if partition.Type != nil { + partitionMap["type"] = partition.Type + } + if partition.Comment != nil { + partitionMap["comment"] = partition.Comment + } + if partition.Transform != nil { + partitionMap["transform"] = partition.Transform + } + if partition.TransformArgs != nil { + transformArgs := make([]string, 0, len(partition.TransformArgs)) + for _, arg := range partition.TransformArgs { + if arg != nil { + transformArgs = append(transformArgs, *arg) + } + } + partitionMap["transform_args"] = transformArgs + } + if partition.CreateTime != nil { + partitionMap["create_time"] = partition.CreateTime + } + partitionsList = append(partitionsList, partitionMap) + } + _ = d.Set("partitions", partitionsList) + } + + if tableInfo.Location != nil { + _ = d.Set("location", tableInfo.Location) + } + if tableInfo.Properties != nil { + propertiesList := make([]map[string]interface{}, 0, len(tableInfo.Properties)) + for _, property := range tableInfo.Properties { + propertyMap := map[string]interface{}{} + if property.Key != nil { + propertyMap["key"] = property.Key + } + if property.Value != nil { + propertyMap["value"] = property.Value + } + propertiesList = append(propertiesList, propertyMap) + } + _ = d.Set("properties", propertiesList) + } + if tableInfo.ModifiedTime != nil { + _ = d.Set("modified_time", tableInfo.ModifiedTime) + } + if tableInfo.CreateTime != nil { + _ = d.Set("create_time", tableInfo.CreateTime) + } + if tableInfo.InputFormat != nil { + _ = d.Set("input_format", tableInfo.InputFormat) + } + if tableInfo.StorageSize != nil { + _ = d.Set("storage_size", tableInfo.StorageSize) + } + if tableInfo.RecordCount != nil { + _ = d.Set("record_count", tableInfo.RecordCount) + } + if tableInfo.MapMaterializedViewName != nil { + _ = d.Set("map_materialized_view_name", tableInfo.MapMaterializedViewName) + } + if tableInfo.HeatValue != nil { + _ = d.Set("heat_value", tableInfo.HeatValue) + } + if tableInfo.InputFormatShort != nil { + _ = d.Set("input_format_short", tableInfo.InputFormatShort) + } + + return nil +} + +func resourceTencentCloudDlcInternalTableUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_dlc_internal_table.update")() + defer tccommon.InconsistentCheck(d, meta)() + + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + ) + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + + databaseName := idSplit[0] + tableName := idSplit[1] + + needChange := false + mutableArgs := []string{"datasource_connection_name", "table_comment", "type", "table_format", "user_alias", "user_sub_uin", "db_govern_policy_is_disable", "govern_policy", "smart_policy"} + for _, v := range mutableArgs { + if d.HasChange(v) { + needChange = true + break + } + } + + if needChange { + request := dlc.NewAlterTableCommentRequest() + tableBaseInfo := &dlc.TableBaseInfo{} + tableBaseInfo.DatabaseName = helper.String(databaseName) + tableBaseInfo.TableName = helper.String(tableName) + + if v, ok := d.GetOk("datasource_connection_name"); ok { + tableBaseInfo.DatasourceConnectionName = helper.String(v.(string)) + } + if v, ok := d.GetOk("table_comment"); ok { + tableBaseInfo.TableComment = helper.String(v.(string)) + } + if v, ok := d.GetOk("type"); ok { + tableBaseInfo.Type = helper.String(v.(string)) + } + if v, ok := d.GetOk("table_format"); ok { + tableBaseInfo.TableFormat = helper.String(v.(string)) + } + if v, ok := d.GetOk("user_alias"); ok { + tableBaseInfo.UserAlias = helper.String(v.(string)) + } + if v, ok := d.GetOk("user_sub_uin"); ok { + tableBaseInfo.UserSubUin = helper.String(v.(string)) + } + if v, ok := d.GetOk("db_govern_policy_is_disable"); ok { + tableBaseInfo.DbGovernPolicyIsDisable = helper.String(v.(string)) + } + + if v, ok := d.GetOk("govern_policy"); ok { + for _, item := range v.([]interface{}) { + governPolicyMap := item.(map[string]interface{}) + dataGovernPolicy := &dlc.DataGovernPolicy{} + if v, ok := governPolicyMap["rule_type"].(string); ok && v != "" { + dataGovernPolicy.RuleType = helper.String(v) + } + if v, ok := governPolicyMap["govern_engine"].(string); ok && v != "" { + dataGovernPolicy.GovernEngine = helper.String(v) + } + tableBaseInfo.GovernPolicy = dataGovernPolicy + } + } + + if v, ok := d.GetOk("smart_policy"); ok { + tableBaseInfo.SmartPolicy = buildSmartPolicy(v.([]interface{})) + } + + request.TableBaseInfo = tableBaseInfo + + reqErr := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseDlcClient().AlterTableCommentWithContext(ctx, 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 == nil || result.Response == nil { + return resource.NonRetryableError(fmt.Errorf("Update dlc_internal_table failed, Response is nil.")) + } + + return nil + }) + + if reqErr != nil { + log.Printf("[CRITAL]%s update dlc_internal_table failed, reason:%+v", logId, reqErr) + return reqErr + } + } + + return resourceTencentCloudDlcInternalTableRead(d, meta) +} + +func resourceTencentCloudDlcInternalTableDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_dlc_internal_table.delete")() + defer tccommon.InconsistentCheck(d, meta)() + + var ( + logId = tccommon.GetLogId(tccommon.ContextNil) + ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + ) + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + + databaseName := idSplit[0] + tableName := idSplit[1] + + request := dlc.NewDeleteTableRequest() + tableBaseInfo := &dlc.TableBaseInfo{} + tableBaseInfo.DatabaseName = helper.String(databaseName) + tableBaseInfo.TableName = helper.String(tableName) + if v, ok := d.GetOk("datasource_connection_name"); ok { + tableBaseInfo.DatasourceConnectionName = helper.String(v.(string)) + } + request.TableBaseInfo = tableBaseInfo + + reqErr := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseDlcClient().DeleteTableWithContext(ctx, 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 == nil || result.Response == nil { + return resource.NonRetryableError(fmt.Errorf("Delete dlc_internal_table failed, Response is nil.")) + } + + return nil + }) + + if reqErr != nil { + log.Printf("[CRITAL]%s delete dlc_internal_table failed, reason:%+v", logId, reqErr) + return reqErr + } + + return nil +} + +func buildSmartPolicy(smartPolicyList []interface{}) *dlc.SmartPolicy { + if len(smartPolicyList) < 1 { + return nil + } + smartPolicyMap := smartPolicyList[0].(map[string]interface{}) + smartPolicy := &dlc.SmartPolicy{} + + if v, ok := smartPolicyMap["base_info"].([]interface{}); ok && len(v) > 0 { + baseInfoMap := v[0].(map[string]interface{}) + baseInfo := &dlc.SmartPolicyBaseInfo{} + if v, ok := baseInfoMap["uin"].(string); ok && v != "" { + baseInfo.Uin = helper.String(v) + } + if v, ok := baseInfoMap["policy_type"].(string); ok && v != "" { + baseInfo.PolicyType = helper.String(v) + } + if v, ok := baseInfoMap["catalog"].(string); ok && v != "" { + baseInfo.Catalog = helper.String(v) + } + if v, ok := baseInfoMap["database"].(string); ok && v != "" { + baseInfo.Database = helper.String(v) + } + if v, ok := baseInfoMap["table"].(string); ok && v != "" { + baseInfo.Table = helper.String(v) + } + if v, ok := baseInfoMap["app_id"].(string); ok && v != "" { + baseInfo.AppId = helper.String(v) + } + smartPolicy.BaseInfo = baseInfo + } + + if v, ok := smartPolicyMap["policy"].([]interface{}); ok && len(v) > 0 { + policyMap := v[0].(map[string]interface{}) + policy := &dlc.SmartOptimizerPolicy{} + + if v, ok := policyMap["inherit"].(string); ok && v != "" { + policy.Inherit = helper.String(v) + } + + if v, ok := policyMap["resources"].([]interface{}); ok && len(v) > 0 { + resources := make([]*dlc.ResourceInfo, 0, len(v)) + for _, resItem := range v { + resMap := resItem.(map[string]interface{}) + resourceInfo := &dlc.ResourceInfo{} + if v, ok := resMap["attribution_type"].(string); ok && v != "" { + resourceInfo.AttributionType = helper.String(v) + } + if v, ok := resMap["resource_type"].(string); ok && v != "" { + resourceInfo.ResourceType = helper.String(v) + } + if v, ok := resMap["name"].(string); ok && v != "" { + resourceInfo.Name = helper.String(v) + } + if v, ok := resMap["instance"].(string); ok && v != "" { + resourceInfo.Instance = helper.String(v) + } + if v, ok := resMap["status"].(int); ok && v != 0 { + resourceInfo.Status = helper.Int64(int64(v)) + } + if v, ok := resMap["resource_group_name"].(string); ok && v != "" { + resourceInfo.ResourceGroupName = helper.String(v) + } + if v, ok := resMap["favor"].([]interface{}); ok && len(v) > 0 { + favorList := make([]*dlc.FavorInfo, 0, len(v)) + for _, favorItem := range v { + favorMap := favorItem.(map[string]interface{}) + favorInfo := &dlc.FavorInfo{} + if v, ok := favorMap["priority"].(int); ok { + favorInfo.Priority = helper.Int64(int64(v)) + } + if v, ok := favorMap["catalog"].(string); ok && v != "" { + favorInfo.Catalog = helper.String(v) + } + if v, ok := favorMap["data_base"].(string); ok && v != "" { + favorInfo.DataBase = helper.String(v) + } + if v, ok := favorMap["table"].(string); ok && v != "" { + favorInfo.Table = helper.String(v) + } + favorList = append(favorList, favorInfo) + } + resourceInfo.Favor = favorList + } + if v, ok := resMap["resource_conf"].([]interface{}); ok && len(v) > 0 { + resourceConfMap := v[0].(map[string]interface{}) + resourceConf := &dlc.ResourceConf{} + if v, ok := resourceConfMap["parallelism"].(int); ok && v != 0 { + resourceConf.Parallelism = helper.Int64(int64(v)) + } + resourceInfo.ResourceConf = resourceConf + } + resources = append(resources, resourceInfo) + } + policy.Resources = resources + } + + if v, ok := policyMap["written"].([]interface{}); ok && len(v) > 0 { + writtenMap := v[0].(map[string]interface{}) + written := &dlc.SmartOptimizerWrittenPolicy{} + if v, ok := writtenMap["written_enable"].(string); ok && v != "" { + written.WrittenEnable = helper.String(v) + } + if v, ok := writtenMap["advance_policy"].([]interface{}); ok && len(v) > 0 { + advancePolicyMap := v[0].(map[string]interface{}) + advancePolicy := &dlc.WrittenAdvancePolicy{} + if v, ok := advancePolicyMap["compact_enable"].(string); ok && v != "" { + advancePolicy.CompactEnable = helper.String(v) + } + if v, ok := advancePolicyMap["delete_enable"].(string); ok && v != "" { + advancePolicy.DeleteEnable = helper.String(v) + } + if v, ok := advancePolicyMap["min_input_files"].(int); ok && v != 0 { + advancePolicy.MinInputFiles = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["target_file_size_bytes"].(int); ok && v != 0 { + advancePolicy.TargetFileSizeBytes = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["retain_last"].(int); ok && v != 0 { + advancePolicy.RetainLast = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["before_days"].(int); ok && v != 0 { + advancePolicy.BeforeDays = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["expired_snapshots_interval_min"].(int); ok && v != 0 { + advancePolicy.ExpiredSnapshotsIntervalMin = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["remove_orphan_interval_min"].(int); ok && v != 0 { + advancePolicy.RemoveOrphanIntervalMin = helper.Int64(int64(v)) + } + if v, ok := advancePolicyMap["cow_compact_enable"].(string); ok && v != "" { + advancePolicy.CowCompactEnable = helper.String(v) + } + if v, ok := advancePolicyMap["compact_strategy"].(string); ok && v != "" { + advancePolicy.CompactStrategy = helper.String(v) + } + if v, ok := advancePolicyMap["sort_orders"].([]interface{}); ok && len(v) > 0 { + sortOrders := make([]*dlc.SortOrder, 0, len(v)) + for _, sortItem := range v { + sortMap := sortItem.(map[string]interface{}) + sortOrder := &dlc.SortOrder{} + if v, ok := sortMap["column"].(string); ok && v != "" { + sortOrder.Column = helper.String(v) + } + if v, ok := sortMap["sort_direction"].(string); ok && v != "" { + sortOrder.SortDirection = helper.String(v) + } + if v, ok := sortMap["null_order"].(string); ok && v != "" { + sortOrder.NullOrder = helper.String(v) + } + sortOrders = append(sortOrders, sortOrder) + } + advancePolicy.SortOrders = sortOrders + } + written.AdvancePolicy = advancePolicy + } + policy.Written = written + } + + if v, ok := policyMap["lifecycle"].([]interface{}); ok && len(v) > 0 { + lifecycleMap := v[0].(map[string]interface{}) + lifecycle := &dlc.SmartOptimizerLifecyclePolicy{} + if v, ok := lifecycleMap["lifecycle_enable"].(string); ok && v != "" { + lifecycle.LifecycleEnable = helper.String(v) + } + if v, ok := lifecycleMap["expiration"].(int); ok && v != 0 { + lifecycle.Expiration = helper.Int64(int64(v)) + } + if v, ok := lifecycleMap["drop_table"].(bool); ok { + lifecycle.DropTable = helper.Bool(v) + } + if v, ok := lifecycleMap["expired_field"].(string); ok && v != "" { + lifecycle.ExpiredField = helper.String(v) + } + if v, ok := lifecycleMap["expired_field_format"].(string); ok && v != "" { + lifecycle.ExpiredFieldFormat = helper.String(v) + } + policy.Lifecycle = lifecycle + } + + if v, ok := policyMap["index"].([]interface{}); ok && len(v) > 0 { + indexMap := v[0].(map[string]interface{}) + index := &dlc.SmartOptimizerIndexPolicy{} + if v, ok := indexMap["index_enable"].(string); ok && v != "" { + index.IndexEnable = helper.String(v) + } + policy.Index = index + } + + if v, ok := policyMap["change_table"].([]interface{}); ok && len(v) > 0 { + changeTableMap := v[0].(map[string]interface{}) + changeTable := &dlc.SmartOptimizerChangeTablePolicy{} + if v, ok := changeTableMap["data_retention_time"].(int); ok && v != 0 { + changeTable.DataRetentionTime = helper.Int64(int64(v)) + } + policy.ChangeTable = changeTable + } + + if v, ok := policyMap["table_expiration"].([]interface{}); ok && len(v) > 0 { + tableExpirationMap := v[0].(map[string]interface{}) + tableExpiration := &dlc.TableExpirationPolicy{} + if v, ok := tableExpirationMap["enabled"].(bool); ok { + tableExpiration.Enabled = helper.Bool(v) + } + if v, ok := tableExpirationMap["expiration"].(int); ok { + tableExpiration.Expiration = helper.Uint64(uint64(v)) + } + policy.TableExpiration = tableExpiration + } + + smartPolicy.Policy = policy + } + + return smartPolicy +} + +func flattenSmartPolicy(smartPolicy *dlc.SmartPolicy) []map[string]interface{} { + smartPolicyList := make([]map[string]interface{}, 0, 1) + smartPolicyMap := map[string]interface{}{} + + if smartPolicy.BaseInfo != nil { + baseInfoList := make([]map[string]interface{}, 0, 1) + baseInfoMap := map[string]interface{}{} + if smartPolicy.BaseInfo.Uin != nil { + baseInfoMap["uin"] = smartPolicy.BaseInfo.Uin + } + if smartPolicy.BaseInfo.PolicyType != nil { + baseInfoMap["policy_type"] = smartPolicy.BaseInfo.PolicyType + } + if smartPolicy.BaseInfo.Catalog != nil { + baseInfoMap["catalog"] = smartPolicy.BaseInfo.Catalog + } + if smartPolicy.BaseInfo.Database != nil { + baseInfoMap["database"] = smartPolicy.BaseInfo.Database + } + if smartPolicy.BaseInfo.Table != nil { + baseInfoMap["table"] = smartPolicy.BaseInfo.Table + } + if smartPolicy.BaseInfo.AppId != nil { + baseInfoMap["app_id"] = smartPolicy.BaseInfo.AppId + } + baseInfoList = append(baseInfoList, baseInfoMap) + smartPolicyMap["base_info"] = baseInfoList + } + + if smartPolicy.Policy != nil { + policyList := make([]map[string]interface{}, 0, 1) + policyMap := map[string]interface{}{} + if smartPolicy.Policy.Inherit != nil { + policyMap["inherit"] = smartPolicy.Policy.Inherit + } + + if smartPolicy.Policy.Resources != nil { + resourcesList := make([]map[string]interface{}, 0, len(smartPolicy.Policy.Resources)) + for _, res := range smartPolicy.Policy.Resources { + resMap := map[string]interface{}{} + if res.AttributionType != nil { + resMap["attribution_type"] = res.AttributionType + } + if res.ResourceType != nil { + resMap["resource_type"] = res.ResourceType + } + if res.Name != nil { + resMap["name"] = res.Name + } + if res.Instance != nil { + resMap["instance"] = res.Instance + } + if res.Status != nil { + resMap["status"] = res.Status + } + if res.ResourceGroupName != nil { + resMap["resource_group_name"] = res.ResourceGroupName + } + if res.Favor != nil { + favorList := make([]map[string]interface{}, 0, len(res.Favor)) + for _, favor := range res.Favor { + favorMap := map[string]interface{}{} + if favor.Priority != nil { + favorMap["priority"] = favor.Priority + } + if favor.Catalog != nil { + favorMap["catalog"] = favor.Catalog + } + if favor.DataBase != nil { + favorMap["data_base"] = favor.DataBase + } + if favor.Table != nil { + favorMap["table"] = favor.Table + } + favorList = append(favorList, favorMap) + } + resMap["favor"] = favorList + } + if res.ResourceConf != nil { + resourceConfList := make([]map[string]interface{}, 0, 1) + resourceConfMap := map[string]interface{}{} + if res.ResourceConf.Parallelism != nil { + resourceConfMap["parallelism"] = res.ResourceConf.Parallelism + } + resourceConfList = append(resourceConfList, resourceConfMap) + resMap["resource_conf"] = resourceConfList + } + resourcesList = append(resourcesList, resMap) + } + policyMap["resources"] = resourcesList + } + + if smartPolicy.Policy.Written != nil { + writtenList := make([]map[string]interface{}, 0, 1) + writtenMap := map[string]interface{}{} + if smartPolicy.Policy.Written.WrittenEnable != nil { + writtenMap["written_enable"] = smartPolicy.Policy.Written.WrittenEnable + } + if smartPolicy.Policy.Written.AdvancePolicy != nil { + advancePolicyList := make([]map[string]interface{}, 0, 1) + advancePolicyMap := map[string]interface{}{} + ap := smartPolicy.Policy.Written.AdvancePolicy + if ap.CompactEnable != nil { + advancePolicyMap["compact_enable"] = ap.CompactEnable + } + if ap.DeleteEnable != nil { + advancePolicyMap["delete_enable"] = ap.DeleteEnable + } + if ap.MinInputFiles != nil { + advancePolicyMap["min_input_files"] = ap.MinInputFiles + } + if ap.TargetFileSizeBytes != nil { + advancePolicyMap["target_file_size_bytes"] = ap.TargetFileSizeBytes + } + if ap.RetainLast != nil { + advancePolicyMap["retain_last"] = ap.RetainLast + } + if ap.BeforeDays != nil { + advancePolicyMap["before_days"] = ap.BeforeDays + } + if ap.ExpiredSnapshotsIntervalMin != nil { + advancePolicyMap["expired_snapshots_interval_min"] = ap.ExpiredSnapshotsIntervalMin + } + if ap.RemoveOrphanIntervalMin != nil { + advancePolicyMap["remove_orphan_interval_min"] = ap.RemoveOrphanIntervalMin + } + if ap.CowCompactEnable != nil { + advancePolicyMap["cow_compact_enable"] = ap.CowCompactEnable + } + if ap.CompactStrategy != nil { + advancePolicyMap["compact_strategy"] = ap.CompactStrategy + } + if ap.SortOrders != nil { + sortOrdersList := make([]map[string]interface{}, 0, len(ap.SortOrders)) + for _, sortOrder := range ap.SortOrders { + sortOrderMap := map[string]interface{}{} + if sortOrder.Column != nil { + sortOrderMap["column"] = sortOrder.Column + } + if sortOrder.SortDirection != nil { + sortOrderMap["sort_direction"] = sortOrder.SortDirection + } + if sortOrder.NullOrder != nil { + sortOrderMap["null_order"] = sortOrder.NullOrder + } + sortOrdersList = append(sortOrdersList, sortOrderMap) + } + advancePolicyMap["sort_orders"] = sortOrdersList + } + advancePolicyList = append(advancePolicyList, advancePolicyMap) + writtenMap["advance_policy"] = advancePolicyList + } + writtenList = append(writtenList, writtenMap) + policyMap["written"] = writtenList + } + + if smartPolicy.Policy.Lifecycle != nil { + lifecycleList := make([]map[string]interface{}, 0, 1) + lifecycleMap := map[string]interface{}{} + if smartPolicy.Policy.Lifecycle.LifecycleEnable != nil { + lifecycleMap["lifecycle_enable"] = smartPolicy.Policy.Lifecycle.LifecycleEnable + } + if smartPolicy.Policy.Lifecycle.Expiration != nil { + lifecycleMap["expiration"] = smartPolicy.Policy.Lifecycle.Expiration + } + if smartPolicy.Policy.Lifecycle.DropTable != nil { + lifecycleMap["drop_table"] = smartPolicy.Policy.Lifecycle.DropTable + } + if smartPolicy.Policy.Lifecycle.ExpiredField != nil { + lifecycleMap["expired_field"] = smartPolicy.Policy.Lifecycle.ExpiredField + } + if smartPolicy.Policy.Lifecycle.ExpiredFieldFormat != nil { + lifecycleMap["expired_field_format"] = smartPolicy.Policy.Lifecycle.ExpiredFieldFormat + } + lifecycleList = append(lifecycleList, lifecycleMap) + policyMap["lifecycle"] = lifecycleList + } + + if smartPolicy.Policy.Index != nil { + indexList := make([]map[string]interface{}, 0, 1) + indexMap := map[string]interface{}{} + if smartPolicy.Policy.Index.IndexEnable != nil { + indexMap["index_enable"] = smartPolicy.Policy.Index.IndexEnable + } + indexList = append(indexList, indexMap) + policyMap["index"] = indexList + } + + if smartPolicy.Policy.ChangeTable != nil { + changeTableList := make([]map[string]interface{}, 0, 1) + changeTableMap := map[string]interface{}{} + if smartPolicy.Policy.ChangeTable.DataRetentionTime != nil { + changeTableMap["data_retention_time"] = smartPolicy.Policy.ChangeTable.DataRetentionTime + } + changeTableList = append(changeTableList, changeTableMap) + policyMap["change_table"] = changeTableList + } + + if smartPolicy.Policy.TableExpiration != nil { + tableExpirationList := make([]map[string]interface{}, 0, 1) + tableExpirationMap := map[string]interface{}{} + if smartPolicy.Policy.TableExpiration.Enabled != nil { + tableExpirationMap["enabled"] = smartPolicy.Policy.TableExpiration.Enabled + } + if smartPolicy.Policy.TableExpiration.Expiration != nil { + tableExpirationMap["expiration"] = smartPolicy.Policy.TableExpiration.Expiration + } + tableExpirationList = append(tableExpirationList, tableExpirationMap) + policyMap["table_expiration"] = tableExpirationList + } + + policyList = append(policyList, policyMap) + smartPolicyMap["policy"] = policyList + } + + smartPolicyList = append(smartPolicyList, smartPolicyMap) + return smartPolicyList +} diff --git a/tencentcloud/services/dlc/resource_tc_dlc_internal_table.md b/tencentcloud/services/dlc/resource_tc_dlc_internal_table.md new file mode 100644 index 0000000000..36e823c558 --- /dev/null +++ b/tencentcloud/services/dlc/resource_tc_dlc_internal_table.md @@ -0,0 +1,113 @@ +Provides a resource to create a DLC internal table + +Example Usage + +Create a basic internal table with columns + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_table" + table_comment = "terraform test table" + type = "TABLE" + table_format = "hive" + columns { + name = "id" + type = "bigint" + comment = "id column" + } + columns { + name = "name" + type = "string" + comment = "name column" + } + properties { + key = "format" + value = "TEXTFILE" + } +} +``` + +Create an Iceberg internal table with smart policy + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_iceberg_table" + table_comment = "terraform iceberg test table" + type = "TABLE" + table_format = "iceberg" + primary_keys = ["id"] + columns { + name = "id" + type = "bigint" + comment = "id column" + not_null = true + } + columns { + name = "name" + type = "string" + comment = "name column" + } + smart_policy { + base_info { + uin = "100012345678" + policy_type = "Table" + catalog = "DataLakeCatalog" + database = "tf_example_database" + table = "tf_example_iceberg_table" + app_id = "1300123456" + } + policy { + inherit = "false" + lifecycle { + lifecycle_enable = "enable" + expiration = 30 + expired_field = "dt" + expired_field_format = "yyyy-MM-dd" + } + table_expiration { + enabled = true + expiration = 90 + } + } + } +} +``` + +Create a table with partitions + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_partitioned_table" + table_comment = "terraform partitioned test table" + type = "TABLE" + table_format = "hive" + columns { + name = "id" + type = "bigint" + } + columns { + name = "name" + type = "string" + } + partitions { + name = "dt" + type = "string" + comment = "date partition" + } + properties { + key = "format" + value = "PARQUET" + } +} +``` + +Import + +DLC internal table can be imported using the composite id (`database_name#table_name`), e.g. + +``` +terraform import tencentcloud_dlc_internal_table.example tf_example_database#tf_example_table +``` diff --git a/tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go b/tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go new file mode 100644 index 0000000000..8b831a16eb --- /dev/null +++ b/tencentcloud/services/dlc/resource_tc_dlc_internal_table_test.go @@ -0,0 +1,517 @@ +package dlc_test + +import ( + "context" + "fmt" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/stretchr/testify/assert" + dlc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125" + + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/connectivity" + svcdlc "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/dlc" +) + +type mockMetaDlcInternalTable struct { + client *connectivity.TencentCloudClient +} + +func (m *mockMetaDlcInternalTable) GetAPIV3Conn() *connectivity.TencentCloudClient { + return m.client +} + +var _ tccommon.ProviderMeta = &mockMetaDlcInternalTable{} + +func newMockMetaDlcInternalTable() *mockMetaDlcInternalTable { + return &mockMetaDlcInternalTable{client: &connectivity.TencentCloudClient{}} +} + +func ptrStrDlcIt(s string) *string { + return &s +} + +func ptrBoolDlcIt(b bool) *bool { + return &b +} + +func ptrInt64DlcIt(i int64) *int64 { + return &i +} + +// go test ./tencentcloud/services/dlc/ -run "TestDlcInternalTable" -v -count=1 -gcflags="all=-l" + +// TestDlcInternalTable_CreateThenRead tests create followed by read +func TestDlcInternalTable_CreateThenRead(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + sqlText := "CREATE TABLE tf_example_db.tf_example_table (id bigint, name string)" + patches.ApplyMethodFunc(dlcClient, "GenerateInternalTableWithContext", func(_ context.Context, request *dlc.GenerateInternalTableRequest) (*dlc.GenerateInternalTableResponse, error) { + assert.NotNil(t, request.TableBaseInfo) + assert.Equal(t, "tf_example_db", *request.TableBaseInfo.DatabaseName) + assert.Equal(t, "tf_example_table", *request.TableBaseInfo.TableName) + assert.Len(t, request.Columns, 2) + assert.Equal(t, "id", *request.Columns[0].Name) + assert.Equal(t, "bigint", *request.Columns[0].Type) + + resp := dlc.NewGenerateInternalTableResponse() + resp.Response = &dlc.GenerateInternalTableResponseParams{ + Execution: &dlc.Execution{ + SQL: ptrStrDlcIt(sqlText), + }, + IsTIcebergSql: ptrBoolDlcIt(false), + RequestId: ptrStrDlcIt("fake-request-id-create"), + } + return resp, nil + }) + + patches.ApplyMethodFunc(dlcClient, "DescribeTableWithContext", func(_ context.Context, request *dlc.DescribeTableRequest) (*dlc.DescribeTableResponse, error) { + assert.Equal(t, "tf_example_db", *request.DatabaseName) + assert.Equal(t, "tf_example_table", *request.TableName) + + resp := dlc.NewDescribeTableResponse() + resp.Response = &dlc.DescribeTableResponseParams{ + Table: &dlc.TableResponseInfo{ + TableBaseInfo: &dlc.TableBaseInfo{ + DatabaseName: ptrStrDlcIt("tf_example_db"), + TableName: ptrStrDlcIt("tf_example_table"), + TableComment: ptrStrDlcIt("test table"), + Type: ptrStrDlcIt("TABLE"), + TableFormat: ptrStrDlcIt("hive"), + }, + Columns: []*dlc.Column{ + { + Name: ptrStrDlcIt("id"), + Type: ptrStrDlcIt("bigint"), + Comment: ptrStrDlcIt("id column"), + }, + { + Name: ptrStrDlcIt("name"), + Type: ptrStrDlcIt("string"), + Comment: ptrStrDlcIt("name column"), + }, + }, + Location: ptrStrDlcIt("cosn://tf-bucket/path"), + CreateTime: ptrStrDlcIt("1700000000000"), + ModifiedTime: ptrStrDlcIt("1700000001000"), + InputFormat: ptrStrDlcIt("org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat"), + StorageSize: ptrInt64DlcIt(1024), + RecordCount: ptrInt64DlcIt(100), + InputFormatShort: ptrStrDlcIt("Parquet"), + }, + RequestId: ptrStrDlcIt("fake-request-id-read"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "table_comment": "test table", + "type": "TABLE", + "table_format": "hive", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + "comment": "id column", + }, + map[string]interface{}{ + "name": "name", + "type": "string", + "comment": "name column", + }, + }, + }) + + err := res.Create(d, meta) + assert.NoError(t, err) + assert.Equal(t, "tf_example_db#tf_example_table", d.Id()) + assert.Equal(t, sqlText, d.Get("execution").(string)) + assert.Equal(t, false, d.Get("is_t_iceberg_sql").(bool)) + assert.Equal(t, "cosn://tf-bucket/path", d.Get("location").(string)) + assert.Equal(t, "1700000000000", d.Get("create_time").(string)) + assert.Equal(t, "1700000001000", d.Get("modified_time").(string)) + assert.Equal(t, 1024, d.Get("storage_size").(int)) + assert.Equal(t, 100, d.Get("record_count").(int)) +} + +// TestDlcInternalTable_Update tests update of mutable fields +func TestDlcInternalTable_Update(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + var capturedRequest *dlc.AlterTableCommentRequest + patches.ApplyMethodFunc(dlcClient, "AlterTableCommentWithContext", func(_ context.Context, request *dlc.AlterTableCommentRequest) (*dlc.AlterTableCommentResponse, error) { + capturedRequest = request + resp := dlc.NewAlterTableCommentResponse() + resp.Response = &dlc.AlterTableCommentResponseParams{ + RequestId: ptrStrDlcIt("fake-request-id-update"), + } + return resp, nil + }) + + patches.ApplyMethodFunc(dlcClient, "DescribeTableWithContext", func(_ context.Context, request *dlc.DescribeTableRequest) (*dlc.DescribeTableResponse, error) { + resp := dlc.NewDescribeTableResponse() + resp.Response = &dlc.DescribeTableResponseParams{ + Table: &dlc.TableResponseInfo{ + TableBaseInfo: &dlc.TableBaseInfo{ + DatabaseName: ptrStrDlcIt("tf_example_db"), + TableName: ptrStrDlcIt("tf_example_table"), + TableComment: ptrStrDlcIt("updated comment"), + Type: ptrStrDlcIt("TABLE"), + TableFormat: ptrStrDlcIt("hive"), + }, + Columns: []*dlc.Column{ + { + Name: ptrStrDlcIt("id"), + Type: ptrStrDlcIt("bigint"), + }, + }, + }, + RequestId: ptrStrDlcIt("fake-request-id-read"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "table_comment": "updated comment", + "type": "TABLE", + "table_format": "hive", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + }) + d.SetId("tf_example_db#tf_example_table") + + err := res.Update(d, meta) + assert.NoError(t, err) + assert.NotNil(t, capturedRequest) + assert.NotNil(t, capturedRequest.TableBaseInfo) + assert.Equal(t, "updated comment", *capturedRequest.TableBaseInfo.TableComment) + assert.Equal(t, "tf_example_db", d.Id()) + assert.Equal(t, "updated comment", d.Get("table_comment").(string)) +} + +// TestDlcInternalTable_Delete tests delete +func TestDlcInternalTable_Delete(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + var capturedRequest *dlc.DeleteTableRequest + patches.ApplyMethodFunc(dlcClient, "DeleteTableWithContext", func(_ context.Context, request *dlc.DeleteTableRequest) (*dlc.DeleteTableResponse, error) { + capturedRequest = request + resp := dlc.NewDeleteTableResponse() + resp.Response = &dlc.DeleteTableResponseParams{ + RequestId: ptrStrDlcIt("fake-request-id-delete"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + }) + d.SetId("tf_example_db#tf_example_table") + + err := res.Delete(d, meta) + assert.NoError(t, err) + assert.NotNil(t, capturedRequest) + assert.NotNil(t, capturedRequest.TableBaseInfo) + assert.Equal(t, "tf_example_db", *capturedRequest.TableBaseInfo.DatabaseName) + assert.Equal(t, "tf_example_table", *capturedRequest.TableBaseInfo.TableName) +} + +// TestDlcInternalTable_EmptyCreateResult tests that empty create result returns error +func TestDlcInternalTable_EmptyCreateResult(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + patches.ApplyMethodFunc(dlcClient, "GenerateInternalTableWithContext", func(_ context.Context, request *dlc.GenerateInternalTableRequest) (*dlc.GenerateInternalTableResponse, error) { + resp := dlc.NewGenerateInternalTableResponse() + resp.Response = &dlc.GenerateInternalTableResponseParams{ + RequestId: ptrStrDlcIt("fake-request-id"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + }) + + err := res.Create(d, meta) + assert.Error(t, err) + assert.Contains(t, err.Error(), "Execution is nil") +} + +// TestDlcInternalTable_TableNotFound tests that read clears id when table not found +func TestDlcInternalTable_TableNotFound(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + patches.ApplyMethodFunc(dlcClient, "DescribeTableWithContext", func(_ context.Context, request *dlc.DescribeTableRequest) (*dlc.DescribeTableResponse, error) { + resp := dlc.NewDescribeTableResponse() + resp.Response = &dlc.DescribeTableResponseParams{ + RequestId: ptrStrDlcIt("fake-request-id"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + }) + d.SetId("tf_example_db#tf_example_table") + + err := res.Read(d, meta) + assert.NoError(t, err) + assert.Empty(t, d.Id()) +} + +// TestDlcInternalTable_Schema validates schema definition +func TestDlcInternalTable_Schema(t *testing.T) { + res := svcdlc.ResourceTencentCloudDlcInternalTable() + + assert.NotNil(t, res) + assert.NotNil(t, res.Create) + assert.NotNil(t, res.Read) + assert.NotNil(t, res.Update) + assert.NotNil(t, res.Delete) + assert.NotNil(t, res.Importer) + + assert.Contains(t, res.Schema, "database_name") + assert.Contains(t, res.Schema, "table_name") + assert.Contains(t, res.Schema, "datasource_connection_name") + assert.Contains(t, res.Schema, "table_comment") + assert.Contains(t, res.Schema, "type") + assert.Contains(t, res.Schema, "table_format") + assert.Contains(t, res.Schema, "user_alias") + assert.Contains(t, res.Schema, "user_sub_uin") + assert.Contains(t, res.Schema, "db_govern_policy_is_disable") + assert.Contains(t, res.Schema, "govern_policy") + assert.Contains(t, res.Schema, "smart_policy") + assert.Contains(t, res.Schema, "primary_keys") + assert.Contains(t, res.Schema, "columns") + assert.Contains(t, res.Schema, "partitions") + assert.Contains(t, res.Schema, "properties") + assert.Contains(t, res.Schema, "upsert_keys") + + assert.Contains(t, res.Schema, "location") + assert.Contains(t, res.Schema, "modified_time") + assert.Contains(t, res.Schema, "create_time") + assert.Contains(t, res.Schema, "input_format") + assert.Contains(t, res.Schema, "storage_size") + assert.Contains(t, res.Schema, "record_count") + assert.Contains(t, res.Schema, "map_materialized_view_name") + assert.Contains(t, res.Schema, "heat_value") + assert.Contains(t, res.Schema, "input_format_short") + assert.Contains(t, res.Schema, "execution") + assert.Contains(t, res.Schema, "is_t_iceberg_sql") + + databaseName := res.Schema["database_name"] + assert.True(t, databaseName.Required) + assert.True(t, databaseName.ForceNew) + + tableName := res.Schema["table_name"] + assert.True(t, tableName.Required) + assert.True(t, tableName.ForceNew) + + columns := res.Schema["columns"] + assert.True(t, columns.Required) + assert.True(t, columns.ForceNew) + + properties := res.Schema["properties"] + assert.True(t, properties.Optional) + assert.True(t, properties.ForceNew) + + primaryKeys := res.Schema["primary_keys"] + assert.True(t, primaryKeys.Optional) + assert.True(t, primaryKeys.ForceNew) + + upsertKeys := res.Schema["upsert_keys"] + assert.True(t, upsertKeys.Optional) + assert.True(t, upsertKeys.ForceNew) + + tableComment := res.Schema["table_comment"] + assert.True(t, tableComment.Optional) + assert.False(t, tableComment.ForceNew) + + location := res.Schema["location"] + assert.True(t, location.Computed) + + storageSize := res.Schema["storage_size"] + assert.True(t, storageSize.Computed) +} + +// TestDlcInternalTable_CreateWithSmartPolicy tests create with smart policy +func TestDlcInternalTable_CreateWithSmartPolicy(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + var capturedRequest *dlc.GenerateInternalTableRequest + patches.ApplyMethodFunc(dlcClient, "GenerateInternalTableWithContext", func(_ context.Context, request *dlc.GenerateInternalTableRequest) (*dlc.GenerateInternalTableResponse, error) { + capturedRequest = request + resp := dlc.NewGenerateInternalTableResponse() + resp.Response = &dlc.GenerateInternalTableResponseParams{ + Execution: &dlc.Execution{ + SQL: ptrStrDlcIt("CREATE TABLE"), + }, + IsTIcebergSql: ptrBoolDlcIt(true), + RequestId: ptrStrDlcIt("fake-request-id"), + } + return resp, nil + }) + + patches.ApplyMethodFunc(dlcClient, "DescribeTableWithContext", func(_ context.Context, request *dlc.DescribeTableRequest) (*dlc.DescribeTableResponse, error) { + resp := dlc.NewDescribeTableResponse() + resp.Response = &dlc.DescribeTableResponseParams{ + Table: &dlc.TableResponseInfo{ + TableBaseInfo: &dlc.TableBaseInfo{ + DatabaseName: ptrStrDlcIt("tf_example_db"), + TableName: ptrStrDlcIt("tf_example_table"), + }, + Columns: []*dlc.Column{ + { + Name: ptrStrDlcIt("id"), + Type: ptrStrDlcIt("bigint"), + }, + }, + }, + RequestId: ptrStrDlcIt("fake-request-id-read"), + } + return resp, nil + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "tf_example_db", + "table_name": "tf_example_table", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + "smart_policy": []interface{}{ + map[string]interface{}{ + "base_info": []interface{}{ + map[string]interface{}{ + "uin": "100012345678", + "policy_type": "Table", + "catalog": "DataLakeCatalog", + "database": "tf_example_db", + "table": "tf_example_table", + "app_id": "1300123456", + }, + }, + "policy": []interface{}{ + map[string]interface{}{ + "inherit": "false", + "table_expiration": []interface{}{ + map[string]interface{}{ + "enabled": true, + "expiration": 90, + }, + }, + }, + }, + }, + }, + }) + + err := res.Create(d, meta) + assert.NoError(t, err) + assert.NotNil(t, capturedRequest.TableBaseInfo.SmartPolicy) + assert.NotNil(t, capturedRequest.TableBaseInfo.SmartPolicy.BaseInfo) + assert.Equal(t, "100012345678", *capturedRequest.TableBaseInfo.SmartPolicy.BaseInfo.Uin) + assert.NotNil(t, capturedRequest.TableBaseInfo.SmartPolicy.Policy) + assert.NotNil(t, capturedRequest.TableBaseInfo.SmartPolicy.Policy.TableExpiration) + assert.Equal(t, true, *capturedRequest.TableBaseInfo.SmartPolicy.Policy.TableExpiration.Enabled) + assert.Equal(t, uint64(90), *capturedRequest.TableBaseInfo.SmartPolicy.Policy.TableExpiration.Expiration) +} + +// TestDlcInternalTable_APIError tests Create when API returns error +func TestDlcInternalTable_APIError(t *testing.T) { + patches := gomonkey.NewPatches() + defer patches.Reset() + + dlcClient := &dlc.Client{} + patches.ApplyMethodReturn(newMockMetaDlcInternalTable().client, "UseDlcClient", dlcClient) + + patches.ApplyMethodFunc(dlcClient, "GenerateInternalTableWithContext", func(_ context.Context, request *dlc.GenerateInternalTableRequest) (*dlc.GenerateInternalTableResponse, error) { + return nil, fmt.Errorf("[TencentCloudSDKError] Code=ResourceNotFound, Message=Database not found") + }) + + meta := newMockMetaDlcInternalTable() + res := svcdlc.ResourceTencentCloudDlcInternalTable() + d := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{ + "database_name": "invalid_db", + "table_name": "tf_example_table", + "columns": []interface{}{ + map[string]interface{}{ + "name": "id", + "type": "bigint", + }, + }, + }) + + err := res.Create(d, meta) + assert.Error(t, err) + assert.Contains(t, err.Error(), "ResourceNotFound") +} diff --git a/tencentcloud/services/dlc/service_tencentcloud_dlc.go b/tencentcloud/services/dlc/service_tencentcloud_dlc.go index 6dd91f455e..1c6a50cb4d 100644 --- a/tencentcloud/services/dlc/service_tencentcloud_dlc.go +++ b/tencentcloud/services/dlc/service_tencentcloud_dlc.go @@ -1607,3 +1607,48 @@ func (me *DlcService) DeleteDlcAttachWorkGroupPolicyAttachmentByPolicyId(ctx con return } + +func (me *DlcService) DescribeDlcInternalTableById(ctx context.Context, databaseName, tableName, datasourceConnectionName string) (tableInfo *dlc.TableResponseInfo, errRet error) { + logId := tccommon.GetLogId(ctx) + + request := dlc.NewDescribeTableRequest() + request.DatabaseName = helper.String(databaseName) + request.TableName = helper.String(tableName) + if datasourceConnectionName != "" { + request.DatasourceConnectionName = helper.String(datasourceConnectionName) + } + + defer func() { + if errRet != nil { + log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", logId, request.GetAction(), request.ToJsonString(), errRet.Error()) + } + }() + + errRet = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + ratelimit.Check(request.GetAction()) + result, e := me.client.UseDlcClient().DescribeTable(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 == nil || result.Response == nil { + return resource.NonRetryableError(fmt.Errorf("Describe dlc internal table failed, Response is nil.")) + } + + if result.Response.Table == nil { + return nil + } + + tableInfo = result.Response.Table + return nil + }) + + if errRet != nil { + log.Printf("[CRITAL]%s describe dlc internal table failed, reason:%+v", logId, errRet) + return + } + + return +} diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/client.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/client.go index 472a42490b..eae4d09382 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/client.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/client.go @@ -2216,6 +2216,7 @@ func NewCreateDatasourceConnectionResponse() (response *CreateDatasourceConnecti // INVALIDPARAMETER_DUPLICATEDATASOURCENAME = "InvalidParameter.DuplicateDatasourceName" // INVALIDPARAMETER_INVALIDDATAENGINENAME = "InvalidParameter.InvalidDataEngineName" // INVALIDPARAMETER_INVALIDDATASOURCECONNECTIONCONFIG = "InvalidParameter.InvalidDatasourceConnectionConfig" +// INVALIDPARAMETER_INVALIDDATASOURCENAME = "InvalidParameter.InvalidDatasourceName" // INVALIDPARAMETER_INVALIDHIVEVERSION = "InvalidParameter.InvalidHiveVersion" // INVALIDPARAMETER_URLFORMATERROR = "InvalidParameter.UrlFormatError" // INVALIDPARAMETER_VPCCIDRFORMATERROR = "InvalidParameter.VpcCidrFormatError" @@ -2238,6 +2239,7 @@ func (c *Client) CreateDatasourceConnection(request *CreateDatasourceConnectionR // INVALIDPARAMETER_DUPLICATEDATASOURCENAME = "InvalidParameter.DuplicateDatasourceName" // INVALIDPARAMETER_INVALIDDATAENGINENAME = "InvalidParameter.InvalidDataEngineName" // INVALIDPARAMETER_INVALIDDATASOURCECONNECTIONCONFIG = "InvalidParameter.InvalidDatasourceConnectionConfig" +// INVALIDPARAMETER_INVALIDDATASOURCENAME = "InvalidParameter.InvalidDatasourceName" // INVALIDPARAMETER_INVALIDHIVEVERSION = "InvalidParameter.InvalidHiveVersion" // INVALIDPARAMETER_URLFORMATERROR = "InvalidParameter.UrlFormatError" // INVALIDPARAMETER_VPCCIDRFORMATERROR = "InvalidParameter.VpcCidrFormatError" @@ -3058,17 +3060,11 @@ func NewCreatePartitionResponse() (response *CreatePartitionResponse) { // 新增资源包 // // 可能返回的错误码: -// FAILEDOPERATION = "FailedOperation" -// INTERNALERROR = "InternalError" -// INTERNALERROR_INTERNALSYSTEMEXCEPTION = "InternalError.InternalSystemException" -// INVALIDPARAMETER = "InvalidParameter" -// INVALIDPARAMETER_INVALIDSQL = "InvalidParameter.InvalidSQL" -// INVALIDPARAMETER_INVALIDSTATEMENTKINDTYPE = "InvalidParameter.InvalidStatementKindType" -// INVALIDPARAMETER_PARAMETERNOTFOUNDORBENONE = "InvalidParameter.ParameterNotFoundOrBeNone" -// RESOURCENOTFOUND = "ResourceNotFound" -// RESOURCENOTFOUND_RESULTSAVEPATHNOTFOUND = "ResourceNotFound.ResultSavePathNotFound" -// RESOURCENOTFOUND_SESSIONNOTFOUND = "ResourceNotFound.SessionNotFound" -// RESOURCENOTFOUND_SESSIONSTATEDEAD = "ResourceNotFound.SessionStateDead" +// FAILEDOPERATION_APICALLFAILED = "FailedOperation.ApiCallFailed" +// INVALIDPARAMETERVALUE_BILLINGITEMSTEP = "InvalidParameterValue.BillingItemStep" +// INVALIDPARAMETERVALUE_POSTPAYPARTITIONNAME = "InvalidParameterValue.PostpayPartitionName" +// LIMITEXCEEDED = "LimitExceeded" +// RESOURCEINSUFFICIENT = "ResourceInsufficient" func (c *Client) CreatePartition(request *CreatePartitionRequest) (response *CreatePartitionResponse, err error) { return c.CreatePartitionWithContext(context.Background(), request) } @@ -3077,17 +3073,11 @@ func (c *Client) CreatePartition(request *CreatePartitionRequest) (response *Cre // 新增资源包 // // 可能返回的错误码: -// FAILEDOPERATION = "FailedOperation" -// INTERNALERROR = "InternalError" -// INTERNALERROR_INTERNALSYSTEMEXCEPTION = "InternalError.InternalSystemException" -// INVALIDPARAMETER = "InvalidParameter" -// INVALIDPARAMETER_INVALIDSQL = "InvalidParameter.InvalidSQL" -// INVALIDPARAMETER_INVALIDSTATEMENTKINDTYPE = "InvalidParameter.InvalidStatementKindType" -// INVALIDPARAMETER_PARAMETERNOTFOUNDORBENONE = "InvalidParameter.ParameterNotFoundOrBeNone" -// RESOURCENOTFOUND = "ResourceNotFound" -// RESOURCENOTFOUND_RESULTSAVEPATHNOTFOUND = "ResourceNotFound.ResultSavePathNotFound" -// RESOURCENOTFOUND_SESSIONNOTFOUND = "ResourceNotFound.SessionNotFound" -// RESOURCENOTFOUND_SESSIONSTATEDEAD = "ResourceNotFound.SessionStateDead" +// FAILEDOPERATION_APICALLFAILED = "FailedOperation.ApiCallFailed" +// INVALIDPARAMETERVALUE_BILLINGITEMSTEP = "InvalidParameterValue.BillingItemStep" +// INVALIDPARAMETERVALUE_POSTPAYPARTITIONNAME = "InvalidParameterValue.PostpayPartitionName" +// LIMITEXCEEDED = "LimitExceeded" +// RESOURCEINSUFFICIENT = "ResourceInsufficient" func (c *Client) CreatePartitionWithContext(ctx context.Context, request *CreatePartitionRequest) (response *CreatePartitionResponse, err error) { if request == nil { request = NewCreatePartitionRequest() @@ -8845,7 +8835,7 @@ func NewDescribeSaleResourceInfoResponse() (response *DescribeSaleResourceInfoRe } // DescribeSaleResourceInfo -// 查询当前地域可售卖的资源规格和最大配额 +// 查询当前地域可售卖的资源规格、最大配额,以及库存情况。StatusCategory 与 DescribePartitionAvailableQuota 数据同源,将实时可新增数量映射为库存分级;当请求 Region 与资源池实际部署地域不一致,或服务 cold-start 快照尚未就绪时,StatusCategory 为 null。 // // 可能返回的错误码: // FAILEDOPERATION = "FailedOperation" @@ -8854,7 +8844,7 @@ func (c *Client) DescribeSaleResourceInfo(request *DescribeSaleResourceInfoReque } // DescribeSaleResourceInfo -// 查询当前地域可售卖的资源规格和最大配额 +// 查询当前地域可售卖的资源规格、最大配额,以及库存情况。StatusCategory 与 DescribePartitionAvailableQuota 数据同源,将实时可新增数量映射为库存分级;当请求 Region 与资源池实际部署地域不一致,或服务 cold-start 快照尚未就绪时,StatusCategory 为 null。 // // 可能返回的错误码: // FAILEDOPERATION = "FailedOperation" @@ -13747,6 +13737,56 @@ func (c *Client) ListExamplesWithContext(ctx context.Context, request *ListExamp return } +func NewListImagesRequest() (request *ListImagesRequest) { + request = &ListImagesRequest{ + BaseRequest: &tchttp.BaseRequest{}, + } + + request.Init().WithApiInfo("dlc", APIVersion, "ListImages") + + + return +} + +func NewListImagesResponse() (response *ListImagesResponse) { + response = &ListImagesResponse{ + BaseResponse: &tchttp.BaseResponse{}, + } + return + +} + +// ListImages +// 列出所有镜像 +// +// 可能返回的错误码: +// FAILEDOPERATION_EXTERNALSERVICE = "FailedOperation.ExternalService" +func (c *Client) ListImages(request *ListImagesRequest) (response *ListImagesResponse, err error) { + return c.ListImagesWithContext(context.Background(), request) +} + +// ListImages +// 列出所有镜像 +// +// 可能返回的错误码: +// FAILEDOPERATION_EXTERNALSERVICE = "FailedOperation.ExternalService" +func (c *Client) ListImagesWithContext(ctx context.Context, request *ListImagesRequest) (response *ListImagesResponse, err error) { + if request == nil { + request = NewListImagesRequest() + } + c.InitBaseRequest(&request.BaseRequest, "dlc", APIVersion, "ListImages") + + if c.GetCredential() == nil { + return nil, errors.New("ListImages require credential") + } + + request.SetContext(ctx) + + response = NewListImagesResponse() + err = c.Send(request, response) + return +} + func NewListInferenceEnginesRequest() (request *ListInferenceEnginesRequest) { request = &ListInferenceEnginesRequest{ BaseRequest: &tchttp.BaseRequest{}, diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/errors.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/errors.go index acbdaa7748..28457401ba 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/errors.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/errors.go @@ -35,6 +35,9 @@ const ( // 另一个请求正在处理中,请稍后再试。 FAILEDOPERATION_ANOTHERREQUESTPROCESSING = "FailedOperation.AnotherRequestProcessing" + // 调用下游计费接口失败,资源销毁通知未送达 + FAILEDOPERATION_APICALLFAILED = "FailedOperation.ApiCallFailed" + // 账户余额不足。 FAILEDOPERATION_BALANCENOTENOUGH = "FailedOperation.BalanceNotEnough" @@ -356,6 +359,9 @@ const ( // 数据源连接配置异常,请重试,或者提交工单联系我们 INVALIDPARAMETER_INVALIDDATASOURCECONNECTIONCONFIG = "InvalidParameter.InvalidDatasourceConnectionConfig" + // 数据源连接名称不合法 + INVALIDPARAMETER_INVALIDDATASOURCENAME = "InvalidParameter.InvalidDatasourceName" + // DecimalType设置非法,Precision必须大于等于Scale,且Precision必须小于38 INVALIDPARAMETER_INVALIDDECIMALTYPE = "InvalidParameter.InvalidDecimalType" @@ -608,6 +614,12 @@ const ( // 参数取值错误。 INVALIDPARAMETERVALUE = "InvalidParameterValue" + // 机型步长不规范,cpu需要为32倍数 + INVALIDPARAMETERVALUE_BILLINGITEMSTEP = "InvalidParameterValue.BillingItemStep" + + // 按量计费资源包名称不规范 + INVALIDPARAMETERVALUE_POSTPAYPARTITIONNAME = "InvalidParameterValue.PostpayPartitionName" + // 队列 Id 与 PartitionCode/QueueName 不一致 INVALIDPARAMETERVALUE_QUEUEIDMISMATCH = "InvalidParameterValue.QueueIdMismatch" @@ -644,6 +656,9 @@ const ( // 有SQL任务尚未执行完成。 RESOURCEINUSE_UNFINISHEDSQLS = "ResourceInUse.UnfinishedSQLs" + // 资源不足。 + RESOURCEINSUFFICIENT = "ResourceInsufficient" + // 指定的spark作业资源不足,请调整driver/executor规格 RESOURCEINSUFFICIENT_SPARKJOBINSUFFICIENTRESOURCES = "ResourceInsufficient.SparkJobInsufficientResources" diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/models.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/models.go index c909aabc4f..52fef133b2 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/models.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125/models.go @@ -3559,6 +3559,15 @@ type CreateInferenceModelRequestParams struct { //

模型 UID(可选,前端预先生成的 UID,不传则后端自动生成)

ModelUid *string `json:"ModelUid,omitnil,omitempty" name:"ModelUid"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

模型文件来源于goosefs

+ GooseFSConfig *GooseFSConfig `json:"GooseFSConfig,omitnil,omitempty" name:"GooseFSConfig"` + + //

模型上传来源类型

枚举值:

  • Local: 本地上传
  • COS: COS上传
  • CFS: CFS上传
  • CFSTurbo: CFSTurbo上传
  • GooseFS: GooseFS上传
+ StorageType *string `json:"StorageType,omitnil,omitempty" name:"StorageType"` } type CreateInferenceModelRequest struct { @@ -3596,6 +3605,15 @@ type CreateInferenceModelRequest struct { //

模型 UID(可选,前端预先生成的 UID,不传则后端自动生成)

ModelUid *string `json:"ModelUid,omitnil,omitempty" name:"ModelUid"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

模型文件来源于goosefs

+ GooseFSConfig *GooseFSConfig `json:"GooseFSConfig,omitnil,omitempty" name:"GooseFSConfig"` + + //

模型上传来源类型

枚举值:

  • Local: 本地上传
  • COS: COS上传
  • CFS: CFS上传
  • CFSTurbo: CFSTurbo上传
  • GooseFS: GooseFS上传
+ StorageType *string `json:"StorageType,omitnil,omitempty" name:"StorageType"` } func (r *CreateInferenceModelRequest) ToJsonString() string { @@ -3621,6 +3639,9 @@ func (r *CreateInferenceModelRequest) FromJsonString(s string) error { delete(f, "UseCustomStorage") delete(f, "Tasks") delete(f, "ModelUid") + delete(f, "ResourceTags") + delete(f, "GooseFSConfig") + delete(f, "StorageType") if len(f) > 0 { return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "CreateInferenceModelRequest has unknown keys!", "") } @@ -3690,6 +3711,9 @@ type CreateInferenceModelResponseParams struct { //

Sub UIN

SubAccountUin *string `json:"SubAccountUin,omitnil,omitempty" name:"SubAccountUin"` + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -3765,6 +3789,18 @@ type CreateInferenceServiceRequestParams struct { //

ApiKeyIds

ApiKeyIds []*string `json:"ApiKeyIds,omitnil,omitempty" name:"ApiKeyIds"` + + //

AdvancedOptions 高级参数 JSON 字符串(可选),扁平 KV 结构,作用于 K8s RayService CR YAML 字段级

+ AdvancedOptions *string `json:"AdvancedOptions,omitnil,omitempty" name:"AdvancedOptions"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

自定义RayServe提交

+ IsCustom *bool `json:"IsCustom,omitnil,omitempty" name:"IsCustom"` + + //

python runtime env

+ RuntimeEnv *string `json:"RuntimeEnv,omitnil,omitempty" name:"RuntimeEnv"` } type CreateInferenceServiceRequest struct { @@ -3823,6 +3859,18 @@ type CreateInferenceServiceRequest struct { //

ApiKeyIds

ApiKeyIds []*string `json:"ApiKeyIds,omitnil,omitempty" name:"ApiKeyIds"` + + //

AdvancedOptions 高级参数 JSON 字符串(可选),扁平 KV 结构,作用于 K8s RayService CR YAML 字段级

+ AdvancedOptions *string `json:"AdvancedOptions,omitnil,omitempty" name:"AdvancedOptions"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

自定义RayServe提交

+ IsCustom *bool `json:"IsCustom,omitnil,omitempty" name:"IsCustom"` + + //

python runtime env

+ RuntimeEnv *string `json:"RuntimeEnv,omitnil,omitempty" name:"RuntimeEnv"` } func (r *CreateInferenceServiceRequest) ToJsonString() string { @@ -3855,6 +3903,10 @@ func (r *CreateInferenceServiceRequest) FromJsonString(s string) error { delete(f, "MaxReplicas") delete(f, "AutoscalerOptions") delete(f, "ApiKeyIds") + delete(f, "AdvancedOptions") + delete(f, "ResourceTags") + delete(f, "IsCustom") + delete(f, "RuntimeEnv") if len(f) > 0 { return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "CreateInferenceServiceRequest has unknown keys!", "") } @@ -3962,6 +4014,18 @@ type CreateInferenceServiceResponseParams struct { //

资源配置(JSON 字符串,取自第一个部署)

ResourceConfig *string `json:"ResourceConfig,omitnil,omitempty" name:"ResourceConfig"` + //

AdvancedOptions 高级参数 JSON 字符串(扁平 KV 结构,取自第一个部署)

+ AdvancedOptions *string `json:"AdvancedOptions,omitnil,omitempty" name:"AdvancedOptions"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

部署模式

+ DeploymentMode *string `json:"DeploymentMode,omitnil,omitempty" name:"DeploymentMode"` + + //

是否是自定义 RayServe 创建

+ IsCustom *bool `json:"IsCustom,omitnil,omitempty" name:"IsCustom"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -4377,21 +4441,21 @@ type CreateLabRequestParams struct { //

数据实验室名称

Name *string `json:"Name,omitnil,omitempty" name:"Name"` - //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

- LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` - //

资源分区ID

ResourcePartitionId *string `json:"ResourcePartitionId,omitnil,omitempty" name:"ResourcePartitionId"` //

队列名称

Queue *string `json:"Queue,omitnil,omitempty" name:"Queue"` - //

数据实验室描述

- Description *string `json:"Description,omitnil,omitempty" name:"Description"` - //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

Image *string `json:"Image,omitnil,omitempty" name:"Image"` + //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

+ LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` + + //

数据实验室描述

+ Description *string `json:"Description,omitnil,omitempty" name:"Description"` + //

镜像拉取策略(Always, IfNotPresent, Never)

ImagePullPolicy *string `json:"ImagePullPolicy,omitnil,omitempty" name:"ImagePullPolicy"` @@ -4447,21 +4511,21 @@ type CreateLabRequest struct { //

数据实验室名称

Name *string `json:"Name,omitnil,omitempty" name:"Name"` - //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

- LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` - //

资源分区ID

ResourcePartitionId *string `json:"ResourcePartitionId,omitnil,omitempty" name:"ResourcePartitionId"` //

队列名称

Queue *string `json:"Queue,omitnil,omitempty" name:"Queue"` - //

数据实验室描述

- Description *string `json:"Description,omitnil,omitempty" name:"Description"` - //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

Image *string `json:"Image,omitnil,omitempty" name:"Image"` + //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

+ LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` + + //

数据实验室描述

+ Description *string `json:"Description,omitnil,omitempty" name:"Description"` + //

镜像拉取策略(Always, IfNotPresent, Never)

ImagePullPolicy *string `json:"ImagePullPolicy,omitnil,omitempty" name:"ImagePullPolicy"` @@ -4524,11 +4588,11 @@ func (r *CreateLabRequest) FromJsonString(s string) error { return err } delete(f, "Name") - delete(f, "LabImage") delete(f, "ResourcePartitionId") delete(f, "Queue") - delete(f, "Description") delete(f, "Image") + delete(f, "LabImage") + delete(f, "Description") delete(f, "ImagePullPolicy") delete(f, "ResourceConfig") delete(f, "ResourceConfigId") @@ -4757,6 +4821,12 @@ type CreateModelVersionRequestParams struct { //

是否使用用户自带存储桶(默认 false 表示平台托管)

UseCustomStorage *bool `json:"UseCustomStorage,omitnil,omitempty" name:"UseCustomStorage"` + + //

创建模型时,模型从goosfe里面选取,则需要传递该参数

+ GooseFSConfig *GooseFSConfig `json:"GooseFSConfig,omitnil,omitempty" name:"GooseFSConfig"` + + //

模型上传路径类型

枚举值:

  • LOCAL: 本地上传
  • CFS: CFS上传
  • COS: COS上传
  • CFSTurbo: CFSTurbo上传
  • GooseFS: GooseFS上传

选择cos、cfs、cfstrubo则必须要传storageuri,选择local时不能传递goosefsconfig

+ StorageType *string `json:"StorageType,omitnil,omitempty" name:"StorageType"` } type CreateModelVersionRequest struct { @@ -4776,6 +4846,12 @@ type CreateModelVersionRequest struct { //

是否使用用户自带存储桶(默认 false 表示平台托管)

UseCustomStorage *bool `json:"UseCustomStorage,omitnil,omitempty" name:"UseCustomStorage"` + + //

创建模型时,模型从goosfe里面选取,则需要传递该参数

+ GooseFSConfig *GooseFSConfig `json:"GooseFSConfig,omitnil,omitempty" name:"GooseFSConfig"` + + //

模型上传路径类型

枚举值:

  • LOCAL: 本地上传
  • CFS: CFS上传
  • COS: COS上传
  • CFSTurbo: CFSTurbo上传
  • GooseFS: GooseFS上传

选择cos、cfs、cfstrubo则必须要传storageuri,选择local时不能传递goosefsconfig

+ StorageType *string `json:"StorageType,omitnil,omitempty" name:"StorageType"` } func (r *CreateModelVersionRequest) ToJsonString() string { @@ -4795,6 +4871,8 @@ func (r *CreateModelVersionRequest) FromJsonString(s string) error { delete(f, "Description") delete(f, "StorageUri") delete(f, "UseCustomStorage") + delete(f, "GooseFSConfig") + delete(f, "StorageType") if len(f) > 0 { return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "CreateModelVersionRequest has unknown keys!", "") } @@ -5267,19 +5345,19 @@ func (r *CreatePartitionQueueResponse) FromJsonString(s string) error { // Predefined struct for user type CreatePartitionRequestParams struct { - //

交易类型:purchase-新购,renew-续费,modify-变配

+ //

交易类型:purchase-新购

ActionType *string `json:"ActionType,omitnil,omitempty" name:"ActionType"` - //

付费模式:0-后付费,1-预付费

+ //

付费模式:1-预付费

PayMode *uint64 `json:"PayMode,omitnil,omitempty" name:"PayMode"` //

资源配额列表(计费项+数量)

ResourceQuotaList []*ResourceQuota `json:"ResourceQuotaList,omitnil,omitempty" name:"ResourceQuotaList"` - //

时间大小,预付费时为购买月数,后付费时为3600

+ //

时间大小,预付费时为购买月数

TimeSpan *int64 `json:"TimeSpan,omitnil,omitempty" name:"TimeSpan"` - //

时间单位,预付费为m(月),后付费为s(秒)

+ //

时间单位,预付费为m(月)

TimeUnit *string `json:"TimeUnit,omitnil,omitempty" name:"TimeUnit"` //

自动续费标志:0-默认,1-自动续费,2-不自动续费(仅预付费有效)

@@ -5288,26 +5366,26 @@ type CreatePartitionRequestParams struct { //

弹性资源池名称,用于订单页展示

Name *string `json:"Name,omitnil,omitempty" name:"Name"` - //

队列描述

+ //

资源包描述

Description *string `json:"Description,omitnil,omitempty" name:"Description"` } type CreatePartitionRequest struct { *tchttp.BaseRequest - //

交易类型:purchase-新购,renew-续费,modify-变配

+ //

交易类型:purchase-新购

ActionType *string `json:"ActionType,omitnil,omitempty" name:"ActionType"` - //

付费模式:0-后付费,1-预付费

+ //

付费模式:1-预付费

PayMode *uint64 `json:"PayMode,omitnil,omitempty" name:"PayMode"` //

资源配额列表(计费项+数量)

ResourceQuotaList []*ResourceQuota `json:"ResourceQuotaList,omitnil,omitempty" name:"ResourceQuotaList"` - //

时间大小,预付费时为购买月数,后付费时为3600

+ //

时间大小,预付费时为购买月数

TimeSpan *int64 `json:"TimeSpan,omitnil,omitempty" name:"TimeSpan"` - //

时间单位,预付费为m(月),后付费为s(秒)

+ //

时间单位,预付费为m(月)

TimeUnit *string `json:"TimeUnit,omitnil,omitempty" name:"TimeUnit"` //

自动续费标志:0-默认,1-自动续费,2-不自动续费(仅预付费有效)

@@ -5316,7 +5394,7 @@ type CreatePartitionRequest struct { //

弹性资源池名称,用于订单页展示

Name *string `json:"Name,omitnil,omitempty" name:"Name"` - //

队列描述

+ //

资源包描述

Description *string `json:"Description,omitnil,omitempty" name:"Description"` } @@ -8698,51 +8776,54 @@ type DatabaseResponseInfo struct { } type DatasourceConnectionConfig struct { - // Mysql数据源连接的属性 + //

Mysql数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 Mysql *MysqlInfo `json:"Mysql,omitnil,omitempty" name:"Mysql"` - // Hive数据源连接的属性 + //

Hive数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 Hive *HiveInfo `json:"Hive,omitnil,omitempty" name:"Hive"` - // Kafka数据源连接的属性 + //

Kafka数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 Kafka *KafkaInfo `json:"Kafka,omitnil,omitempty" name:"Kafka"` - // 其他数据源连接的属性 + //

其他数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 OtherDatasourceConnection *OtherDatasourceConnection `json:"OtherDatasourceConnection,omitnil,omitempty" name:"OtherDatasourceConnection"` - // PostgreSQL数据源连接的属性 + //

PostgreSQL数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 PostgreSql *DataSourceInfo `json:"PostgreSql,omitnil,omitempty" name:"PostgreSql"` - // SQLServer数据源连接的属性 + //

SQLServer数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 SqlServer *DataSourceInfo `json:"SqlServer,omitnil,omitempty" name:"SqlServer"` - // ClickHouse数据源连接的属性 + //

ClickHouse数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 ClickHouse *DataSourceInfo `json:"ClickHouse,omitnil,omitempty" name:"ClickHouse"` - // Elasticsearch数据源连接的属性 + //

Elasticsearch数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 Elasticsearch *ElasticsearchInfo `json:"Elasticsearch,omitnil,omitempty" name:"Elasticsearch"` - // TDSQL-PostgreSQL数据源连接的属性 + //

TDSQL-PostgreSQL数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 TDSQLPostgreSql *DataSourceInfo `json:"TDSQLPostgreSql,omitnil,omitempty" name:"TDSQLPostgreSql"` - // Doris数据源连接的属性 + //

Doris数据源连接的属性

// 注意:此字段可能返回 null,表示取不到有效值。 TCHouseD *TCHouseD `json:"TCHouseD,omitnil,omitempty" name:"TCHouseD"` - // TccHive数据目录连接信息 + //

TccHive数据目录连接信息

TccHive *TccHive `json:"TccHive,omitnil,omitempty" name:"TccHive"` - // MongoDB 数据源 + //

MongoDB 数据源

MongoDB *DataSourceInfo `json:"MongoDB,omitnil,omitempty" name:"MongoDB"` + + //

TCHouseP数据源

+ TCHouseP *TCHousePInfo `json:"TCHouseP,omitnil,omitempty" name:"TCHouseP"` } type DatasourceConnectionInfo struct { @@ -12746,6 +12827,9 @@ func (r *DescribeMCPTaskResponse) FromJsonString(s string) error { type DescribeMCPTaskResultRequestParams struct { //

任务ID

TaskId *string `json:"TaskId,omitnil,omitempty" name:"TaskId"` + + //

下一次请求数据

+ NextToken *string `json:"NextToken,omitnil,omitempty" name:"NextToken"` } type DescribeMCPTaskResultRequest struct { @@ -12753,6 +12837,9 @@ type DescribeMCPTaskResultRequest struct { //

任务ID

TaskId *string `json:"TaskId,omitnil,omitempty" name:"TaskId"` + + //

下一次请求数据

+ NextToken *string `json:"NextToken,omitnil,omitempty" name:"NextToken"` } func (r *DescribeMCPTaskResultRequest) ToJsonString() string { @@ -12768,6 +12855,7 @@ func (r *DescribeMCPTaskResultRequest) FromJsonString(s string) error { return err } delete(f, "TaskId") + delete(f, "NextToken") if len(f) > 0 { return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "DescribeMCPTaskResultRequest has unknown keys!", "") } @@ -13976,7 +14064,7 @@ func (r *DescribeSaleResourceInfoRequest) FromJsonString(s string) error { // Predefined struct for user type DescribeSaleResourceInfoResponseParams struct { - // 可售卖资源规格列表 + // 可售卖资源规格列表,包含规格、步长、单账户上限、以及库存情况 SaleResourceInfoList []*ResourceSaleInfo `json:"SaleResourceInfoList,omitnil,omitempty" name:"SaleResourceInfoList"` // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 @@ -18697,6 +18785,10 @@ type GetInferenceModelResponseParams struct { //

Sub UIN

SubAccountUin *string `json:"SubAccountUin,omitnil,omitempty" name:"SubAccountUin"` + //

系统标签列表(TagKey-TagValue)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -18848,6 +18940,15 @@ type GetInferenceServiceResponseParams struct { //

资源配置(JSON 字符串,取自第一个部署)

ResourceConfig *string `json:"ResourceConfig,omitnil,omitempty" name:"ResourceConfig"` + //

部署模式

+ DeploymentMode *string `json:"DeploymentMode,omitnil,omitempty" name:"DeploymentMode"` + + //

是否为自定义代码部署

+ IsCustom *bool `json:"IsCustom,omitnil,omitempty" name:"IsCustom"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -21254,8 +21355,29 @@ func (r *GetResourceConfigResponse) FromJsonString(s string) error { return json.Unmarshal([]byte(s), &r) } +type GooseFSConfig struct { + //

goosefs集群id

+ ClusterId *string `json:"ClusterId,omitnil,omitempty" name:"ClusterId"` + + //

goosefs命名空间名称

+ GooseFSPath *string `json:"GooseFSPath,omitnil,omitempty" name:"GooseFSPath"` + + //

主从节点信息

+ MasterAddresses []*string `json:"MasterAddresses,omitnil,omitempty" name:"MasterAddresses"` +} + type GpuSummaryItem struct { + //

GPU 型号

+ // 注意:此字段可能返回 null,表示取不到有效值。 + GpuType *string `json:"GpuType,omitnil,omitempty" name:"GpuType"` + + //

GPU 总数(gpuNum × replicas)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + GpuCount *int64 `json:"GpuCount,omitnil,omitempty" name:"GpuCount"` + //

运行中的副本数

+ // 注意:此字段可能返回 null,表示取不到有效值。 + Replicas *int64 `json:"Replicas,omitnil,omitempty" name:"Replicas"` } // Predefined struct for user @@ -21498,6 +21620,32 @@ type IcebergTablePartition struct { Location *LocationInfo `json:"Location,omitnil,omitempty" name:"Location"` } +type ImageDto struct { + //

镜像ID

+ Id *int64 `json:"Id,omitnil,omitempty" name:"Id"` + + //

镜像名称

+ Name *string `json:"Name,omitnil,omitempty" name:"Name"` + + //

镜像地址

+ Url *string `json:"Url,omitnil,omitempty" name:"Url"` + + //

镜像描述

+ Description *string `json:"Description,omitnil,omitempty" name:"Description"` + + //

镜像类型(Ray/Workspace)

+ Type *string `json:"Type,omitnil,omitempty" name:"Type"` + + //

镜像内置的 Ray 版本号

+ RayVersion *string `json:"RayVersion,omitnil,omitempty" name:"RayVersion"` + + //

创建时间

+ CreateTime *uint64 `json:"CreateTime,omitnil,omitempty" name:"CreateTime"` + + //

更新时间

+ UpdateTime *uint64 `json:"UpdateTime,omitnil,omitempty" name:"UpdateTime"` +} + type InferenceEngineInfo struct { //

引擎标识符

EngineId *string `json:"EngineId,omitnil,omitempty" name:"EngineId"` @@ -21617,6 +21765,10 @@ type InferenceModelInfo struct { //

云账户的 Sub UIN

SubAccountUin *string `json:"SubAccountUin,omitnil,omitempty" name:"SubAccountUin"` + + //

系统标签列表(TagKey-TagValue)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` } type InferenceServiceInfo struct { @@ -22691,6 +22843,96 @@ func (r *ListExamplesResponse) FromJsonString(s string) error { return json.Unmarshal([]byte(s), &r) } +// Predefined struct for user +type ListImagesRequestParams struct { + // 关键词搜索(模糊匹配名称或描述) + Keyword *string `json:"Keyword,omitnil,omitempty" name:"Keyword"` + + // 镜像类型过滤(Ray/Workspace) + Type *string `json:"Type,omitnil,omitempty" name:"Type"` + + // 页数 + Page *int64 `json:"Page,omitnil,omitempty" name:"Page"` + + // 数量 + PageSize *int64 `json:"PageSize,omitnil,omitempty" name:"PageSize"` +} + +type ListImagesRequest struct { + *tchttp.BaseRequest + + // 关键词搜索(模糊匹配名称或描述) + Keyword *string `json:"Keyword,omitnil,omitempty" name:"Keyword"` + + // 镜像类型过滤(Ray/Workspace) + Type *string `json:"Type,omitnil,omitempty" name:"Type"` + + // 页数 + Page *int64 `json:"Page,omitnil,omitempty" name:"Page"` + + // 数量 + PageSize *int64 `json:"PageSize,omitnil,omitempty" name:"PageSize"` +} + +func (r *ListImagesRequest) ToJsonString() string { + b, _ := json.Marshal(r) + return string(b) +} + +// FromJsonString It is highly **NOT** recommended to use this function +// because it has no param check, nor strict type check +func (r *ListImagesRequest) FromJsonString(s string) error { + f := make(map[string]interface{}) + if err := json.Unmarshal([]byte(s), &f); err != nil { + return err + } + delete(f, "Keyword") + delete(f, "Type") + delete(f, "Page") + delete(f, "PageSize") + if len(f) > 0 { + return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "ListImagesRequest has unknown keys!", "") + } + return json.Unmarshal([]byte(s), &r) +} + +// Predefined struct for user +type ListImagesResponseParams struct { + // 总记录数 + Total *int64 `json:"Total,omitnil,omitempty" name:"Total"` + + // 当前页码(从1开始) + Page *int64 `json:"Page,omitnil,omitempty" name:"Page"` + + // 页数 + PageSize *int64 `json:"PageSize,omitnil,omitempty" name:"PageSize"` + + // 总页数 + TotalPages *int64 `json:"TotalPages,omitnil,omitempty" name:"TotalPages"` + + // 镜像列表 + Items []*ImageDto `json:"Items,omitnil,omitempty" name:"Items"` + + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 + RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` +} + +type ListImagesResponse struct { + *tchttp.BaseResponse + Response *ListImagesResponseParams `json:"Response"` +} + +func (r *ListImagesResponse) ToJsonString() string { + b, _ := json.Marshal(r) + return string(b) +} + +// FromJsonString It is highly **NOT** recommended to use this function +// because it has no param check, nor strict type check +func (r *ListImagesResponse) FromJsonString(s string) error { + return json.Unmarshal([]byte(s), &r) +} + // Predefined struct for user type ListInferenceEnginesRequestParams struct { //

当前页码

@@ -27579,6 +27821,10 @@ type ResourceSaleInfo struct { //

最大资源数量,仅GU有值

// 注意:此字段可能返回 null,表示取不到有效值。 MaxSpec *int64 `json:"MaxSpec,omitnil,omitempty" name:"MaxSpec"` + + //

库存情况,对当前地域该计费项实时可新增数量的分级预估。取值复用 BcpConstants 库存状态常量:

  • EnoughStock:余量充足
  • NormalStock:余量正常
  • UnderStock:余量紧张
  • WithoutStock:无库存

该值为底层提供的预估值,不代表保证可发货量,仅用于展示库存概况。当请求 Region 与资源池地域不一致、cold-start 缓存未 ready、或该计费项在快照中缺失时返回 null。

+ // 注意:此字段可能返回 null,表示取不到有效值。 + StatusCategory *string `json:"StatusCategory,omitnil,omitempty" name:"StatusCategory"` } type ResourceSpec struct { @@ -27801,6 +28047,10 @@ type RestartInferenceServiceResponseParams struct { //

资源配置(JSON 字符串,取自第一个部署)

ResourceConfig *string `json:"ResourceConfig,omitnil,omitempty" name:"ResourceConfig"` + //

系统标签列表(TagKey-TagValue)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -29198,6 +29448,16 @@ type StopInferenceServiceResponseParams struct { //

资源配置(JSON 字符串,取自第一个部署)

ResourceConfig *string `json:"ResourceConfig,omitnil,omitempty" name:"ResourceConfig"` + //

系统标签列表(TagKey-TagValue)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + + //

部署模式

+ DeploymentMode *string `json:"DeploymentMode,omitnil,omitempty" name:"DeploymentMode"` + + //

是否为自定义代码部署

+ IsCustom *bool `json:"IsCustom,omitnil,omitempty" name:"IsCustom"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -29727,6 +29987,40 @@ type TCHouseD struct { AccessInfo *string `json:"AccessInfo,omitnil,omitempty" name:"AccessInfo"` } +type TCHousePInfo struct { + //

实例id

+ // 注意:此字段可能返回 null,表示取不到有效值。 + InstanceId *string `json:"InstanceId,omitnil,omitempty" name:"InstanceId"` + + //

实例名称

+ // 注意:此字段可能返回 null,表示取不到有效值。 + InstanceName *string `json:"InstanceName,omitnil,omitempty" name:"InstanceName"` + + //

JdbcUrl

+ // 注意:此字段可能返回 null,表示取不到有效值。 + JdbcUrl *string `json:"JdbcUrl,omitnil,omitempty" name:"JdbcUrl"` + + //

用户名

+ // 注意:此字段可能返回 null,表示取不到有效值。 + User *string `json:"User,omitnil,omitempty" name:"User"` + + //

密码

+ // 注意:此字段可能返回 null,表示取不到有效值。 + Password *string `json:"Password,omitnil,omitempty" name:"Password"` + + //

地址

+ // 注意:此字段可能返回 null,表示取不到有效值。 + Location *DatasourceConnectionLocation `json:"Location,omitnil,omitempty" name:"Location"` + + //

数据库名称

+ // 注意:此字段可能返回 null,表示取不到有效值。 + DbName *string `json:"DbName,omitnil,omitempty" name:"DbName"` + + //

地址信息

+ // 注意:此字段可能返回 null,表示取不到有效值。 + AccessInfo *string `json:"AccessInfo,omitnil,omitempty" name:"AccessInfo"` +} + type TColumn struct { // 字段名称 Name *string `json:"Name,omitnil,omitempty" name:"Name"` @@ -31138,6 +31432,9 @@ type UpdateInferenceModelRequestParams struct { //

模型标签列表(可选)

Tags []*string `json:"Tags,omitnil,omitempty" name:"Tags"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` } type UpdateInferenceModelRequest struct { @@ -31157,6 +31454,9 @@ type UpdateInferenceModelRequest struct { //

模型标签列表(可选)

Tags []*string `json:"Tags,omitnil,omitempty" name:"Tags"` + + //

系统标签列表(TagKey-TagValue)

+ ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` } func (r *UpdateInferenceModelRequest) ToJsonString() string { @@ -31176,6 +31476,7 @@ func (r *UpdateInferenceModelRequest) FromJsonString(s string) error { delete(f, "Description") delete(f, "ParameterSize") delete(f, "Tags") + delete(f, "ResourceTags") if len(f) > 0 { return tcerr.NewTencentCloudSDKError("ClientError.BuildRequestError", "UpdateInferenceModelRequest has unknown keys!", "") } @@ -31244,6 +31545,10 @@ type UpdateInferenceModelResponseParams struct { //

SUB UIN

SubAccountUin *string `json:"SubAccountUin,omitnil,omitempty" name:"SubAccountUin"` + //

系统标签列表(TagKey-TagValue)

+ // 注意:此字段可能返回 null,表示取不到有效值。 + ResourceTags []*Tag `json:"ResourceTags,omitnil,omitempty" name:"ResourceTags"` + // 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 RequestId *string `json:"RequestId,omitnil,omitempty" name:"RequestId"` } @@ -31748,15 +32053,15 @@ type UpdateLabRequestParams struct { //

数据实验室名称

Name *string `json:"Name,omitnil,omitempty" name:"Name"` + //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

+ Image *string `json:"Image,omitnil,omitempty" name:"Image"` + //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` //

数据实验室描述

Description *string `json:"Description,omitnil,omitempty" name:"Description"` - //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

- Image *string `json:"Image,omitnil,omitempty" name:"Image"` - //

镜像拉取策略(Always, IfNotPresent, Never)

ImagePullPolicy *string `json:"ImagePullPolicy,omitnil,omitempty" name:"ImagePullPolicy"` @@ -31806,15 +32111,15 @@ type UpdateLabRequest struct { //

数据实验室名称

Name *string `json:"Name,omitnil,omitempty" name:"Name"` + //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

+ Image *string `json:"Image,omitnil,omitempty" name:"Image"` + //

Lab 镜像地址(必填,用于开发工具如 Jupyter/VSCode/WebShell)。前端在"内置 / 自定义"两态中选择此值;当 Image 字段未显式传入时,后端会基于该字段按 R1(镜像表命中)/R2(同值 fallback)派生 Ray 集群镜像。

LabImage *string `json:"LabImage,omitnil,omitempty" name:"LabImage"` //

数据实验室描述

Description *string `json:"Description,omitnil,omitempty" name:"Description"` - //

Ray 集群镜像地址(可选,OpenAPI/SDK 高级控制入口)。前端不再传递此字段;为空时后端按 R1(镜像表查询命中)→ R2(同值 fallback)顺序自动派生。非空时直接作为 Ray 集群镜像,跳过派生(EXPLICIT),且后端不校验其与 LabImage 的兼容性。

- Image *string `json:"Image,omitnil,omitempty" name:"Image"` - //

镜像拉取策略(Always, IfNotPresent, Never)

ImagePullPolicy *string `json:"ImagePullPolicy,omitnil,omitempty" name:"ImagePullPolicy"` @@ -31871,9 +32176,9 @@ func (r *UpdateLabRequest) FromJsonString(s string) error { return err } delete(f, "Name") + delete(f, "Image") delete(f, "LabImage") delete(f, "Description") - delete(f, "Image") delete(f, "ImagePullPolicy") delete(f, "ResourceConfigId") delete(f, "GroupId") diff --git a/vendor/modules.txt b/vendor/modules.txt index cf8af01847..7aa79ab650 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1306,7 +1306,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dc/v20180410 # github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dcdb v1.0.673 ## explicit; go 1.14 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dcdb/v20180411 -# github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.156 +# github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc v1.3.170 ## explicit; go 1.14 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dlc/v20210125 # github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.124 diff --git a/website/docs/r/dlc_internal_table.html.markdown b/website/docs/r/dlc_internal_table.html.markdown new file mode 100644 index 0000000000..3aa1a20407 --- /dev/null +++ b/website/docs/r/dlc_internal_table.html.markdown @@ -0,0 +1,306 @@ +--- +subcategory: "Data Lake Compute(DLC)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_dlc_internal_table" +sidebar_current: "docs-tencentcloud-resource-dlc_internal_table" +description: |- + Provides a resource to create a DLC internal table +--- + +# tencentcloud_dlc_internal_table + +Provides a resource to create a DLC internal table + +## Example Usage + +### Create a basic internal table with columns + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_table" + table_comment = "terraform test table" + type = "TABLE" + table_format = "hive" + columns { + name = "id" + type = "bigint" + comment = "id column" + } + columns { + name = "name" + type = "string" + comment = "name column" + } + properties { + key = "format" + value = "TEXTFILE" + } +} +``` + +### Create an Iceberg internal table with smart policy + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_iceberg_table" + table_comment = "terraform iceberg test table" + type = "TABLE" + table_format = "iceberg" + primary_keys = ["id"] + columns { + name = "id" + type = "bigint" + comment = "id column" + not_null = true + } + columns { + name = "name" + type = "string" + comment = "name column" + } + smart_policy { + base_info { + uin = "100012345678" + policy_type = "Table" + catalog = "DataLakeCatalog" + database = "tf_example_database" + table = "tf_example_iceberg_table" + app_id = "1300123456" + } + policy { + inherit = "false" + lifecycle { + lifecycle_enable = "enable" + expiration = 30 + expired_field = "dt" + expired_field_format = "yyyy-MM-dd" + } + table_expiration { + enabled = true + expiration = 90 + } + } + } +} +``` + +### Create a table with partitions + +```hcl +resource "tencentcloud_dlc_internal_table" "example" { + database_name = "tf_example_database" + table_name = "tf_example_partitioned_table" + table_comment = "terraform partitioned test table" + type = "TABLE" + table_format = "hive" + columns { + name = "id" + type = "bigint" + } + columns { + name = "name" + type = "string" + } + partitions { + name = "dt" + type = "string" + comment = "date partition" + } + properties { + key = "format" + value = "PARQUET" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `columns` - (Required, List, ForceNew) Column information of the table. +* `database_name` - (Required, String, ForceNew) The name of the database to which the internal table belongs. +* `table_name` - (Required, String, ForceNew) The name of the internal table. +* `datasource_connection_name` - (Optional, String) The name of the datasource connection to which the table belongs. +* `db_govern_policy_is_disable` - (Optional, String) Whether the database data governance is disabled. true: disabled, false: enabled. Deprecated, use smart_policy instead. +* `govern_policy` - (Optional, List) Data governance policy. Deprecated, use smart_policy instead. +* `partitions` - (Optional, List, ForceNew) Partition information of the table. +* `primary_keys` - (Optional, List: [`String`], ForceNew) Primary keys of the T-ICEBERG table. +* `properties` - (Optional, List, ForceNew) Property information of the table. +* `smart_policy` - (Optional, List) Smart data governance policy. +* `table_comment` - (Optional, String) The comment of the table. +* `table_format` - (Optional, String) The format of the table, such as hive, iceberg, etc. +* `type` - (Optional, String) The type of the table, table or view. +* `upsert_keys` - (Optional, List: [`String`], ForceNew) Upsert keys for V2 upsert table. +* `user_alias` - (Optional, String) The alias of the user who creates the table. +* `user_sub_uin` - (Optional, String) The sub UIN of the user who creates the table. + +The `advance_policy` object of `written` supports the following: + +* `before_days` - (Optional, Int) Snapshot expiration time in days. +* `compact_enable` - (Optional, String) Whether to enable compaction. +* `compact_strategy` - (Optional, String) File compaction strategy. +* `cow_compact_enable` - (Optional, String) Whether to enable COW table compaction. +* `delete_enable` - (Optional, String) Whether to enable history data cleanup. +* `expired_snapshots_interval_min` - (Optional, Int) Snapshot expiration execution interval in minutes. +* `min_input_files` - (Optional, Int) The minimum number of files to trigger compaction. +* `remove_orphan_interval_min` - (Optional, Int) Orphan file removal execution interval in minutes. +* `retain_last` - (Optional, Int) Number of snapshots to retain. +* `sort_orders` - (Optional, List) Sort compaction strategy rules. +* `target_file_size_bytes` - (Optional, Int) Target file size in bytes for compaction. + +The `base_info` object of `smart_policy` supports the following: + +* `uin` - (Required, String) User UIN. +* `app_id` - (Optional, String) User APP ID. +* `catalog` - (Optional, String) Catalog name. +* `database` - (Optional, String) Database name. +* `policy_type` - (Optional, String) Policy type: Catalog/Database/Table. +* `table` - (Optional, String) Table name. + +The `change_table` object of `policy` supports the following: + +* `data_retention_time` - (Optional, Int) Data retention time in days for the change table. + +The `columns` object supports the following: + +* `name` - (Required, String) Column name. +* `type` - (Required, String) Column type. +* `comment` - (Optional, String) Column comment. +* `default` - (Optional, String) Column default value. +* `is_partition` - (Optional, Bool) Whether the column is a partition field. +* `not_null` - (Optional, Bool) Whether the column is not null. +* `position` - (Optional, Int) Column position, smaller is earlier. +* `precision` - (Optional, Int) The precision of the numeric type. +* `scale` - (Optional, Int) The scale of the numeric type. + +The `data_mask_strategy_info` object of `columns` supports the following: + + +The `favor` object of `resources` supports the following: + +* `catalog` - (Optional, String) Catalog name. +* `data_base` - (Optional, String) Database name. +* `priority` - (Optional, Int) Priority. +* `table` - (Optional, String) Table name. + +The `govern_policy` object supports the following: + +* `govern_engine` - (Optional, String) Governance engine. +* `rule_type` - (Optional, String) Governance rule type. Customize: custom; Intelligence: intelligent governance. + +The `index` object of `policy` supports the following: + +* `index_enable` - (Optional, String) Whether to enable index. + +The `lifecycle` object of `policy` supports the following: + +* `drop_table` - (Optional, Bool) Whether to drop the table. Deprecated, use table_expiration instead. +* `expiration` - (Optional, Int) Expiration time. +* `expired_field_format` - (Optional, String) Expired field format. +* `expired_field` - (Optional, String) Expired field. +* `lifecycle_enable` - (Optional, String) Whether lifecycle is enabled. + +The `partitions` object supports the following: + +* `comment` - (Optional, String) Partition comment. +* `name` - (Optional, String) Partition column name. +* `transform_args` - (Optional, List) Transform strategy arguments. +* `transform` - (Optional, String) Implicit partition transform strategy. +* `type` - (Optional, String) Partition type. + +The `policy` object of `smart_policy` supports the following: + +* `change_table` - (Optional, List) Change table policy. +* `index` - (Optional, List) Index policy. +* `inherit` - (Optional, String) Whether to inherit. +* `lifecycle` - (Optional, List) Data lifecycle policy. +* `resources` - (Optional, List) Data governance resources. +* `table_expiration` - (Optional, List) Table expiration policy. +* `written` - (Optional, List) Data rewrite policy. + +The `properties` object supports the following: + +* `key` - (Required, String) Property key. +* `value` - (Required, String) Property value. + +The `resource_conf` object of `resources` supports the following: + +* `parallelism` - (Optional, Int) The parallelism of the optimization task. + +The `resources` object of `policy` supports the following: + +* `attribution_type` - (Optional, String) Attribution type. +* `favor` - (Optional, List) Affinity info list. +* `instance` - (Optional, String) Instance name. +* `name` - (Optional, String) Engine name. +* `resource_conf` - (Optional, List) Resource configuration. +* `resource_group_name` - (Optional, String) Standard engine resource group name. +* `resource_type` - (Optional, String) Resource type. +* `status` - (Optional, Int) Status. + +The `smart_policy` object supports the following: + +* `base_info` - (Optional, List) Base info of the smart policy. +* `policy` - (Optional, List) Smart optimizer policy. + +The `sort_orders` object of `advance_policy` supports the following: + +* `column` - (Optional, String) Column name for sorting. +* `null_order` - (Optional, String) Null order: at the beginning or end. +* `sort_direction` - (Optional, String) Sort direction: ascending or descending. + +The `table_expiration` object of `policy` supports the following: + +* `enabled` - (Required, Bool) Whether the policy is enabled. +* `expiration` - (Required, Int) Table expiration time in days. + +The `written` object of `policy` supports the following: + +* `advance_policy` - (Optional, List) Advanced rewrite policy. +* `written_enable` - (Optional, String) none/enable/disable/default. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. +* `create_time` - Table creation time, in ms. +* `execution` - The auto-generated SQL statement from create. +* `heat_value` - Access heat value. +* `input_format_short` - Abbreviation of InputFormat. +* `input_format` - Data format. +* `is_t_iceberg_sql` - Whether it is T-ICEBERG SQL. +* `location` - Data storage path. +* `map_materialized_view_name` - Materialized view name mapping. +* `modified_time` - Table modification time, in ms. +* `record_count` - Table row count. +* `storage_size` - Table storage size in bytes. + +The `columns` object exports the following: + +* `create_time` - Column creation time. +* `data_mask_strategy_info` - Data mask strategy info. + * `strategy_desc` - Strategy description. + * `strategy_id` - Strategy ID. + * `strategy_name` - Strategy name. + * `strategy_type` - Strategy type. + * `users` - User sub UIN list separated by semicolons. +* `modified_time` - Column modification time. +* `nullable` - Whether the column is nullable. +* `type_text` - Data field description. + +The `partitions` object exports the following: + +* `create_time` - Partition creation time. + + +## Import + +DLC internal table can be imported using the composite id (`database_name#table_name`), e.g. + +``` +terraform import tencentcloud_dlc_internal_table.example tf_example_database#tf_example_table +``` + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index b8d95e38fd..555e08f817 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -2625,6 +2625,9 @@
  • tencentcloud_dlc_datasource_house_attachment
  • +
  • + tencentcloud_dlc_internal_table +
  • tencentcloud_dlc_modify_data_engine_description_operation