From 60bf7fff37ac56c1160412c54cdeb12ecc014531 Mon Sep 17 00:00:00 2001 From: Zippo-Wang <852420284@qq.com> Date: Fri, 22 Aug 2025 17:00:21 +0800 Subject: [PATCH] feat(dms): add new resource to restart nodes --- .../dms_rocketmq_node_batch_restart.md | 50 ++++++++ huaweicloud/provider.go | 5 +- ...ud_dms_rocketmq_node_batch_restart_test.go | 52 ++++++++ ...eicloud_dms_rocketmq_node_batch_restart.go | 120 ++++++++++++++++++ 4 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 docs/resources/dms_rocketmq_node_batch_restart.md create mode 100644 huaweicloud/services/acceptance/rocketmq/data_source_huaweicloud_dms_rocketmq_node_batch_restart_test.go create mode 100644 huaweicloud/services/rocketmq/resource_huaweicloud_dms_rocketmq_node_batch_restart.go diff --git a/docs/resources/dms_rocketmq_node_batch_restart.md b/docs/resources/dms_rocketmq_node_batch_restart.md new file mode 100644 index 00000000000..e68c4398067 --- /dev/null +++ b/docs/resources/dms_rocketmq_node_batch_restart.md @@ -0,0 +1,50 @@ +--- +subcategory: "Distributed Message Service (DMS)" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_dms_rocketmq_node_batch_restart" +description: |- + Using this resource to batch restart nodes of a RocketMQ instance within HuaweiCloud. +--- + +# huaweicloud_dms_rocketmq_node_batch_restart + +Using this resource to batch restart nodes of a RocketMQ instance within HuaweiCloud. + +-> This resource is only a one-time action resource for restarting nodes of RocketMQ instance. Deleting this resource +will not clear the corresponding request record, but will only remove the resource information from the tfstate file. + +## Example Usage + +```hcl +variable "instance_id" {} + +data "huaweicloud_dms_rocketmq_instance_nodes" "test" { + instance_id = var.instance_id +} + +resource "huaweicloud_dms_rocketmq_node_batch_restart" "test" { + instance_id = var.instance_id + + nodes = [ + data.huaweicloud_dms_rocketmq_instance_nodes.test.nodes[0].id, + data.huaweicloud_dms_rocketmq_instance_nodes.test.nodes[1].id + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to restart the nodes of a RocketMQ instance. + If omitted, the provider-level region will be used. Changing this parameter will create a new resource. + +* `instance_id` - (Required, String, NonUpdatable) Specifies the ID of the RocketMQ instance to which nodes belong. + +* `nodes` - (Required, List, NonUpdatable) Specifies the list of node IDs to be restarted. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 93bb6b1182f..7805a7b4351 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -2285,12 +2285,13 @@ func Provider() *schema.Provider { "huaweicloud_dms_rocketmq_instance": rocketmq.ResourceDmsRocketMQInstance(), "huaweicloud_dms_rocketmq_consumer_group": rocketmq.ResourceDmsRocketMQConsumerGroup(), "huaweicloud_dms_rocketmq_consumption_verify": rocketmq.ResourceDmsRocketMQConsumptionVerify(), + "huaweicloud_dms_rocketmq_dead_letter_resend": rocketmq.ResourceDmsRocketMQDeadLetterResend(), "huaweicloud_dms_rocketmq_message_offset_reset": rocketmq.ResourceDmsRocketMQMessageOffsetReset(), "huaweicloud_dms_rocketmq_message_send": rocketmq.ResourceRocketMQMessageSend(), - "huaweicloud_dms_rocketmq_dead_letter_resend": rocketmq.ResourceDmsRocketMQDeadLetterResend(), + "huaweicloud_dms_rocketmq_migration_task": rocketmq.ResourceDmsRocketmqMigrationTask(), + "huaweicloud_dms_rocketmq_node_batch_restart": rocketmq.ResourceNodeBatchRestart(), "huaweicloud_dms_rocketmq_topic": rocketmq.ResourceDmsRocketMQTopic(), "huaweicloud_dms_rocketmq_user": rocketmq.ResourceDmsRocketMQUser(), - "huaweicloud_dms_rocketmq_migration_task": rocketmq.ResourceDmsRocketmqMigrationTask(), "huaweicloud_dns_custom_line": dns.ResourceCustomLine(), "huaweicloud_dns_ptrrecord": dns.ResourcePtrRecord(), diff --git a/huaweicloud/services/acceptance/rocketmq/data_source_huaweicloud_dms_rocketmq_node_batch_restart_test.go b/huaweicloud/services/acceptance/rocketmq/data_source_huaweicloud_dms_rocketmq_node_batch_restart_test.go new file mode 100644 index 00000000000..33befea9b3c --- /dev/null +++ b/huaweicloud/services/acceptance/rocketmq/data_source_huaweicloud_dms_rocketmq_node_batch_restart_test.go @@ -0,0 +1,52 @@ +package rocketmq + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccNodeBatchRestart_basic(t *testing.T) { + var ( + dataSourceName = "huaweicloud_dms_rocketmq_node_batch_restart.test" + instanceID = acceptance.HW_DMS_ROCKETMQ_INSTANCE_ID + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + acceptance.TestAccPreCheckDMSRocketMQInstanceID(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccNodeBatchRestart_basic(instanceID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "instance_id", instanceID), + resource.TestCheckResourceAttr(dataSourceName, "nodes.#", "2"), + resource.TestCheckResourceAttrSet(dataSourceName, "nodes.0"), + ), + }, + }, + }) +} + +func testAccNodeBatchRestart_basic(instanceID string) string { + return fmt.Sprintf(` +data "huaweicloud_dms_rocketmq_instance_nodes" "test" { + instance_id = "%[1]s" +} + +resource "huaweicloud_dms_rocketmq_node_batch_restart" "test" { + instance_id = "%[1]s" + + nodes = [ + try(data.huaweicloud_dms_rocketmq_instance_nodes.test.nodes[0].id), + try(data.huaweicloud_dms_rocketmq_instance_nodes.test.nodes[1].id) + ] +} +`, instanceID) +} diff --git a/huaweicloud/services/rocketmq/resource_huaweicloud_dms_rocketmq_node_batch_restart.go b/huaweicloud/services/rocketmq/resource_huaweicloud_dms_rocketmq_node_batch_restart.go new file mode 100644 index 00000000000..557bb62a7b7 --- /dev/null +++ b/huaweicloud/services/rocketmq/resource_huaweicloud_dms_rocketmq_node_batch_restart.go @@ -0,0 +1,120 @@ +package rocketmq + +import ( + "context" + "strings" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +var nodeBatchRestartNonUpdatableParams = []string{"instance_id", "nodes"} + +// @API RocketMQ POST /v2/{project_id}/{engine}/instances/{instance_id}/restart +func ResourceNodeBatchRestart() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceNodeBatchRestartCreate, + ReadContext: resourceNodeBatchRestartRead, + DeleteContext: resourceNodeBatchRestartDelete, + + CustomizeDiff: customdiff.All( + config.FlexibleForceNew(nodeBatchRestartNonUpdatableParams), + ), + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + Description: `The region in which to restart the nodes of a RocketMQ instance.`, + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: `The ID of the RocketMQ instance to be restarted.`, + }, + "nodes": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The list of node names to be restarted.`, + }, + + // Internal + "enable_force_new": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"true", "false"}, false), + Description: utils.SchemaDesc("", utils.SchemaDescInput{Internal: true}), + }, + }, + } +} + +func resourceNodeBatchRestartCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + client, err := cfg.NewServiceClient("dmsv2", region) + if err != nil { + return diag.Errorf("error creating DMS client: %s", err) + } + + httpUrl := "v2/{project_id}/rocketmq/instances/{instance_id}/restart" + httpUrl = strings.ReplaceAll(httpUrl, "{project_id}", client.ProjectID) + httpUrl = strings.ReplaceAll(httpUrl, "{instance_id}", d.Get("instance_id").(string)) + restartPath := client.Endpoint + httpUrl + + nodesRaw := d.Get("nodes").([]interface{}) + nodes := make([]string, len(nodesRaw)) + for i, node := range nodesRaw { + nodes[i] = node.(string) + } + + opt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + JSONBody: map[string]interface{}{ + "nodes": nodes, + }, + } + + _, err = client.Request("POST", restartPath, &opt) + if err != nil { + return diag.Errorf("error restarting nodes of the RocketMQ instance: %s", err) + } + + randUUID, err := uuid.GenerateUUID() + if err != nil { + return diag.Errorf("unable to generate resource ID: %s", err) + } + d.SetId(randUUID) + + return resourceNodeBatchRestartRead(ctx, d, meta) +} + +func resourceNodeBatchRestartRead(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil +} + +func resourceNodeBatchRestartDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + errorMsg := `This resource is a one-time action resource used to restart nodes of a RocketMQ instance. Deleting +this resource will not clear the restart operation record, but will only remove the resource information from the +tfstate file.` + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: errorMsg, + }, + } +}