From ed995997f163658794c421f4ded625fbaf7240ac Mon Sep 17 00:00:00 2001 From: Jason-Zhang Date: Thu, 12 Dec 2024 20:26:47 +0800 Subject: [PATCH] feat(cce): support updating tags in autopilot cluster (#6007) --- docs/resources/cce_autopilot_cluster.md | 7 +- ..._huaweicloud_cce_autopilot_cluster_test.go | 14 ++++ ...ource_huaweicloud_cce_autopilot_cluster.go | 67 ++++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/resources/cce_autopilot_cluster.md b/docs/resources/cce_autopilot_cluster.md index d55ee0913a..dd210e637c 100644 --- a/docs/resources/cce_autopilot_cluster.md +++ b/docs/resources/cce_autopilot_cluster.md @@ -46,6 +46,11 @@ resource "huaweicloud_cce_autopilot_cluster" "mycluster" { subnet_id = huaweicloud_vpc_subnet.mysubnet.ipv4_subnet_id } } + + tags = { + "foo" = "bar" + "key" = "value" + } } ``` @@ -111,7 +116,7 @@ The following arguments are supported: * `authentication` - (Optional, List, NonUpdatable) Specifies the configurations of the cluster authentication mode. The [authentication](#autopilot_cluster_authentication) structure is documented below. -* `tags` - (Optional, Map, NonUpdatable) Specifies the cluster tags in the format of key-value pairs. +* `tags` - (Optional, Map) Specifies the cluster tags in the format of key-value pairs. * `kube_proxy_mode` - (Optional, String, NonUpdatable) Specifies the kube proxy mode of the cluster. The value can be: **iptables**. diff --git a/huaweicloud/services/acceptance/cceautopilot/resource_huaweicloud_cce_autopilot_cluster_test.go b/huaweicloud/services/acceptance/cceautopilot/resource_huaweicloud_cce_autopilot_cluster_test.go index 27e77af5c2..2035b71a9c 100644 --- a/huaweicloud/services/acceptance/cceautopilot/resource_huaweicloud_cce_autopilot_cluster_test.go +++ b/huaweicloud/services/acceptance/cceautopilot/resource_huaweicloud_cce_autopilot_cluster_test.go @@ -70,6 +70,8 @@ func TestAccAutopilotCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "flavor", "cce.autopilot.cluster"), resource.TestCheckResourceAttr(resourceName, "description", "created by terraform"), resource.TestCheckResourceAttr(resourceName, "container_network.0.mode", "eni"), + resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value"), resource.TestCheckResourceAttrPair(resourceName, "host_network.0.vpc", "huaweicloud_vpc.test", "id"), resource.TestCheckResourceAttrPair(resourceName, "host_network.0.subnet", "huaweicloud_vpc_subnet.test", "id"), resource.TestCheckResourceAttrPair(resourceName, "eni_network.0.subnets.0.subnet_id", @@ -85,6 +87,8 @@ func TestAccAutopilotCluster_basic(t *testing.T) { rc.CheckResourceExists(), resource.TestCheckResourceAttr(resourceName, "alias", rName+"-update"), resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "tags.foo", "bar_update"), + resource.TestCheckResourceAttr(resourceName, "tags.key_update", "value_update"), ), }, { @@ -119,6 +123,11 @@ resource "huaweicloud_cce_autopilot_cluster" "test" { subnet_id = huaweicloud_vpc_subnet.test.ipv4_subnet_id } } + + tags = { + "foo" = "bar" + "key" = "value" + } } `, common.TestVpc(rName), rName) } @@ -147,6 +156,11 @@ resource "huaweicloud_cce_autopilot_cluster" "test" { subnet_id = huaweicloud_vpc_subnet.test.ipv4_subnet_id } } + + tags = { + "foo" = "bar_update" + "key_update" = "value_update" + } } `, common.TestVpc(rName), rName) } diff --git a/huaweicloud/services/cceautopilot/resource_huaweicloud_cce_autopilot_cluster.go b/huaweicloud/services/cceautopilot/resource_huaweicloud_cce_autopilot_cluster.go index a3cd26db5b..1dfa4c6db4 100644 --- a/huaweicloud/services/cceautopilot/resource_huaweicloud_cce_autopilot_cluster.go +++ b/huaweicloud/services/cceautopilot/resource_huaweicloud_cce_autopilot_cluster.go @@ -27,7 +27,7 @@ var autopilotClusterNonUpdatableParams = []string{ "enable_swr_image_access", "enable_autopilot", "ipv6_enable", "service_network", "service_network.*.ipv4_cidr", "authentication", "authentication.*.mode", - "tags", "kube_proxy_mode", + "kube_proxy_mode", "extend_param", "extend_param.*.enterprise_project_id", "configurations_override", "configurations_override.*.name", "configurations_override.*.configurations", "configurations_override.*.configurations.*.name", "configurations_override.*.configurations.*.value", @@ -40,6 +40,8 @@ var autopilotClusterNonUpdatableParams = []string{ // @API CCE PUT /autopilot/v3/projects/{project_id}/clusters/{cluster_id} // @API CCE PUT /autopilot/v3/projects/{project_id}/clusters/{cluster_id}/mastereip // @API CCE DELETE /autopilot/v3/projects/{project_id}/clusters/{cluster_id} +// @API CCE POST /autopilot/v3/projects/{project_id}/clusters/{cluster_id}/tags/create +// @API CCE POST /autopilot/v3/projects/{project_id}/clusters/{cluster_id}/tags/delete func ResourceAutopilotCluster() *schema.Resource { return &schema.Resource{ CreateContext: resourceAutopilotClusterCreate, @@ -883,6 +885,52 @@ func clusterEipAction(updateClusterClient *golangsdk.ServiceClient, clusterID, e return nil } +func buildUpdateClusterTagsBodyParams(action string, tags map[string]interface{}) map[string]interface{} { + taglist := make([]map[string]interface{}, 0, len(tags)) + if action == "create" { + for k, v := range tags { + tag := map[string]interface{}{ + "key": k, + "value": v, + } + taglist = append(taglist, tag) + } + } else { + for k := range tags { + tag := map[string]interface{}{ + "key": k, + } + taglist = append(taglist, tag) + } + } + + return map[string]interface{}{ + "tags": taglist, + } +} + +func clusterTagsAction(updateClusterClient *golangsdk.ServiceClient, clusterID, action string, tags map[string]interface{}) error { + var updateClusterTagsHttpUrl = "autopilot/v3/projects/{project_id}/clusters/{cluster_id}/tags/{action}" + + updateClusterTagsPath := updateClusterClient.Endpoint + updateClusterTagsHttpUrl + updateClusterTagsPath = strings.ReplaceAll(updateClusterTagsPath, "{project_id}", updateClusterClient.ProjectID) + updateClusterTagsPath = strings.ReplaceAll(updateClusterTagsPath, "{cluster_id}", clusterID) + updateClusterTagsPath = strings.ReplaceAll(updateClusterTagsPath, "{action}", action) + + updateOpts := buildUpdateClusterTagsBodyParams(action, tags) + updateClusterOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + JSONBody: utils.RemoveNil(updateOpts), + OkCodes: []int{204}, + } + + _, err := updateClusterClient.Request("POST", updateClusterTagsPath, &updateClusterOpt) + if err != nil { + return err + } + return nil +} + func resourceAutopilotClusterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { cfg := meta.(*config.Config) region := cfg.GetRegion(d) @@ -932,6 +980,23 @@ func resourceAutopilotClusterUpdate(ctx context.Context, d *schema.ResourceData, } } + if d.HasChange("tags") { + oldTags, newTags := d.GetChange("tags") + if len(oldTags.(map[string]interface{})) > 0 { + err = clusterTagsAction(updateClusterClient, id, "delete", oldTags.(map[string]interface{})) + if err != nil { + return diag.Errorf("error removing tags from CCE autopilot cluster (%s): %s", id, err) + } + } + + if len(newTags.(map[string]interface{})) > 0 { + err = clusterTagsAction(updateClusterClient, id, "create", newTags.(map[string]interface{})) + if err != nil { + return diag.Errorf("error adding tags to CCE autopilot cluster (%s): %s", id, err) + } + } + } + return resourceAutopilotClusterRead(ctx, d, meta) }