From 0f5b3586daaefb41342c1370476800f8dc342dea Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Wed, 8 May 2024 19:14:43 +0800 Subject: [PATCH 1/5] feat(tke): [116855855]add tencentcloud_kubernetes_addon --- tencentcloud/common/context.go | 39 +++ tencentcloud/provider.go | 2 +- .../tke/resource_tc_kubernetes_addon.go | 278 ++++++++++++++++++ .../tke/resource_tc_kubernetes_addon_test.go | 51 ++++ .../services/tke/service_tencentcloud_tke.go | 30 ++ 5 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 tencentcloud/common/context.go create mode 100644 tencentcloud/services/tke/resource_tc_kubernetes_addon.go create mode 100644 tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go diff --git a/tencentcloud/common/context.go b/tencentcloud/common/context.go new file mode 100644 index 0000000000..e5458aa9b2 --- /dev/null +++ b/tencentcloud/common/context.go @@ -0,0 +1,39 @@ +package common + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +type ctxResourceDataKey struct{} +type ctxProviderMetaKey struct{} + +// NewResourceLifeCycleHandleFuncContext 创建一个资源生命周期处理方法上下文 +func NewResourceLifeCycleHandleFuncContext( + parent context.Context, + logID string, + d *schema.ResourceData, + meta interface{}, +) context.Context { + ctx := context.WithValue(parent, LogIdKey, logID) + ctx = context.WithValue(ctx, ctxResourceDataKey{}, d) + ctx = context.WithValue(ctx, ctxProviderMetaKey{}, meta) + return ctx +} + +// ResourceDataFromContext 从上下文获取资源数据 +func ResourceDataFromContext(ctx context.Context) *schema.ResourceData { + if d, ok := ctx.Value(ctxResourceDataKey{}).(*schema.ResourceData); ok { + return d + } + return nil +} + +// ProviderMetaFromContext 从上下文获取 provider meta +func ProviderMetaFromContext(ctx context.Context) interface{} { + if meta, ok := ctx.Value(ctxProviderMetaKey{}).(ProviderMeta); ok { + return meta + } + return nil +} diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index aecf620fb9..6aa564fb16 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -1971,7 +1971,7 @@ func Provider() *schema.Provider { "tencentcloud_csip_risk_center": csip.ResourceTencentCloudCsipRiskCenter(), "tencentcloud_organization_org_share_unit_member": tco.ResourceTencentCloudOrganizationOrgShareUnitMember(), "tencentcloud_organization_org_share_unit": tco.ResourceTencentCloudOrganizationOrgShareUnit(), - }, + "tencentcloud_kubernetes_addon": tke.ResourceTencentCloudKubernetesAddon()}, ConfigureFunc: providerConfigure, } diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon.go new file mode 100644 index 0000000000..c8e920d451 --- /dev/null +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon.go @@ -0,0 +1,278 @@ +// Code generated by iacg; DO NOT EDIT. +package tke + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tke "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke/v20180525" + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" + "log" + "strings" +) + +func ResourceTencentCloudKubernetesAddon() *schema.Resource { + return &schema.Resource{ + Create: resourceTencentCloudKubernetesAddonCreate, + Read: resourceTencentCloudKubernetesAddonRead, + Update: resourceTencentCloudKubernetesAddonUpdate, + Delete: resourceTencentCloudKubernetesAddonDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "cluster_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "ID of cluster.", + }, + + "addon_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of addon.", + }, + + "addon_version": { + Type: schema.TypeString, + Optional: true, + Description: "Version of addon.", + }, + + "raw_values": { + Type: schema.TypeString, + Optional: true, + Description: "Params of addon, base64 encoded json format.", + }, + + "phase": { + Type: schema.TypeString, + Computed: true, + Description: "Status of addon.", + }, + + "reason": { + Type: schema.TypeString, + Computed: true, + Description: "Reason of addon failed.", + }, + }, + } +} + +func resourceTencentCloudKubernetesAddonCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon.create")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + + var ( + clusterId string + addonName string + ) + var ( + request = tke.NewInstallAddonRequest() + response = tke.NewInstallAddonResponse() + ) + + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) + } + if v, ok := d.GetOk("addon_name"); ok { + addonName = v.(string) + } + + request.ClusterId = &clusterId + request.AddonName = &addonName + + if v, ok := d.GetOk("addon_version"); ok { + request.AddonVersion = helper.String(v.(string)) + } + + if v, ok := d.GetOk("raw_values"); ok { + request.RawValues = helper.String(v.(string)) + } + + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().InstallAddonWithContext(ctx, 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 { + log.Printf("[CRITAL]%s create kubernetes addon failed, reason:%+v", logId, err) + return err + } + + _ = response + + + d.SetId(strings.Join([]string{clusterId, addonName}, tccommon.FILED_SP)) + + return resourceTencentCloudKubernetesAddonRead(d, meta) +} + +func resourceTencentCloudKubernetesAddonRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon.read")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + clusterId := idSplit[0] + addonName := idSplit[1] + + _ = d.Set("cluster_id", clusterId) + _ = d.Set("addon_name", addonName) + + respData, err := service.DescribeKubernetesAddonById(ctx, clusterId, addonName) + if err != nil { + return err + } + + if respData == nil { + d.SetId("") + log.Printf("[WARN]%s resource `kubernetes_addon` [%s] not found, please check if it has been deleted.\n", logId, d.Id()) + return nil + } + + if respData.AddonVersion != nil { + _ = d.Set("addon_version", respData.AddonVersion) + } + + if respData.RawValues != nil { + _ = d.Set("raw_values", respData.RawValues) + } + + if respData.Phase != nil { + _ = d.Set("phase", respData.Phase) + } + + if respData.Reason != nil { + _ = d.Set("reason", respData.Reason) + } + + + _ = addonName + return nil +} + +func resourceTencentCloudKubernetesAddonUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon.update")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + clusterId := idSplit[0] + addonName := idSplit[1] + + needChange := false + mutableArgs := []string{"addon_version", "raw_values"} + for _, v := range mutableArgs { + if d.HasChange(v) { + needChange = true + break + } + } + + if needChange { + request := tke.NewUpdateAddonRequest() + + request.ClusterId = &clusterId + request.AddonName = &addonName + + if v, ok := d.GetOk("addon_version"); ok { + request.AddonVersion = helper.String(v.(string)) + } + + if v, ok := d.GetOk("raw_values"); ok { + request.RawValues = helper.String(v.(string)) + } + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().UpdateAddonWithContext(ctx, 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()) + } + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s update kubernetes addon failed, reason:%+v", logId, err) + return err + } + } + + + _ = addonName + return resourceTencentCloudKubernetesAddonRead(d, meta) +} + +func resourceTencentCloudKubernetesAddonDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon.delete")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + clusterId := idSplit[0] + addonName := idSplit[1] + + var ( + request = tke.NewDeleteAddonRequest() + response = tke.NewDeleteAddonResponse() + ) + + request.ClusterId = &clusterId + request.AddonName = &addonName + + + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().DeleteAddonWithContext(ctx, 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 { + log.Printf("[CRITAL]%s create kubernetes addon failed, reason:%+v", logId, err) + return err + } + + _ = response + _ = addonName + return nil +} diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go new file mode 100644 index 0000000000..82e65732c5 --- /dev/null +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go @@ -0,0 +1,51 @@ +package tke_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" +) + +func TestAccTencentCloudKubernetesAddonResource_basic(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + tcacctest.AccPreCheck(t) + }, + Providers: tcacctest.AccProviders, + Steps: []resource.TestStep{{ + Config: testAccKubernetesAddon, + Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon.kubernetes_addon", "id"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon.kubernetes_addon", "addon_name", "cos"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon.kubernetes_addon", "addon_version", "2018-05-25"), + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon.kubernetes_addon", "phase"), + // resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon.kubernetes_addon", "reason"), + ), + }, + }, + }) +} + +const testAccKubernetesAddon = ` +// resource "tencentcloud_kubernetes_cluster" "example" { +// vpc_id = "` + tcacctest.DefaultTmpVpcId + `" +// cluster_cidr = "10.31.0.0/16" +// cluster_max_pod_num = 32 +// cluster_name = "tf_example_cluster" +// cluster_desc = "example for tke cluster" +// cluster_max_service_num = 32 +// cluster_internet = false # (can be ignored) open it after the nodes added +// cluster_version = "1.22.5" +// cluster_deploy_type = "MANAGED_CLUSTER" +// # without any worker config +// } + +resource "tencentcloud_kubernetes_addon" "kubernetes_addon" { +// cluster_id = tencentcloud_kubernetes_cluster.example.id + cluster_id = "cls-lv0y4v68" + addon_name = "cos" + addon_version = "2018-05-25" + raw_values = "e30=" +} +` diff --git a/tencentcloud/services/tke/service_tencentcloud_tke.go b/tencentcloud/services/tke/service_tencentcloud_tke.go index d9b06cd153..f9d43bca72 100644 --- a/tencentcloud/services/tke/service_tencentcloud_tke.go +++ b/tencentcloud/services/tke/service_tencentcloud_tke.go @@ -2790,3 +2790,33 @@ func (me *TkeService) DescribeKubernetesClusterNodePoolsByFilter(ctx context.Con clusterNodePools = response.Response.NodePoolSet return } + +func (me *TkeService) DescribeKubernetesAddonById(ctx context.Context, clusterId string, addonName string) (ret *tke.Addon, errRet error) { + logId := tccommon.GetLogId(ctx) + + request := tke.NewDescribeAddonRequest() + request.ClusterId = &clusterId + request.AddonName = &addonName + + 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()) + } + }() + + ratelimit.Check(request.GetAction()) + + response, err := me.client.UseTkeClient().DescribeAddon(request) + if err != nil { + errRet = err + return + } + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + if len(response.Response.Addons) < 1 { + return + } + + ret = response.Response.Addons[0] + return +} From 45d0332f85c29a390b4227aa6f815c5e87286499 Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Fri, 10 May 2024 01:08:07 +0800 Subject: [PATCH 2/5] add doc --- tencentcloud/provider.md | 1 + .../tke/resource_tc_kubernetes_addon.md | 36 +++++++++++ .../tke/resource_tc_kubernetes_addon_test.go | 37 ++++++----- website/docs/r/kubernetes_addon.html.markdown | 64 +++++++++++++++++++ website/tencentcloud.erb | 3 + 5 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 tencentcloud/services/tke/resource_tc_kubernetes_addon.md create mode 100644 website/docs/r/kubernetes_addon.html.markdown diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index 783feadc18..8b2d2f15ff 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -669,6 +669,7 @@ Tencent Kubernetes Engine(TKE) tencentcloud_kubernetes_auth_attachment tencentcloud_kubernetes_addon_attachment tencentcloud_kubernetes_cluster_endpoint + tencentcloud_kubernetes_addon TDMQ for Pulsar(tpulsar) Data Source diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon.md b/tencentcloud/services/tke/resource_tc_kubernetes_addon.md new file mode 100644 index 0000000000..8450fb0180 --- /dev/null +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon.md @@ -0,0 +1,36 @@ +Provide a resource to configure kubernetes cluster app addons. + +Example Usage + +Install cos addon + +```hcl + +resource "tencentcloud_kubernetes_cluster" "example" { + vpc_id = "vpc-xxxxxxxx" + cluster_cidr = "10.31.0.0/16" + cluster_max_pod_num = 32 + cluster_name = "tf_example_cluster" + cluster_desc = "example for tke cluster" + cluster_max_service_num = 32 + cluster_internet = false # (can be ignored) open it after the nodes added + cluster_version = "1.22.5" + cluster_deploy_type = "MANAGED_CLUSTER" + # without any worker config +} + +resource "tencentcloud_kubernetes_addon" "kubernetes_addon" { + cluster_id = tencentcloud_kubernetes_cluster.example.id + addon_name = "cos" + addon_version = "2018-05-25" + raw_values = "e30=" +} + +``` + +Import + +Addon can be imported by using cluster_id#addon_name +``` +$ terraform import tencentcloud_kubernetes_addon.addon_cos cls-xxx#addon_name +``` \ No newline at end of file diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go index 82e65732c5..c21dd21969 100644 --- a/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon_test.go @@ -23,29 +23,34 @@ func TestAccTencentCloudKubernetesAddonResource_basic(t *testing.T) { // resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon.kubernetes_addon", "reason"), ), }, + { + ResourceName: "tencentcloud_kubernetes_addon.kubernetes_addon", + ImportState: true, + ImportStateVerify: true, + }, }, }) } const testAccKubernetesAddon = ` -// resource "tencentcloud_kubernetes_cluster" "example" { -// vpc_id = "` + tcacctest.DefaultTmpVpcId + `" -// cluster_cidr = "10.31.0.0/16" -// cluster_max_pod_num = 32 -// cluster_name = "tf_example_cluster" -// cluster_desc = "example for tke cluster" -// cluster_max_service_num = 32 -// cluster_internet = false # (can be ignored) open it after the nodes added -// cluster_version = "1.22.5" -// cluster_deploy_type = "MANAGED_CLUSTER" -// # without any worker config -// } +resource "tencentcloud_kubernetes_cluster" "example" { + vpc_id = "` + tcacctest.DefaultTmpVpcId + `" + cluster_cidr = "10.31.0.0/16" + cluster_max_pod_num = 32 + cluster_name = "tf_example_cluster" + cluster_desc = "example for tke cluster" + cluster_max_service_num = 32 + cluster_internet = false # (can be ignored) open it after the nodes added + cluster_version = "1.22.5" + cluster_deploy_type = "MANAGED_CLUSTER" + # without any worker config +} resource "tencentcloud_kubernetes_addon" "kubernetes_addon" { -// cluster_id = tencentcloud_kubernetes_cluster.example.id - cluster_id = "cls-lv0y4v68" - addon_name = "cos" + cluster_id = tencentcloud_kubernetes_cluster.example.id + # cluster_id = "cls-lv0y4v68" + addon_name = "cos" addon_version = "2018-05-25" - raw_values = "e30=" + raw_values = "e30=" } ` diff --git a/website/docs/r/kubernetes_addon.html.markdown b/website/docs/r/kubernetes_addon.html.markdown new file mode 100644 index 0000000000..676b32c7ba --- /dev/null +++ b/website/docs/r/kubernetes_addon.html.markdown @@ -0,0 +1,64 @@ +--- +subcategory: "Tencent Kubernetes Engine(TKE)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_kubernetes_addon" +sidebar_current: "docs-tencentcloud-resource-kubernetes_addon" +description: |- + Provide a resource to configure kubernetes cluster app addons. +--- + +# tencentcloud_kubernetes_addon + +Provide a resource to configure kubernetes cluster app addons. + +## Example Usage + +### Install cos addon + +```hcl +resource "tencentcloud_kubernetes_cluster" "example" { + vpc_id = "vpc-xxxxxxxx" + cluster_cidr = "10.31.0.0/16" + cluster_max_pod_num = 32 + cluster_name = "tf_example_cluster" + cluster_desc = "example for tke cluster" + cluster_max_service_num = 32 + cluster_internet = false # (can be ignored) open it after the nodes added + cluster_version = "1.22.5" + cluster_deploy_type = "MANAGED_CLUSTER" + # without any worker config +} + +resource "tencentcloud_kubernetes_addon" "kubernetes_addon" { + cluster_id = tencentcloud_kubernetes_cluster.example.id + addon_name = "cos" + addon_version = "2018-05-25" + raw_values = "e30=" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `addon_name` - (Required, String, ForceNew) Name of addon. +* `cluster_id` - (Required, String, ForceNew) ID of cluster. +* `addon_version` - (Optional, String) Version of addon. +* `raw_values` - (Optional, String) Params of addon, base64 encoded json format. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. +* `phase` - Status of addon. +* `reason` - Reason of addon failed. + + +## Import + +Addon can be imported by using cluster_id#addon_name +``` +$ terraform import tencentcloud_kubernetes_addon.addon_cos cls-xxx#addon_name +``` + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 004cede11a..b3fc5b16f9 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -4562,6 +4562,9 @@
  • Resources