From 01e98e76c58b229aae7023127c21042dc66fd289 Mon Sep 17 00:00:00 2001 From: chenhanzhang Date: Wed, 11 Feb 2026 10:46:46 +0800 Subject: [PATCH] New Resource: alicloud_sls_metric_store. --- alicloud/provider.go | 1 + .../resource_alicloud_sls_metric_store.go | 331 ++++++++++++++++++ ...resource_alicloud_sls_metric_store_test.go | 118 +++++++ alicloud/service_alicloud_sls_v2.go | 77 ++++ website/docs/r/sls_metric_store.html.markdown | 82 +++++ 5 files changed, 609 insertions(+) create mode 100644 alicloud/resource_alicloud_sls_metric_store.go create mode 100644 alicloud/resource_alicloud_sls_metric_store_test.go create mode 100644 website/docs/r/sls_metric_store.html.markdown diff --git a/alicloud/provider.go b/alicloud/provider.go index 4fa2ded255f0..f3c0876a814c 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -915,6 +915,7 @@ func Provider() terraform.ResourceProvider { "alicloud_vpc_ipam_ipams": dataSourceAliCloudVpcIpamIpams(), }, ResourcesMap: map[string]*schema.Resource{ + "alicloud_sls_metric_store": resourceAliCloudSlsMetricStore(), "alicloud_oss_bucket_overwrite_config": resourceAliCloudOssBucketOverwriteConfig(), "alicloud_cloud_firewall_user_alarm_config": resourceAliCloudCloudFirewallUserAlarmConfig(), "alicloud_oss_bucket_archive_direct_read": resourceAliCloudOssBucketArchiveDirectRead(), diff --git a/alicloud/resource_alicloud_sls_metric_store.go b/alicloud/resource_alicloud_sls_metric_store.go new file mode 100644 index 000000000000..4381c0fbf770 --- /dev/null +++ b/alicloud/resource_alicloud_sls_metric_store.go @@ -0,0 +1,331 @@ +package alicloud + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAliCloudSlsMetricStore() *schema.Resource { + return &schema.Resource{ + Create: resourceAliCloudSlsMetricStoreCreate, + Read: resourceAliCloudSlsMetricStoreRead, + Update: resourceAliCloudSlsMetricStoreUpdate, + Delete: resourceAliCloudSlsMetricStoreDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "auto_split": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "create_time": { + Type: schema.TypeInt, + Computed: true, + }, + "hot_ttl": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: IntBetween(0, 3650), + }, + "infrequent_access_ttl": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: IntBetween(0, 3650), + }, + "max_split_shard": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: IntBetween(0, 256), + }, + "metering_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: StringInSlice([]string{"ChargeByFunction", "ChargeByDataIngest"}, false), + }, + "metric_store_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "metric_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: StringInSlice([]string{"prometheus"}, false), + }, + "mode": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: StringInSlice([]string{"standard"}, false), + }, + "project_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "shard_count": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: IntAtLeast(1), + }, + "ttl": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: IntBetween(0, 3650), + }, + }, + } +} + +func resourceAliCloudSlsMetricStoreCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + + action := fmt.Sprintf("/metricstores") + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]*string) + body := make(map[string]interface{}) + hostMap := make(map[string]*string) + var err error + request = make(map[string]interface{}) + hostMap["project"] = StringPointer(d.Get("project_name").(string)) + if v, ok := d.GetOk("metric_store_name"); ok { + request["name"] = v + } + + if v, ok := d.GetOkExists("infrequent_access_ttl"); ok && v.(int) > 0 { + request["infrequentAccessTTL"] = v + } + if v, ok := d.GetOkExists("hot_ttl"); ok && v.(int) > 0 { + request["hot_ttl"] = v + } + request["ttl"] = d.Get("ttl") + if v, ok := d.GetOk("metric_type"); ok { + request["metricType"] = v + } + if v, ok := d.GetOk("mode"); ok { + request["mode"] = v + } + if v, ok := d.GetOkExists("auto_split"); ok { + request["autoSplit"] = v + } + request["shardCount"] = d.Get("shard_count") + if v, ok := d.GetOkExists("max_split_shard"); ok { + request["maxSplitShard"] = v + } + body = request + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + response, err = client.Do("Sls", roaParam("POST", "2020-12-30", "CreateMetricStore", action), query, body, nil, hostMap, false) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, "alicloud_sls_metric_store", action, AlibabaCloudSdkGoERROR) + } + + d.SetId(fmt.Sprintf("%v:%v", *hostMap["project"], request["name"])) + + return resourceAliCloudSlsMetricStoreUpdate(d, meta) +} + +func resourceAliCloudSlsMetricStoreRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + slsServiceV2 := SlsServiceV2{client} + + objectRaw, err := slsServiceV2.DescribeSlsMetricStore(d.Id()) + if err != nil { + if !d.IsNewResource() && NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_sls_metric_store DescribeSlsMetricStore Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + + d.Set("create_time", objectRaw["createTime"]) + d.Set("max_split_shard", objectRaw["maxSplitShard"]) + d.Set("metric_type", objectRaw["metricType"]) + d.Set("mode", objectRaw["mode"]) + d.Set("shard_count", objectRaw["shardCount"]) + d.Set("ttl", objectRaw["ttl"]) + d.Set("metric_store_name", objectRaw["name"]) + + parts := strings.Split(d.Id(), ":") + d.Set("project_name", parts[0]) + + return nil +} + +func resourceAliCloudSlsMetricStoreUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var request map[string]interface{} + var response map[string]interface{} + var query map[string]*string + var body map[string]interface{} + update := false + d.Partial(true) + + var err error + parts := strings.Split(d.Id(), ":") + name := parts[1] + action := fmt.Sprintf("/metricstores/%s", name) + request = make(map[string]interface{}) + query = make(map[string]*string) + body = make(map[string]interface{}) + hostMap := make(map[string]*string) + hostMap["project"] = StringPointer(parts[0]) + + if !d.IsNewResource() && d.HasChange("infrequent_access_ttl") { + update = true + } + if v, ok := d.GetOkExists("infrequent_access_ttl"); (ok || d.HasChange("infrequent_access_ttl")) && v.(int) > 0 { + request["infrequentAccessTTL"] = v + } + if !d.IsNewResource() && d.HasChange("hot_ttl") { + update = true + } + if v, ok := d.GetOkExists("hot_ttl"); (ok || d.HasChange("hot_ttl")) && v.(int) > 0 { + request["hot_ttl"] = v + } + if !d.IsNewResource() && d.HasChange("ttl") { + update = true + } + request["ttl"] = d.Get("ttl") + if !d.IsNewResource() && d.HasChange("mode") { + update = true + } + if v, ok := d.GetOk("mode"); ok || d.HasChange("mode") { + request["mode"] = v + } + if !d.IsNewResource() && d.HasChange("auto_split") { + update = true + } + if v, ok := d.GetOkExists("auto_split"); ok || d.HasChange("auto_split") { + request["autoSplit"] = v + } + if !d.IsNewResource() && d.HasChange("max_split_shard") { + update = true + } + if v, ok := d.GetOkExists("max_split_shard"); ok || d.HasChange("max_split_shard") { + request["maxSplitShard"] = v + } + body = request + if update { + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.Do("Sls", roaParam("PUT", "2020-12-30", "UpdateMetricStore", action), query, body, nil, hostMap, false) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + } + update = false + parts = strings.Split(d.Id(), ":") + metricStore := parts[1] + action = fmt.Sprintf("/metricstores/%s/meteringmode", metricStore) + request = make(map[string]interface{}) + query = make(map[string]*string) + body = make(map[string]interface{}) + hostMap = make(map[string]*string) + hostMap["project"] = StringPointer(parts[0]) + + if d.HasChange("metering_mode") { + update = true + } + request["meteringMode"] = d.Get("metering_mode") + body = request + if update { + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = client.Do("Sls", roaParam("PUT", "2020-12-30", "UpdateMetricStoreMeteringMode", action), query, body, nil, hostMap, false) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + } + + d.Partial(false) + return resourceAliCloudSlsMetricStoreRead(d, meta) +} + +func resourceAliCloudSlsMetricStoreDelete(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*connectivity.AliyunClient) + parts := strings.Split(d.Id(), ":") + name := parts[1] + action := fmt.Sprintf("/metricstores/%s", name) + var request map[string]interface{} + var response map[string]interface{} + query := make(map[string]*string) + hostMap := make(map[string]*string) + var err error + request = make(map[string]interface{}) + hostMap["project"] = StringPointer(parts[0]) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { + response, err = client.Do("Sls", roaParam("DELETE", "2020-12-30", "DeleteMetricStore", action), query, nil, nil, hostMap, false) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + + if err != nil { + if IsExpectedErrors(err, []string{"MetricStoreNotExist"}) || NotFoundError(err) { + return nil + } + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + + return nil +} diff --git a/alicloud/resource_alicloud_sls_metric_store_test.go b/alicloud/resource_alicloud_sls_metric_store_test.go new file mode 100644 index 000000000000..4982291c50ff --- /dev/null +++ b/alicloud/resource_alicloud_sls_metric_store_test.go @@ -0,0 +1,118 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccAliCloudSlsMetricStore_basic7939(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_sls_metric_store.default" + ra := resourceAttrInit(resourceId, AlicloudSlsMetricStoreMap7939) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &SlsServiceV2{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeSlsMetricStore") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(10000, 99999) + name := fmt.Sprintf("tfaccsls%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, AlicloudSlsMetricStoreBasicDependence7939) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckWithRegions(t, true, []connectivity.Region{"cn-hangzhou"}) + testAccPreCheck(t) + }, + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "project_name": "${alicloud_log_project.defaultj3iK32.project_name}", + "metering_mode": "ChargeByFunction", + "mode": "standard", + "metric_type": "prometheus", + "metric_store_name": name, + "ttl": "7", + "shard_count": "2", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "project_name": "sls-sdk-testp-metricstore", + "metering_mode": "ChargeByFunction", + "mode": "standard", + "metric_type": "prometheus", + "metric_store_name": name, + "ttl": "7", + "shard_count": "2", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "ttl": "10", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "ttl": "10", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "ttl": "7", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "ttl": "7", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "ttl": "10", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "ttl": "10", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{}), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{}), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"metering_mode"}, + }, + }, + }) +} + +var AlicloudSlsMetricStoreMap7939 = map[string]string{ + "create_time": CHECKSET, +} + +func AlicloudSlsMetricStoreBasicDependence7939(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} + +resource "alicloud_log_project" "defaultj3iK32" { + description = "test" + project_name = "sls-sdk-testp-metricstore" +} + + +`, name) +} diff --git a/alicloud/service_alicloud_sls_v2.go b/alicloud/service_alicloud_sls_v2.go index 9797dbd7a248..cdb16f54319f 100644 --- a/alicloud/service_alicloud_sls_v2.go +++ b/alicloud/service_alicloud_sls_v2.go @@ -974,3 +974,80 @@ func (s *SlsServiceV2) SlsScheduledSqlStateRefreshFuncWithApi(id string, field s } // DescribeSlsScheduledSql >>> Encapsulated. +// DescribeSlsMetricStore <<< Encapsulated get interface for Sls MetricStore. + +func (s *SlsServiceV2) DescribeSlsMetricStore(id string) (object map[string]interface{}, err error) { + client := s.client + var request map[string]interface{} + var response map[string]interface{} + var query map[string]*string + parts := strings.Split(id, ":") + if len(parts) != 2 { + err = WrapError(fmt.Errorf("invalid Resource Id %s. Expected parts' length %d, got %d", id, 2, len(parts))) + return nil, err + } + name := parts[1] + request = make(map[string]interface{}) + query = make(map[string]*string) + hostMap := make(map[string]*string) + hostMap["project"] = StringPointer(parts[0]) + + action := fmt.Sprintf("/metricstores/%s", name) + + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(1*time.Minute, func() *resource.RetryError { + response, err = client.Do("Sls", roaParam("GET", "2020-12-30", "GetMetricStore", action), query, nil, nil, hostMap, true) + + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + if IsExpectedErrors(err, []string{"MetricStoreNotExist"}) { + return object, WrapErrorf(NotFoundErr("MetricStore", id), NotFoundMsg, response) + } + return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) + } + + return response, nil +} + +func (s *SlsServiceV2) SlsMetricStoreStateRefreshFunc(id string, field string, failStates []string) resource.StateRefreshFunc { + return s.SlsMetricStoreStateRefreshFuncWithApi(id, field, failStates, s.DescribeSlsMetricStore) +} + +func (s *SlsServiceV2) SlsMetricStoreStateRefreshFuncWithApi(id string, field string, failStates []string, call func(id string) (map[string]interface{}, error)) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + object, err := call(id) + if err != nil { + if NotFoundError(err) { + return object, "", nil + } + return nil, "", WrapError(err) + } + v, err := jsonpath.Get(field, object) + currentStatus := fmt.Sprint(v) + + if strings.HasPrefix(field, "#") { + v, _ := jsonpath.Get(strings.TrimPrefix(field, "#"), object) + if v != nil { + currentStatus = "#CHECKSET" + } + } + + for _, failState := range failStates { + if currentStatus == failState { + return object, currentStatus, WrapError(Error(FailedToReachTargetStatus, currentStatus)) + } + } + return object, currentStatus, nil + } +} + +// DescribeSlsMetricStore >>> Encapsulated. diff --git a/website/docs/r/sls_metric_store.html.markdown b/website/docs/r/sls_metric_store.html.markdown new file mode 100644 index 000000000000..be99bec98560 --- /dev/null +++ b/website/docs/r/sls_metric_store.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Log Service (SLS)" +layout: "alicloud" +page_title: "Alicloud: alicloud_sls_metric_store" +description: |- + Provides a Alicloud Log Service (SLS) Metric Store resource. +--- + +# alicloud_sls_metric_store + +Provides a Log Service (SLS) Metric Store resource. + + + +For information about Log Service (SLS) Metric Store and how to use it, see [What is Metric Store](https://next.api.alibabacloud.com/document/Sls/2020-12-30/CreateMetricStore). + +-> **NOTE:** Available since v1.271.0. + +## Example Usage + +Basic Usage + +```terraform +variable "name" { + default = "terraform-example" +} + +provider "alicloud" { + region = "cn-hangzhou" +} + +resource "alicloud_log_project" "default" { + description = "example" + project_name = "sls-sdk-examplep-metricstore" +} + +resource "alicloud_sls_metric_store" "default" { + project_name = alicloud_log_project.default.project_name + metering_mode = "ChargeByFunction" + mode = "standard" + metric_type = "prometheus" + metric_store_name = "example-metric" + ttl = "7" + shard_count = "2" +} +``` + +## Argument Reference + +The following arguments are supported: +* `auto_split` - (Optional, Computed) Determines whether to automatically split a shard. Default to `false`. +* `hot_ttl` - (Optional, Int) The ttl of hot storage. Default to 30, at least 30, hot storage ttl must be less than ttl. +* `infrequent_access_ttl` - (Optional, Int) Low frequency storage time +* `max_split_shard` - (Optional, Int) The maximum number of shards for automatic split, which is in the range of 1 to 256. You must specify this parameter when autoSplit is true. +* `metering_mode` - (Optional, Computed) Metering mode of the metricStore, ChargeByFunction or ChargeByDataIngest +* `metric_store_name` - (Required, ForceNew) The metric store, unique in the same project. +* `metric_type` - (Optional, ForceNew, Computed) Type of metric store, defaults to prometheus. +* `mode` - (Optional, Computed) The mode of storage. Default to `standard`, must be `standard. +* `project_name` - (Required, ForceNew) The project name to the metric store belongs. +* `shard_count` - (Required, ForceNew, Int) The number of shards in the metric store. +* `ttl` - (Required, Int) Ttl for data storage, in days. + +## Attributes Reference + +The following attributes are exported: +* `id` - The ID of the resource supplied above. The value is formulated as `:`. +* `create_time` - Creation time. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts) for certain actions: +* `create` - (Defaults to 5 mins) Used when create the Metric Store. +* `delete` - (Defaults to 5 mins) Used when delete the Metric Store. +* `update` - (Defaults to 5 mins) Used when update the Metric Store. + +## Import + +Log Service (SLS) Metric Store can be imported using the id, e.g. + +```shell +$ terraform import alicloud_sls_metric_store.example : +``` \ No newline at end of file