From d5edc0378c81b7e28840798ad48408a832b20ff5 Mon Sep 17 00:00:00 2001 From: shichangkuo Date: Wed, 28 Oct 2020 11:57:25 +0800 Subject: [PATCH] support tags for dds and dcs instance resource (#610) * support tags for dds instance resource * support tags for dcs instance resource --- docs/resources/dcs_instance.md | 4 +- docs/resources/dds_instance.md | 3 + .../resource_huaweicloud_dcs_instance_v1.go | 64 +++++++++++++++---- ...source_huaweicloud_dcs_instance_v1_test.go | 15 +++-- .../resource_huaweicloud_dds_instance_v3.go | 38 ++++++++++- ...source_huaweicloud_dds_instance_v3_test.go | 26 +++++--- 6 files changed, 117 insertions(+), 33 deletions(-) diff --git a/docs/resources/dcs_instance.md b/docs/resources/dcs_instance.md index cb0d9b019c..62415aa88d 100644 --- a/docs/resources/dcs_instance.md +++ b/docs/resources/dcs_instance.md @@ -47,7 +47,6 @@ resource "huaweicloud_dcs_instance" "instance_1" { begin_at = "00:00-01:00" period_type = "weekly" backup_at = [1] - depends_on = ["huaweicloud_networking_secgroup.secgroup_1"] } ``` @@ -190,6 +189,8 @@ The following arguments are supported: * `enterprise_project_id` - (Optional) The enterprise project id of the dcs instance. Changing this creates a new instance. +* `tags` - (Optional) The key/value pairs to associate with the dcs instance. + The `whitelists` block supports: * `group_name` - (Required) Specifies the name of IP address group. @@ -224,6 +225,7 @@ The following attributes are exported: * `begin_at` - See Argument Reference above. * `period_type` - See Argument Reference above. * `backup_at` - See Argument Reference above. +* `tags` - See Argument Reference above. * `order_id` - An order ID is generated only in the monthly or yearly billing mode. In other billing modes, no value is returned for this parameter. * `resource_spec_code` - Resource specifications. diff --git a/docs/resources/dds_instance.md b/docs/resources/dds_instance.md index 70fc1a1e00..41bd3b3428 100644 --- a/docs/resources/dds_instance.md +++ b/docs/resources/dds_instance.md @@ -116,6 +116,8 @@ The following arguments are supported: **Note:** The instance will be restarted in the background when switching SSL. Please operate with caution. +* `tags` - (Optional) The key/value pairs to associate with the DDS instance. + The `datastore` block supports: * `type` - (Required) Specifies the DB engine. 'DDS-Community' and 'DDS-Enhanced' are supported. @@ -184,6 +186,7 @@ The following attributes are exported: * `mode` - See Argument Reference above. * `flavor` - See Argument Reference above. * `backup_strategy` - See Argument Reference above. +* `tags` - See Argument Reference above. * `db_username` - Indicates the DB Administator name. * `status` - Indicates the the DB instance status. * `port` - Indicates the database port number. The port range is 2100 to 9500. diff --git a/huaweicloud/resource_huaweicloud_dcs_instance_v1.go b/huaweicloud/resource_huaweicloud_dcs_instance_v1.go index 8fdbc72827..5561595f49 100644 --- a/huaweicloud/resource_huaweicloud_dcs_instance_v1.go +++ b/huaweicloud/resource_huaweicloud_dcs_instance_v1.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/common/tags" "github.com/huaweicloud/golangsdk/openstack/dcs/v1/instances" "github.com/huaweicloud/golangsdk/openstack/dcs/v2/whitelists" ) @@ -148,6 +149,7 @@ func resourceDcsInstanceV1() *schema.Resource { }, }, }, + "tags": tagsSchema(), "enterprise_project_id": { Type: schema.TypeString, Optional: true, @@ -293,7 +295,7 @@ func resourceDcsInstancesV1Create(d *schema.ResourceData, meta interface{}) erro config := meta.(*Config) dcsV1Client, err := config.dcsV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating HuaweiCloud dcs instance client: %s", err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v1 client: %s", err) } if err := resourceDcsInstancesCheck(d); err != nil { @@ -351,9 +353,9 @@ func resourceDcsInstancesV1Create(d *schema.ResourceData, meta interface{}) erro d.SetId(v.InstanceID) // set whitelist - dcsV2Client, err := config.NewServiceClient("dcsv2", GetRegion(d, config)) + dcsV2Client, err := config.dcsV2Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating HuaweiCloud dcs instance client: %s", err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v2 client: %s", err) } whitelistOpts := getDcsInstanceWhitelist(d) log.Printf("[DEBUG] Create whitelist options: %#v", whitelistOpts) @@ -365,6 +367,15 @@ func resourceDcsInstancesV1Create(d *schema.ResourceData, meta interface{}) erro } } + //set tags + tagRaw := d.Get("tags").(map[string]interface{}) + if len(tagRaw) > 0 { + taglist := expandResourceTags(tagRaw) + if tagErr := tags.Create(dcsV2Client, "dcs", v.InstanceID, taglist).ExtractErr(); tagErr != nil { + return fmt.Errorf("Error setting tags of DCS instance %s: %s", v.InstanceID, tagErr) + } + } + return resourceDcsInstancesV1Read(d, meta) } @@ -373,7 +384,7 @@ func resourceDcsInstancesV1Read(d *schema.ResourceData, meta interface{}) error dcsV1Client, err := config.dcsV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating HuaweiCloud dcs instance client: %s", err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v1 client: %s", err) } v, err := instances.Get(dcsV1Client, d.Id()).Extract() if err != nil { @@ -420,7 +431,10 @@ func resourceDcsInstancesV1Read(d *schema.ResourceData, meta interface{}) error } d.Set("capacity", capacity) - dcsV2Client, err := config.NewServiceClient("dcsv2", GetRegion(d, config)) + dcsV2Client, err := config.dcsV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud dcs instance v2 client: %s", err) + } object, err := whitelists.Get(dcsV2Client, d.Id()).Extract() enable := object.Enable @@ -434,6 +448,16 @@ func resourceDcsInstancesV1Read(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error setting whitelists for DCS instance, err: %s", err) } + // set tags + resourceTags, err := tags.Get(dcsV2Client, "instances", d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error fetching tags of DCS instance: %s", err) + } + tagmap := tagsToMap(resourceTags.Tags) + if err := d.Set("tags", tagmap); err != nil { + return fmt.Errorf("[DEBUG] Error saving tag to state for DCS instance (%s): %s", d.Id(), err) + } + return nil } @@ -447,7 +471,7 @@ func resourceDcsInstancesV1Update(d *schema.ResourceData, meta interface{}) erro if d.HasChanges("name", "description", "security_group_id", "maintain_begin", "maintain_end") { dcsV1Client, err := config.dcsV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error updating HuaweiCloud dcs instance client: %s", err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v1 client: %s", err) } description := d.Get("description").(string) @@ -465,14 +489,26 @@ func resourceDcsInstancesV1Update(d *schema.ResourceData, meta interface{}) erro } } - if d.HasChange("whitelists") { - dcsV2Client, err := config.NewServiceClient("dcsv2", GetRegion(d, config)) - whitelistOpts := getDcsInstanceWhitelist(d) - log.Printf("[DEBUG] update whitelist options: %#v", whitelistOpts) - - err = whitelists.Put(dcsV2Client, d.Id(), whitelistOpts).ExtractErr() + if d.HasChanges("whitelists", "tags") { + dcsV2Client, err := config.dcsV2Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error updating whitelist for instance (%s): %s", d.Id(), err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v2 client: %s", err) + } + + if d.HasChange("whitelists") { + whitelistOpts := getDcsInstanceWhitelist(d) + log.Printf("[DEBUG] update whitelist options: %#v", whitelistOpts) + + err = whitelists.Put(dcsV2Client, d.Id(), whitelistOpts).ExtractErr() + if err != nil { + return fmt.Errorf("Error updating whitelist for instance (%s): %s", d.Id(), err) + } + } + + // update tags + tagErr := UpdateResourceTags(dcsV2Client, d, "dcs", d.Id()) + if tagErr != nil { + return fmt.Errorf("Error updating tags of DCS instance:%s, err:%s", d.Id(), tagErr) } } @@ -483,7 +519,7 @@ func resourceDcsInstancesV1Delete(d *schema.ResourceData, meta interface{}) erro config := meta.(*Config) dcsV1Client, err := config.dcsV1Client(GetRegion(d, config)) if err != nil { - return fmt.Errorf("Error creating HuaweiCloud dcs instance client: %s", err) + return fmt.Errorf("Error creating HuaweiCloud dcs instance v1 client: %s", err) } _, err = instances.Get(dcsV1Client, d.Id()).Extract() diff --git a/huaweicloud/resource_huaweicloud_dcs_instance_v1_test.go b/huaweicloud/resource_huaweicloud_dcs_instance_v1_test.go index a2a8cb240c..fa2652eb25 100644 --- a/huaweicloud/resource_huaweicloud_dcs_instance_v1_test.go +++ b/huaweicloud/resource_huaweicloud_dcs_instance_v1_test.go @@ -4,11 +4,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/huaweicloud/golangsdk/openstack/dcs/v1/instances" - - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" ) func TestAccDcsInstancesV1_basic(t *testing.T) { @@ -29,6 +28,8 @@ func TestAccDcsInstancesV1_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "Redis"), resource.TestCheckResourceAttr(resourceName, "engine_version", "3.0"), resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), + resource.TestCheckResourceAttr(resourceName, "tags.owner", "terraform"), resource.TestCheckResourceAttrSet(resourceName, "ip"), resource.TestCheckResourceAttrSet(resourceName, "port"), ), @@ -77,6 +78,7 @@ func TestAccDcsInstancesV1_whitelists(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "engine", "Redis"), resource.TestCheckResourceAttr(resourceName, "engine_version", "5.0"), resource.TestCheckResourceAttr(resourceName, "whitelist_enable", "true"), + resource.TestCheckResourceAttr(resourceName, "whitelists.#", "2"), ), }, }, @@ -174,8 +176,8 @@ func testAccDcsV1Instance_basic(instanceName string) string { engine = "Redis" capacity = 2 vpc_id = "%s" - security_group_id = huaweicloud_networking_secgroup.secgroup_1.id subnet_id = "%s" + security_group_id = huaweicloud_networking_secgroup.secgroup_1.id available_zones = [data.huaweicloud_dcs_az.az_1.id] product_id = "dcs.master_standby-h" save_days = 1 @@ -183,7 +185,11 @@ func testAccDcsV1Instance_basic(instanceName string) string { begin_at = "00:00-01:00" period_type = "weekly" backup_at = [1] - depends_on = ["huaweicloud_networking_secgroup.secgroup_1"] + + tags = { + key = "value" + owner = "terraform" + } } `, OS_AVAILABILITY_ZONE, instanceName, OS_VPC_ID, OS_NETWORK_ID) } @@ -214,7 +220,6 @@ func testAccDcsV1Instance_epsId(instanceName string) string { begin_at = "00:00-01:00" period_type = "weekly" backup_at = [1] - depends_on = ["huaweicloud_networking_secgroup.secgroup_1"] enterprise_project_id = "%s" } `, OS_AVAILABILITY_ZONE, instanceName, OS_VPC_ID, OS_NETWORK_ID, OS_ENTERPRISE_PROJECT_ID) diff --git a/huaweicloud/resource_huaweicloud_dds_instance_v3.go b/huaweicloud/resource_huaweicloud_dds_instance_v3.go index 24c0c3ad0e..c14318421e 100644 --- a/huaweicloud/resource_huaweicloud_dds_instance_v3.go +++ b/huaweicloud/resource_huaweicloud_dds_instance_v3.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/common/tags" "github.com/huaweicloud/golangsdk/openstack/dds/v3/instances" ) @@ -170,6 +171,7 @@ func resourceDdsInstanceV3() *schema.Resource { Optional: true, Default: true, }, + "tags": tagsSchema(), "db_username": { Type: schema.TypeString, Computed: true, @@ -319,7 +321,9 @@ func resourceDdsInstanceV3Create(d *schema.ResourceData, meta interface{}) error Flavor: resourceDdsFlavors(d), BackupStrategy: resourceDdsBackupStrategy(d), } - if ssl := d.Get("ssl").(bool); !ssl { + if d.Get("ssl").(bool) { + createOpts.Ssl = "1" + } else { createOpts.Ssl = "0" } log.Printf("[DEBUG] Create Options: %#v", createOpts) @@ -332,7 +336,7 @@ func resourceDdsInstanceV3Create(d *schema.ResourceData, meta interface{}) error d.SetId(instance.Id) stateConf := &resource.StateChangeConf{ - Pending: []string{"creating"}, + Pending: []string{"creating", "updating"}, Target: []string{"normal"}, Refresh: DdsInstanceStateRefreshFunc(client, instance.Id), Timeout: d.Timeout(schema.TimeoutCreate), @@ -347,6 +351,15 @@ func resourceDdsInstanceV3Create(d *schema.ResourceData, meta interface{}) error instance.Id, err) } + //set tags + tagRaw := d.Get("tags").(map[string]interface{}) + if len(tagRaw) > 0 { + taglist := expandResourceTags(tagRaw) + if tagErr := tags.Create(client, "instances", instance.Id, taglist).ExtractErr(); tagErr != nil { + return fmt.Errorf("Error setting tags of DDS instance %s: %s", instance.Id, tagErr) + } + } + return resourceDdsInstanceV3Read(d, meta) } @@ -370,7 +383,9 @@ func resourceDdsInstanceV3Read(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error extracting DDS instance: %s", err) } if instances.TotalCount == 0 { - return fmt.Errorf("Error fetching DDS instance: deleted") + log.Printf("[WARN] DDS instance (%s) was not found", instanceID) + d.SetId("") + return nil } insts := instances.Instances instance := insts[0] @@ -417,6 +432,16 @@ func resourceDdsInstanceV3Read(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error setting nodes of DDS instance, err: %s", err) } + // save tags + resourceTags, err := tags.Get(client, "instances", d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error fetching tags of DDS instance: %s", err) + } + tagmap := tagsToMap(resourceTags.Tags) + if err := d.Set("tags", tagmap); err != nil { + return fmt.Errorf("[DEBUG] Error saving tag to state for DDS instance (%s): %s", d.Id(), err) + } + return nil } @@ -493,6 +518,13 @@ func resourceDdsInstanceV3Update(d *schema.ResourceData, meta interface{}) error d.Id(), err) } + if d.HasChange("tags") { + tagErr := UpdateResourceTags(client, d, "instances", d.Id()) + if tagErr != nil { + return fmt.Errorf("Error updating tags of DDS instance:%s, err:%s", d.Id(), tagErr) + } + } + return resourceDdsInstanceV3Read(d, meta) } diff --git a/huaweicloud/resource_huaweicloud_dds_instance_v3_test.go b/huaweicloud/resource_huaweicloud_dds_instance_v3_test.go index f270488147..0178d4dd32 100644 --- a/huaweicloud/resource_huaweicloud_dds_instance_v3_test.go +++ b/huaweicloud/resource_huaweicloud_dds_instance_v3_test.go @@ -11,6 +11,7 @@ import ( func TestAccDDSV3Instance_basic(t *testing.T) { var instance instances.Instance + resourceName := "huaweicloud_dds_instance.instance" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -20,11 +21,11 @@ func TestAccDDSV3Instance_basic(t *testing.T) { { Config: TestAccDDSInstanceV3Config_basic, Check: resource.ComposeTestCheckFunc( - testAccCheckDDSV3InstanceExists("huaweicloud_dds_instance_v3.instance", &instance), - resource.TestCheckResourceAttr( - "huaweicloud_dds_instance_v3.instance", "name", "dds-instance"), - resource.TestCheckResourceAttr( - "huaweicloud_dds_instance_v3.instance", "ssl", "true"), + testAccCheckDDSV3InstanceExists(resourceName, &instance), + resource.TestCheckResourceAttr(resourceName, "name", "dds-instance"), + resource.TestCheckResourceAttr(resourceName, "ssl", "true"), + resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"), + resource.TestCheckResourceAttr(resourceName, "tags.owner", "terraform"), ), }, }, @@ -39,7 +40,7 @@ func testAccCheckDDSV3InstanceDestroy(s *terraform.State) error { } for _, rs := range s.RootModule().Resources { - if rs.Type != "huaweicloud_dds_instance_v3" { + if rs.Type != "huaweicloud_dds_instance" { continue } @@ -92,7 +93,7 @@ func testAccCheckDDSV3InstanceExists(n string, instance *instances.Instance) res return err } if instances.TotalCount == 0 { - return fmt.Errorf("Instance not found. ") + return fmt.Errorf("dds instance not found.") } return nil @@ -100,11 +101,11 @@ func testAccCheckDDSV3InstanceExists(n string, instance *instances.Instance) res } var TestAccDDSInstanceV3Config_basic = fmt.Sprintf(` -resource "huaweicloud_networking_secgroup_v2" "secgroup_acc" { +resource "huaweicloud_networking_secgroup" "secgroup_acc" { name = "secgroup_acc" } -resource "huaweicloud_dds_instance_v3" "instance" { +resource "huaweicloud_dds_instance" "instance" { name = "dds-instance" datastore { type = "DDS-Community" @@ -115,9 +116,10 @@ resource "huaweicloud_dds_instance_v3" "instance" { availability_zone = "%s" vpc_id = "%s" subnet_id = "%s" - security_group_id = huaweicloud_networking_secgroup_v2.secgroup_acc.id + security_group_id = huaweicloud_networking_secgroup.secgroup_acc.id password = "Test@123" mode = "Sharding" + flavor { type = "mongos" num = 2 @@ -141,4 +143,8 @@ resource "huaweicloud_dds_instance_v3" "instance" { start_time = "08:00-09:00" keep_days = "8" } + tags = { + foo = "bar" + owner = "terraform" + } }`, OS_REGION_NAME, OS_AVAILABILITY_ZONE, OS_VPC_ID, OS_NETWORK_ID)