From 9f6188bd31165bad66dd41b11d3c80c725cebcf5 Mon Sep 17 00:00:00 2001 From: SevenEarth <391613297@qq.com> Date: Thu, 10 Apr 2025 20:09:14 +0800 Subject: [PATCH 1/3] add --- tencentcloud/provider.go | 1 + tencentcloud/provider.md | 1 + .../services/cls/data_source_tc_cls_topics.go | 341 ++++++++++++++++++ .../services/cls/data_source_tc_cls_topics.md | 35 ++ .../cls/data_source_tc_cls_topics_test.go | 29 ++ .../services/cls/service_tencentcloud_cls.go | 71 ++++ website/docs/d/cls_topics.html.markdown | 74 ++++ website/tencentcloud.erb | 3 + 8 files changed, 555 insertions(+) create mode 100644 tencentcloud/services/cls/data_source_tc_cls_topics.go create mode 100644 tencentcloud/services/cls/data_source_tc_cls_topics.md create mode 100644 tencentcloud/services/cls/data_source_tc_cls_topics_test.go create mode 100644 website/docs/d/cls_topics.html.markdown diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index 52ac9686dc..79313e0571 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -1086,6 +1086,7 @@ func Provider() *schema.Provider { "tencentcloud_cls_machines": cls.DataSourceTencentCloudClsMachines(), "tencentcloud_cls_machine_group_configs": cls.DataSourceTencentCloudClsMachineGroupConfigs(), "tencentcloud_cls_logsets": cls.DataSourceTencentCloudClsLogsets(), + "tencentcloud_cls_topics": cls.DataSourceTencentCloudClsTopics(), "tencentcloud_eb_search": eb.DataSourceTencentCloudEbSearch(), "tencentcloud_eb_bus": eb.DataSourceTencentCloudEbBus(), "tencentcloud_eb_event_rules": eb.DataSourceTencentCloudEbEventRules(), diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index 866af6d5a9..f8b1d7b12f 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -1428,6 +1428,7 @@ tencentcloud_cls_shipper_tasks tencentcloud_cls_machines tencentcloud_cls_machine_group_configs tencentcloud_cls_logsets +tencentcloud_cls_topics TencentCloud Lighthouse(Lighthouse) Resource diff --git a/tencentcloud/services/cls/data_source_tc_cls_topics.go b/tencentcloud/services/cls/data_source_tc_cls_topics.go new file mode 100644 index 0000000000..c67aba6fa9 --- /dev/null +++ b/tencentcloud/services/cls/data_source_tc_cls_topics.go @@ -0,0 +1,341 @@ +package cls + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + clsv20201016 "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cls/v20201016" + + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func DataSourceTencentCloudClsTopics() *schema.Resource { + return &schema.Resource{ + Read: dataSourceTencentCloudClsTopicsRead, + Schema: map[string]*schema.Schema{ + "filters": { + Type: schema.TypeList, + Optional: true, + Description: "
  • topicName: Filter by **log topic name**. Fuzzy match is implemented by default. You can use the `PreciseSearch` parameter to set exact match. Type: String. Required. No.
  • logsetName: Filter by **logset name**. Fuzzy match is implemented by default. You can use the `PreciseSearch` parameter to set exact match. Type: String. Required: No.
  • topicId: Filter by **log topic ID**. Type: String. Required: No.
  • logsetId: Filter by **logset ID**. You can call `DescribeLogsets` to query the list of created logsets or log in to the console to view them. You can also call `CreateLogset` to create a logset. Type: String. Required: No.
  • tagKey: Filter by **tag key**. Type: String. Required: No.
  • tag:tagKey: Filter by **tag key-value pair**. The `tagKey` should be replaced with a specified tag key, such as `tag:exampleKey`. Type: String. Required: No.
  • storageType: Filter by **log topic storage type**. Valid values: `hot` (standard storage) and `cold` (IA storage). Type: String. Required: No. Each request can have up to 10 `Filters` and 100 `Filter.Values`.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + Description: "Field to be filtered.", + }, + "values": { + Type: schema.TypeSet, + Required: true, + Description: "Value to be filtered.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "precise_search": { + Type: schema.TypeInt, + Optional: true, + Description: "Match mode for `Filters` fields.\n- 0: Fuzzy match for `topicName` and `logsetName`. This is the default value.\n- 1: Exact match for `topicName`.\n- 2: Exact match for `logsetName`.\n- 3: Exact match for `topicName` and `logsetName`.", + }, + + "biz_type": { + Type: schema.TypeInt, + Optional: true, + Description: "Topic type\n- 0 (default): Log topic.\n- 1: Metric topic.", + }, + + "topics": { + Type: schema.TypeList, + Computed: true, + Description: "Log topic list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "logset_id": { + Type: schema.TypeString, + Required: true, + Description: "Logset ID.", + }, + "topic_id": { + Type: schema.TypeString, + Required: true, + Description: "Topic ID.", + }, + "topic_name": { + Type: schema.TypeString, + Required: true, + Description: "Topic Name.", + }, + "partition_count": { + Type: schema.TypeInt, + Required: true, + Description: "Number of topic partitions.", + }, + "index": { + Type: schema.TypeBool, + Required: true, + Description: "Whether the topic has indexing enabled (the topic type must be log topic).", + }, + "assumer_name": { + Type: schema.TypeString, + Required: true, + Description: "Cloud product identifier. When the topic is created by other cloud products, this field displays the name of the cloud product, such as CDN, TKE.Note: This field may return null, indicating that no valid values can be obtained.", + }, + "create_time": { + Type: schema.TypeString, + Required: true, + Description: "Creation time.", + }, + "status": { + Type: schema.TypeBool, + Required: true, + Description: "Whether the topic has log collection enabled. true: collection enabled; false: collection disabled.Log collection is enabled by default when creating a log topic, and this field can be modified by calling ModifyTopic through the SDK.The console currently does not support modifying this parameter.", + }, + "tags": { + Type: schema.TypeList, + Required: true, + Description: "Tag information bound to the topicNote: This field may return null, indicating that no valid values can be obtained.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + Description: "The tag key.\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + "value": { + Type: schema.TypeString, + Required: true, + Description: "The tag value.\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + }, + }, + }, + "auto_split": { + Type: schema.TypeBool, + Required: true, + Description: "Whether automatic split is enabled for this topic\nNote: this field may return `null`, indicating that no valid values can be obtained.", + }, + "max_split_partitions": { + Type: schema.TypeInt, + Required: true, + Description: "Maximum number of partitions to split into for this topic if automatic split is enabled\nNote: this field may return `null`, indicating that no valid values can be obtained.", + }, + "storage_type": { + Type: schema.TypeString, + Required: true, + Description: "Storage type of the topicNote: This field may return null, indicating that no valid values can be obtained.", + }, + "period": { + Type: schema.TypeInt, + Required: true, + Description: "Lifecycle in days. Value range: 1-3600 (3640 indicates permanent retention)\nNote: This field may return `null`, indicating that no valid value was found.", + }, + "sub_assumer_name": { + Type: schema.TypeString, + Required: true, + Description: "Cloud product sub-identifier. If the log topic is created by another cloud product, this field returns the name of the cloud product and its log type, such as `TKE-Audit` or `TKE-Event`. Some products only return the cloud product identifier (`AssumerName`), without this field.\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + "describes": { + Type: schema.TypeString, + Required: true, + Description: "Topic description\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + "hot_period": { + Type: schema.TypeInt, + Required: true, + Description: "Enable log sinking, with the lifecycle of standard storage, where hotPeriod < Period.For standard storage, hotPeriod is used, and for infrequent access storage, it is Period-hotPeriod. (The topic type must be a log topic)HotPeriod=0 indicates that log sinking is not enabled.\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + "biz_type": { + Type: schema.TypeInt, + Required: true, + Description: "Topic type.\n- 0: log Topic \n- 1: Metric Topic\nNote: This field may return null, indicating that no valid values can be obtained.", + }, + "is_web_tracking": { + Type: schema.TypeBool, + Required: true, + Description: "Free authentication switch. false: disabled; true: enabled.After enabling, anonymous access to the log topic will be supported for specified operations. For details, please refer to Log Topic (https://intl.cloud.tencent.com/document/product/614/41035?from_cn_redirect=1).Note: This field may return null, indicating that no valid values can be obtained.", + }, + }, + }, + }, + + "result_output_file": { + Type: schema.TypeString, + Optional: true, + Description: "Used to save results.", + }, + }, + } +} + +func dataSourceTencentCloudClsTopicsRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("data_source.tencentcloud_cls_topics.read")() + defer tccommon.InconsistentCheck(d, meta)() + + var ( + logId = tccommon.GetLogId(nil) + ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + service = ClsService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + ) + + paramMap := make(map[string]interface{}) + if v, ok := d.GetOk("filters"); ok { + filtersSet := v.([]interface{}) + tmpSet := make([]*clsv20201016.Filter, 0, len(filtersSet)) + for _, item := range filtersSet { + filtersMap := item.(map[string]interface{}) + filter := clsv20201016.Filter{} + if v, ok := filtersMap["key"].(string); ok && v != "" { + filter.Key = helper.String(v) + } + + if v, ok := filtersMap["values"]; ok { + valuesSet := v.(*schema.Set).List() + for i := range valuesSet { + values := valuesSet[i].(string) + filter.Values = append(filter.Values, helper.String(values)) + } + } + + tmpSet = append(tmpSet, &filter) + } + + paramMap["Filters"] = tmpSet + } + + if v, ok := d.GetOkExists("precise_search"); ok { + paramMap["PreciseSearch"] = helper.IntUint64(v.(int)) + } + + if v, ok := d.GetOkExists("biz_type"); ok { + paramMap["BizType"] = helper.IntUint64(v.(int)) + } + + var respData []*clsv20201016.TopicInfo + reqErr := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + result, e := service.DescribeClsTopicsByFilter(ctx, paramMap) + if e != nil { + return tccommon.RetryError(e) + } + + respData = result + return nil + }) + + if reqErr != nil { + return reqErr + } + + ids := make([]string, 0, len(respData)) + topicsList := make([]map[string]interface{}, 0, len(respData)) + if respData != nil { + for _, topics := range respData { + topicsMap := map[string]interface{}{} + if topics.LogsetId != nil { + topicsMap["logset_id"] = topics.LogsetId + } + + if topics.TopicId != nil { + topicsMap["topic_id"] = topics.TopicId + ids = append(ids, *topics.TopicId) + } + + if topics.TopicName != nil { + topicsMap["topic_name"] = topics.TopicName + } + + if topics.PartitionCount != nil { + topicsMap["partition_count"] = topics.PartitionCount + } + + if topics.Index != nil { + topicsMap["index"] = topics.Index + } + + if topics.AssumerName != nil { + topicsMap["assumer_name"] = topics.AssumerName + } + + if topics.CreateTime != nil { + topicsMap["create_time"] = topics.CreateTime + } + + if topics.Status != nil { + topicsMap["status"] = topics.Status + } + + tagsList := make([]map[string]interface{}, 0, len(topics.Tags)) + if topics.Tags != nil { + for _, tags := range topics.Tags { + tagsMap := map[string]interface{}{} + if tags.Key != nil { + tagsMap["key"] = tags.Key + } + + if tags.Value != nil { + tagsMap["value"] = tags.Value + } + + tagsList = append(tagsList, tagsMap) + } + + topicsMap["tags"] = tagsList + } + + if topics.AutoSplit != nil { + topicsMap["auto_split"] = topics.AutoSplit + } + + if topics.MaxSplitPartitions != nil { + topicsMap["max_split_partitions"] = topics.MaxSplitPartitions + } + + if topics.StorageType != nil { + topicsMap["storage_type"] = topics.StorageType + } + + if topics.Period != nil { + topicsMap["period"] = topics.Period + } + + if topics.SubAssumerName != nil { + topicsMap["sub_assumer_name"] = topics.SubAssumerName + } + + if topics.Describes != nil { + topicsMap["describes"] = topics.Describes + } + + if topics.HotPeriod != nil { + topicsMap["hot_period"] = topics.HotPeriod + } + + if topics.BizType != nil { + topicsMap["biz_type"] = topics.BizType + } + + if topics.IsWebTracking != nil { + topicsMap["is_web_tracking"] = topics.IsWebTracking + } + + topicsList = append(topicsList, topicsMap) + } + + _ = d.Set("topics", topicsList) + } + + d.SetId(helper.DataResourceIdsHash(ids)) + output, ok := d.GetOk("result_output_file") + if ok && output.(string) != "" { + if e := tccommon.WriteToFile(output.(string), topicsList); e != nil { + return e + } + } + + return nil +} diff --git a/tencentcloud/services/cls/data_source_tc_cls_topics.md b/tencentcloud/services/cls/data_source_tc_cls_topics.md new file mode 100644 index 0000000000..1ae3b2f2da --- /dev/null +++ b/tencentcloud/services/cls/data_source_tc_cls_topics.md @@ -0,0 +1,35 @@ +Use this data source to query detailed information of CLS topics + +Example Usage + +Query all topics + +```hcl +data "tencentcloud_cls_topics" "example" {} +``` + +Query topics by filters + +```hcl +data "tencentcloud_cls_topics" "example" { + filters { + key = "topicId" + values = ["88babc9b-ab8f-4dd1-9b04-3e2925cf9c4c"] + } + + filters { + key = "topicName" + values = ["tf-example"] + } + + filters { + key = "logsetId" + values = ["3e8e0521-32db-4532-beeb-9beefa56d3ea"] + } + + filters { + key = "storageType" + values = ["hot"] + } +} +``` diff --git a/tencentcloud/services/cls/data_source_tc_cls_topics_test.go b/tencentcloud/services/cls/data_source_tc_cls_topics_test.go new file mode 100644 index 0000000000..06a74e3cfc --- /dev/null +++ b/tencentcloud/services/cls/data_source_tc_cls_topics_test.go @@ -0,0 +1,29 @@ +package cls_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" +) + +func TestAccTencentCloudClsTopicsDataSource_basic(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + tcacctest.AccPreCheck(t) + }, + Providers: tcacctest.AccProviders, + Steps: []resource.TestStep{{ + Config: testAccClsTopicsDataSource, + Check: resource.ComposeTestCheckFunc( + tcacctest.AccCheckTencentCloudDataSourceID("data.tencentcloud_cls_topics.example"), + ), + }}, + }) +} + +const testAccClsTopicsDataSource = ` +data "tencentcloud_cls_topics" "example" {} +` diff --git a/tencentcloud/services/cls/service_tencentcloud_cls.go b/tencentcloud/services/cls/service_tencentcloud_cls.go index 69ceb508d6..6eb08fbedf 100644 --- a/tencentcloud/services/cls/service_tencentcloud_cls.go +++ b/tencentcloud/services/cls/service_tencentcloud_cls.go @@ -1510,3 +1510,74 @@ func (me *ClsService) DescribeClsWebCallbackById(ctx context.Context, webCallbac ret = response.Response.WebCallbacks[0] return } + +func (me *ClsService) DescribeClsTopicsByFilter(ctx context.Context, param map[string]interface{}) (ret []*cls.TopicInfo, errRet error) { + var ( + logId = tccommon.GetLogId(ctx) + request = cls.NewDescribeTopicsRequest() + response = cls.NewDescribeTopicsResponse() + ) + + 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()) + } + }() + + for k, v := range param { + if k == "Filters" { + request.Filters = v.([]*cls.Filter) + } + + if k == "PreciseSearch" { + request.PreciseSearch = v.(*uint64) + } + + if k == "BizType" { + request.BizType = v.(*uint64) + } + } + + ratelimit.Check(request.GetAction()) + + var ( + offset int64 = 0 + limit int64 = 100 + ) + + for { + request.Offset = &offset + request.Limit = &limit + err := resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + ratelimit.Check(request.GetAction()) + result, e := me.client.UseClsClient().DescribeTopics(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()) + } + + response = result + return nil + }) + + if err != nil { + errRet = err + return + } + + if response == nil || len(response.Response.Topics) < 1 { + break + } + + ret = append(ret, response.Response.Topics...) + if len(response.Response.Topics) < int(limit) { + break + } + + offset += limit + } + + return +} diff --git a/website/docs/d/cls_topics.html.markdown b/website/docs/d/cls_topics.html.markdown new file mode 100644 index 0000000000..78352ba714 --- /dev/null +++ b/website/docs/d/cls_topics.html.markdown @@ -0,0 +1,74 @@ +--- +subcategory: "Cloud Log Service(CLS)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_cls_topics" +sidebar_current: "docs-tencentcloud-datasource-cls_topics" +description: |- + Use this data source to query detailed information of CLS topics +--- + +# tencentcloud_cls_topics + +Use this data source to query detailed information of CLS topics + +## Example Usage + +### Query all topics + +```hcl +data "tencentcloud_cls_topics" "example" {} +``` + +### Query topics by filters + +```hcl +data "tencentcloud_cls_topics" "example" { + filters { + key = "topicId" + values = ["88babc9b-ab8f-4dd1-9b04-3e2925cf9c4c"] + } + + filters { + key = "topicName" + values = ["tf-example"] + } + + filters { + key = "logsetId" + values = ["3e8e0521-32db-4532-beeb-9beefa56d3ea"] + } + + filters { + key = "storageType" + values = ["hot"] + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `biz_type` - (Optional, Int) Topic type +- 0 (default): Log topic. +- 1: Metric topic. +* `filters` - (Optional, List)
  • topicName: Filter by **log topic name**. Fuzzy match is implemented by default. You can use the `PreciseSearch` parameter to set exact match. Type: String. Required. No.
  • logsetName: Filter by **logset name**. Fuzzy match is implemented by default. You can use the `PreciseSearch` parameter to set exact match. Type: String. Required: No.
  • topicId: Filter by **log topic ID**. Type: String. Required: No.
  • logsetId: Filter by **logset ID**. You can call `DescribeLogsets` to query the list of created logsets or log in to the console to view them. You can also call `CreateLogset` to create a logset. Type: String. Required: No.
  • tagKey: Filter by **tag key**. Type: String. Required: No.
  • tag:tagKey: Filter by **tag key-value pair**. The `tagKey` should be replaced with a specified tag key, such as `tag:exampleKey`. Type: String. Required: No.
  • storageType: Filter by **log topic storage type**. Valid values: `hot` (standard storage) and `cold` (IA storage). Type: String. Required: No. Each request can have up to 10 `Filters` and 100 `Filter.Values`. +* `precise_search` - (Optional, Int) Match mode for `Filters` fields. +- 0: Fuzzy match for `topicName` and `logsetName`. This is the default value. +- 1: Exact match for `topicName`. +- 2: Exact match for `logsetName`. +- 3: Exact match for `topicName` and `logsetName`. +* `result_output_file` - (Optional, String) Used to save results. + +The `filters` object supports the following: + +* `key` - (Required, String) Field to be filtered. +* `values` - (Required, Set) Value to be filtered. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `topics` - Log topic list. + + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index c92609db70..8cdab7a35d 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -1535,6 +1535,9 @@
  • tencentcloud_cls_shipper_tasks
  • +
  • + tencentcloud_cls_topics +
  • From ffb118bc268b852138e2d450f59fcd600096ed38 Mon Sep 17 00:00:00 2001 From: SevenEarth <391613297@qq.com> Date: Thu, 10 Apr 2025 20:11:11 +0800 Subject: [PATCH 2/3] add --- .changelog/3291.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/3291.txt diff --git a/.changelog/3291.txt b/.changelog/3291.txt new file mode 100644 index 0000000000..ced54282b5 --- /dev/null +++ b/.changelog/3291.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +tencentcloud_cls_topics +``` \ No newline at end of file From b9df6b1fbf799c5dd4cdefd74bb8a654f2256db1 Mon Sep 17 00:00:00 2001 From: SevenEarth <391613297@qq.com> Date: Fri, 11 Apr 2025 17:57:10 +0800 Subject: [PATCH 3/3] add --- tencentcloud/services/cls/data_source_tc_cls_topics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tencentcloud/services/cls/data_source_tc_cls_topics.go b/tencentcloud/services/cls/data_source_tc_cls_topics.go index c67aba6fa9..1a55f7b1d1 100644 --- a/tencentcloud/services/cls/data_source_tc_cls_topics.go +++ b/tencentcloud/services/cls/data_source_tc_cls_topics.go @@ -178,7 +178,7 @@ func dataSourceTencentCloudClsTopicsRead(d *schema.ResourceData, meta interface{ defer tccommon.InconsistentCheck(d, meta)() var ( - logId = tccommon.GetLogId(nil) + logId = tccommon.GetLogId(tccommon.ContextNil) ctx = tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) service = ClsService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} )