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 0fe00be2c6..c10805530d 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -1114,8 +1114,8 @@ func Provider() *schema.Provider { "tencentcloud_kubernetes_cluster_endpoint": tke.ResourceTencentCloudTkeClusterEndpoint(), "tencentcloud_eks_cluster": tke.ResourceTencentCloudEksCluster(), "tencentcloud_eks_container_instance": tke.ResourceTencentCloudEksContainerInstance(), - "tencentcloud_kubernetes_addon_attachment": tke.ResourceTencentCloudTkeAddonAttachment(), - "tencentcloud_kubernetes_auth_attachment": tke.ResourceTencentCloudTKEAuthAttachment(), + "tencentcloud_kubernetes_addon_attachment": tke.ResourceTencentCloudKubernetesAddonAttachment(), + "tencentcloud_kubernetes_auth_attachment": tke.ResourceTencentCloudKubernetesAuthAttachment(), "tencentcloud_kubernetes_as_scaling_group": tke.ResourceTencentCloudKubernetesAsScalingGroup(), "tencentcloud_kubernetes_scale_worker": tke.ResourceTencentCloudTkeScaleWorker(), "tencentcloud_kubernetes_cluster_attachment": tke.ResourceTencentCloudTkeClusterAttachment(), diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment.go index bf37deda67..6130196fd6 100644 --- a/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment.go +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment.go @@ -1,22 +1,27 @@ +// Code generated by iacg; DO NOT EDIT. package tke import ( "context" - "encoding/base64" "fmt" - "strings" - - tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" - - tke "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tke/v20180525" - + "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 ResourceTencentCloudTkeAddonAttachment() *schema.Resource { +func ResourceTencentCloudKubernetesAddonAttachment() *schema.Resource { return &schema.Resource{ + Create: resourceTencentCloudKubernetesAddonAttachmentCreate, + Read: resourceTencentCloudKubernetesAddonAttachmentRead, + Update: resourceTencentCloudKubernetesAddonAttachmentUpdate, + Delete: resourceTencentCloudKubernetesAddonAttachmentDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "cluster_id": { Type: schema.TypeString, @@ -24,306 +29,290 @@ func ResourceTencentCloudTkeAddonAttachment() *schema.Resource { ForceNew: true, Description: "ID of cluster.", }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "Name of addon.", }, + "version": { Type: schema.TypeString, Optional: true, Computed: true, - Description: "Addon version, default latest version. Conflict with `request_body`.", ConflictsWith: []string{"request_body"}, + Description: "Addon version, default latest version. Conflict with `request_body`.", }, + "values": { Type: schema.TypeList, Optional: true, Computed: true, - Description: "Values the addon passthroughs. Conflict with `request_body`.", ConflictsWith: []string{"request_body"}, - Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Values the addon passthroughs. Conflict with `request_body`.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, }, + "raw_values": { Type: schema.TypeString, Optional: true, Computed: true, - Description: "Raw Values. Conflict with `request_body`. Required with `raw_values_type`.", ConflictsWith: []string{"request_body"}, RequiredWith: []string{"raw_values_type"}, + Description: "Raw Values. Conflict with `request_body`. Required with `raw_values_type`.", }, + "raw_values_type": { Type: schema.TypeString, Optional: true, Computed: true, - Description: "The type of raw Values. Required with `raw_values`.", RequiredWith: []string{"raw_values"}, + Description: "The type of raw Values. Required with `raw_values`.", }, + "request_body": { Type: schema.TypeString, Optional: true, - Description: "Serialized json string as request body of addon spec. If set, will ignore `version` and `values`.", ConflictsWith: []string{"version", "values"}, + Description: "Serialized json string as request body of addon spec. If set, will ignore `version` and `values`.", }, + "response_body": { Type: schema.TypeString, Computed: true, Description: "Addon response body.", }, + "status": { Type: schema.TypeMap, Computed: true, Description: "Addon current status.", }, }, - Create: resourceTencentCloudTkeAddonAttachmentCreate, - Update: resourceTencentCloudTkeAddonAttachmentUpdate, - Read: resourceTencentCloudTkeAddonAttachmentRead, - Delete: resourceTencentCloudTkeAddonAttachmentDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, } } -func resourceTencentCloudTkeAddonAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_addon_attachment.create")() +func resourceTencentCloudKubernetesAddonAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon_attachment.create")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() - service := TkeService{client: client} - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) var ( - clusterId = d.Get("cluster_id").(string) - addonName = d.Get("name").(string) - version = d.Get("version").(string) - values = d.Get("values").([]interface{}) - rawValues *string - rawValuesType *string - reqBody = d.Get("request_body").(string) + clusterId string + name string + ) + var ( + request = tke.NewForwardApplicationRequestV3Request() + response = tke.NewForwardApplicationRequestV3Response() ) - if version == "" { - request := tke.NewGetTkeAppChartListRequest() - chartList, err := service.GetTkeAppChartList(ctx, request) - if err != nil { - return fmt.Errorf("error while fetching latest chart versions, %s", err.Error()) - } - for i := range chartList { - chart := chartList[i] - if *chart.Name == addonName { - version = *chart.LatestVersion - break - } - } + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) + } + if v, ok := d.GetOk("name"); ok { + name = v.(string) } - if reqBody == "" { - if v, ok := d.GetOk("raw_values"); ok { - rawValues = helper.String(v.(string)) - } - if v, ok := d.GetOk("raw_values_type"); ok { - rawValuesType = helper.String(v.(string)) - } + if v, ok := d.GetOk("cluster_id"); ok { + request.ClusterName = helper.String(v.(string)) + } - var reqErr error - v := helper.InterfacesStringsPoint(values) - reqBody, reqErr = service.GetAddonReqBody(addonName, version, v, rawValues, rawValuesType) - if reqErr != nil { - return reqErr - } + if v, ok := d.GetOk("path"); ok { + request.Path = helper.String(v.(string)) } - err := service.CreateExtensionAddon(ctx, clusterId, reqBody) + if v, ok := d.GetOk("request_body"); ok { + request.RequestBody = helper.String(v.(string)) + } - if err != nil { + if err := resourceTencentCloudKubernetesAddonAttachmentCreatePostFillRequest0(ctx, request); err != nil { return err } - d.SetId(clusterId + tccommon.FILED_SP + addonName) - - resData := &AddonResponseData{} - reason := "unknown error" - phase, has, _ := service.PollingAddonsPhase(ctx, clusterId, addonName, resData) - - if resData.Status != nil && resData.Status["reason"] != nil { - reason = resData.Status["reason"].(string) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ForwardApplicationRequestV3WithContext(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 attachment failed, reason:%+v", logId, err) + return err } - if !has { - return fmt.Errorf("addon %s not exists", addonName) - } + _ = response - if phase == "ChartFetchFailed" || phase == "Failed" || phase == "RollbackFailed" || phase == "SyncFailed" { - msg := fmt.Sprintf("Unexpected chart phase `%s`, reason: %s", phase, reason) - if err := resourceTencentCloudTkeAddonAttachmentDelete(d, meta); err != nil { - return err - } - d.SetId("") - return fmt.Errorf(msg) + if err := resourceTencentCloudKubernetesAddonAttachmentCreatePostHandleResponse0(ctx, response); err != nil { + return err } - return resourceTencentCloudTkeAddonAttachmentRead(d, meta) + d.SetId(strings.Join([]string{clusterId, name}, tccommon.FILED_SP)) + + return resourceTencentCloudKubernetesAddonAttachmentRead(d, meta) } -func resourceTencentCloudTkeAddonAttachmentRead(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_addon_attachment.read")() +func resourceTencentCloudKubernetesAddonAttachmentRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon_attachment.read")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - id := d.Id() - has := false - split := strings.Split(id, tccommon.FILED_SP) - if len(split) < 2 { - return fmt.Errorf("id expected format: cluster_id#addon_name but no addon_name provided") + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) } - clusterId := split[0] - addonName := split[1] + clusterId := idSplit[0] + name := idSplit[1] - var ( - err error - response string - addonResponseData = &AddonResponseData{} - ) + _ = d.Set("cluster_id", clusterId) - _, has, err = service.PollingAddonsPhase(ctx, clusterId, addonName, addonResponseData) + _ = d.Set("name", name) - if err != nil || !has { - d.SetId("") + respData, err := service.DescribeKubernetesAddonAttachmentById(ctx) + if err != nil { return err } - response, _, err = service.DescribeExtensionAddon(ctx, clusterId, addonName) - - if err != nil { + if respData == nil { d.SetId("") - return err + log.Printf("[WARN]%s resource `kubernetes_addon_attachment` [%s] not found, please check if it has been deleted.\n", logId, d.Id()) + return nil + } + if respData.ResponseBody != nil { + _ = d.Set("response_body", respData.ResponseBody) } - _ = d.Set("response_body", response) - - spec := addonResponseData.Spec - statuses := addonResponseData.Status + if err := resourceTencentCloudKubernetesAddonAttachmentReadPostHandleResponse0(ctx, respData); err != nil { + return err + } - if spec != nil { - _ = d.Set("cluster_id", clusterId) - _ = d.Set("name", spec.Chart.ChartName) - _ = d.Set("version", spec.Chart.ChartVersion) - if spec.Values != nil && len(spec.Values.Values) > 0 { + _ = clusterId + _ = name + return nil +} - // Filter auto-filled values from addon creation - filteredValues := getFilteredValues(d, spec.Values.Values) - _ = d.Set("values", filteredValues) - } +func resourceTencentCloudKubernetesAddonAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon_attachment.update")() + defer tccommon.InconsistentCheck(d, meta)() - if spec.Values != nil && spec.Values.RawValues != nil { - rawValues := spec.Values.RawValues - rawValuesType := spec.Values.RawValuesType + logId := tccommon.GetLogId(tccommon.ContextNil) - base64DecodeValues, _ := base64.StdEncoding.DecodeString(*rawValues) - jsonValues := string(base64DecodeValues) + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) - _ = d.Set("raw_values", jsonValues) - _ = d.Set("raw_values_type", rawValuesType) + immutableArgs := []string{"cluster_id", "name"} + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) } } + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) != 2 { + return fmt.Errorf("id is broken,%s", d.Id()) + } + clusterId := idSplit[0] + name := idSplit[1] + + needChange := false + mutableArgs := []string{} + for _, v := range mutableArgs { + if d.HasChange(v) { + needChange = true + break + } + } + + if needChange { + request := tke.NewForwardApplicationRequestV3Request() - if statuses != nil || len(statuses) == 0 { - strMap := helper.CovertInterfaceMapToStrPtr(statuses) - err := d.Set("status", strMap) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ForwardApplicationRequestV3WithContext(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 attachment failed, reason:%+v", logId, err) return err } } - d.SetId(id) + if err := resourceTencentCloudKubernetesAddonAttachmentUpdateOnExit(ctx); err != nil { + return err + } - return nil + _ = clusterId + _ = name + return resourceTencentCloudKubernetesAddonAttachmentRead(d, meta) } -func resourceTencentCloudTkeAddonAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_addon_attachment.update")() +func resourceTencentCloudKubernetesAddonAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_addon_attachment.delete")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + 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] + name := idSplit[1] var ( - id = d.Id() - split = strings.Split(id, tccommon.FILED_SP) - clusterId = split[0] - addonName = split[1] - version = d.Get("version").(string) - values = d.Get("values").([]interface{}) - reqBody = d.Get("request_body").(string) - err error - rawValues *string - rawValuesType *string + request = tke.NewForwardApplicationRequestV3Request() + response = tke.NewForwardApplicationRequestV3Response() ) - if d.HasChange("request_body") && reqBody == "" || d.HasChange("version") || d.HasChange("values") || d.HasChange("raw_values") || d.HasChange("raw_values_type") { - if v, ok := d.GetOk("raw_values"); ok { - rawValues = helper.String(v.(string)) - } - if v, ok := d.GetOk("raw_values_type"); ok { - rawValuesType = helper.String(v.(string)) - } - reqBody, err = service.GetAddonReqBody(addonName, version, helper.InterfacesStringsPoint(values), rawValues, rawValuesType) + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) + } + if v, ok := d.GetOk("name"); ok { + name = v.(string) } - if err != nil { + if err := resourceTencentCloudKubernetesAddonAttachmentDeletePostFillRequest0(ctx, request); err != nil { return err } - err = service.UpdateExtensionAddon(ctx, clusterId, addonName, reqBody) - + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ForwardApplicationRequestV3WithContext(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 attachment failed, reason:%+v", logId, err) return err } - return resourceTencentCloudTkeAddonAttachmentRead(d, meta) -} - -func resourceTencentCloudTkeAddonAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_addon_attachment.delete")() - logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - - var ( - id = d.Id() - split = strings.Split(id, tccommon.FILED_SP) - clusterId = split[0] - addonName = split[1] - has bool - ) - - if err := service.DeleteExtensionAddon(ctx, clusterId, addonName); err != nil { + _ = response + if err := resourceTencentCloudKubernetesAddonAttachmentDeletePostHandleResponse0(ctx, response); err != nil { return err } - // check if addon terminating or still exists - _, has, _ = service.PollingAddonsPhase(ctx, clusterId, addonName, nil) - - if has { - return fmt.Errorf("addon %s still exists", addonName) - } - + _ = clusterId + _ = name return nil } - -func getFilteredValues(d *schema.ResourceData, values []*string) []string { - rawValues := helper.InterfacesStrings(d.Get("values").([]interface{})) - - for _, value := range values { - kv := strings.Split(*value, "=") - key := kv[0] - - if tccommon.IsContains(TKE_ADDON_DEFAULT_VALUES_KEY, key) || tccommon.IsContains(rawValues, *value) { - continue - } - rawValues = append(rawValues, *value) - } - return rawValues -} diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_extension.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_extension.go new file mode 100644 index 0000000000..2b6ac19d5c --- /dev/null +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_extension.go @@ -0,0 +1,259 @@ +package tke + +import ( + "context" + "encoding/base64" + "fmt" + 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" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var addonResponseData = &AddonResponseData{} + +func resourceTencentCloudKubernetesAddonAttachmentCreatePostFillRequest0(ctx context.Context, req *tke.ForwardApplicationRequestV3Request) error { + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + + var ( + addonName = d.Get("name").(string) + version = d.Get("version").(string) + values = d.Get("values").([]interface{}) + rawValues *string + rawValuesType *string + reqBody = d.Get("request_body").(string) + service = TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + ) + clusterName := *req.ClusterName + if version == "" { + request := tke.NewGetTkeAppChartListRequest() + chartList, err := service.GetTkeAppChartList(ctx, request) + if err != nil { + return fmt.Errorf("error while fetching latest chart versions, %s", err.Error()) + } + for i := range chartList { + chart := chartList[i] + if *chart.Name == addonName { + version = *chart.LatestVersion + break + } + } + } + + if reqBody == "" { + if v, ok := d.GetOk("raw_values"); ok { + rawValues = helper.String(v.(string)) + } + if v, ok := d.GetOk("raw_values_type"); ok { + rawValuesType = helper.String(v.(string)) + } + + var reqErr error + v := helper.InterfacesStringsPoint(values) + reqBody, reqErr = service.GetAddonReqBody(addonName, version, v, rawValues, rawValuesType) + if reqErr != nil { + return reqErr + } + } + req.RequestBody = &reqBody + req.Path = helper.String(service.GetAddonsPath(clusterName, "")) + req.Method = helper.String("POST") + return nil +} + +func resourceTencentCloudKubernetesAddonAttachmentCreatePostHandleResponse0(ctx context.Context, resp *tke.ForwardApplicationRequestV3Response) error { + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + var ( + clusterId string + name string + ) + + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) + } + if v, ok := d.GetOk("name"); ok { + name = v.(string) + } + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + + addonName := name + resData := &AddonResponseData{} + reason := "unknown error" + phase, has, _ := service.PollingAddonsPhase(ctx, clusterId, addonName, resData) + + if resData.Status != nil && resData.Status["reason"] != nil { + reason = resData.Status["reason"].(string) + } + + if !has { + return fmt.Errorf("addon %s not exists", addonName) + } + + if phase == "ChartFetchFailed" || phase == "Failed" || phase == "RollbackFailed" || phase == "SyncFailed" { + msg := fmt.Sprintf("Unexpected chart phase `%s`, reason: %s", phase, reason) + if err := resourceTencentCloudKubernetesAddonAttachmentDelete(d, meta); err != nil { + return err + } + d.SetId("") + return fmt.Errorf(msg) + } + return nil +} +func resourceTencentCloudKubernetesAddonAttachmentReadPreRequest0(ctx context.Context, req *tke.ForwardApplicationRequestV3Request) error { + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + var ( + err error + ) + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + + has := false + clusterName := d.Get("cluster_id").(string) + addonName := d.Get("name").(string) + + _, has, err = service.PollingAddonsPhase(ctx, clusterName, addonName, addonResponseData) + + if err != nil || !has { + d.SetId("") + return err + } + + req.Method = helper.String("GET") + req.ClusterName = &clusterName + req.Path = helper.String(service.GetAddonsPath(clusterName, addonName)) + + return nil +} + +func resourceTencentCloudKubernetesAddonAttachmentReadPostHandleResponse0(ctx context.Context, resp *tke.ForwardApplicationRequestV3ResponseParams) error { + d := tccommon.ResourceDataFromContext(ctx) + + spec := addonResponseData.Spec + statuses := addonResponseData.Status + clusterId := d.Get("cluster_id").(string) + + if spec != nil { + _ = d.Set("cluster_id", clusterId) + _ = d.Set("name", spec.Chart.ChartName) + _ = d.Set("version", spec.Chart.ChartVersion) + if spec.Values != nil && len(spec.Values.Values) > 0 { + + // Filter auto-filled values from addon creation + filteredValues := getFilteredValues(d, spec.Values.Values) + _ = d.Set("values", filteredValues) + } + + if spec.Values != nil && spec.Values.RawValues != nil { + rawValues := spec.Values.RawValues + rawValuesType := spec.Values.RawValuesType + + base64DecodeValues, _ := base64.StdEncoding.DecodeString(*rawValues) + jsonValues := string(base64DecodeValues) + + _ = d.Set("raw_values", jsonValues) + _ = d.Set("raw_values_type", rawValuesType) + } + } + + if statuses != nil || len(statuses) == 0 { + strMap := helper.CovertInterfaceMapToStrPtr(statuses) + err := d.Set("status", strMap) + if err != nil { + return err + } + } + return nil +} + +func resourceTencentCloudKubernetesAddonAttachmentUpdateOnExit(ctx context.Context) error { + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + var ( + id = d.Id() + split = strings.Split(id, tccommon.FILED_SP) + clusterId = split[0] + addonName = split[1] + version = d.Get("version").(string) + values = d.Get("values").([]interface{}) + reqBody = d.Get("request_body").(string) + err error + rawValues *string + rawValuesType *string + ) + + if d.HasChange("request_body") && reqBody == "" || d.HasChange("version") || d.HasChange("values") || d.HasChange("raw_values") || d.HasChange("raw_values_type") { + if v, ok := d.GetOk("raw_values"); ok { + rawValues = helper.String(v.(string)) + } + if v, ok := d.GetOk("raw_values_type"); ok { + rawValuesType = helper.String(v.(string)) + } + reqBody, err = service.GetAddonReqBody(addonName, version, helper.InterfacesStringsPoint(values), rawValues, rawValuesType) + } + + if err != nil { + return err + } + + err = service.UpdateExtensionAddon(ctx, clusterId, addonName, reqBody) + + if err != nil { + return err + } + return nil +} + +func resourceTencentCloudKubernetesAddonAttachmentDeletePostFillRequest0(ctx context.Context, req *tke.ForwardApplicationRequestV3Request) error { + + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + clusterName := d.Get("cluster_id").(string) + addonName := d.Get("name").(string) + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + + req.Method = helper.String("DELETE") + req.ClusterName = &clusterName + req.Path = helper.String(service.GetAddonsPath(clusterName, addonName)) + return nil +} +func resourceTencentCloudKubernetesAddonAttachmentDeletePostHandleResponse0(ctx context.Context, resp *tke.ForwardApplicationRequestV3Response) error { + d := tccommon.ResourceDataFromContext(ctx) + meta := tccommon.ProviderMetaFromContext(ctx) + var ( + id = d.Id() + split = strings.Split(id, tccommon.FILED_SP) + clusterId = split[0] + addonName = split[1] + has bool + ) + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + + // check if addon terminating or still exists + _, has, _ = service.PollingAddonsPhase(ctx, clusterId, addonName, nil) + + if has { + return fmt.Errorf("addon %s still exists", addonName) + } + return nil +} + +func getFilteredValues(d *schema.ResourceData, values []*string) []string { + rawValues := helper.InterfacesStrings(d.Get("values").([]interface{})) + + for _, value := range values { + kv := strings.Split(*value, "=") + key := kv[0] + + if tccommon.IsContains(TKE_ADDON_DEFAULT_VALUES_KEY, key) || tccommon.IsContains(rawValues, *value) { + continue + } + rawValues = append(rawValues, *value) + } + return rawValues +} diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_test.go b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_test.go index 29f075ad99..9bc5d1be43 100644 --- a/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_test.go +++ b/tencentcloud/services/tke/resource_tc_kubernetes_addon_attachment_test.go @@ -63,24 +63,59 @@ func TestAccTencentCloudKubernetesAddonAttachmentResource(t *testing.T) { Providers: tcacctest.AccProviders, Steps: []resource.TestStep{ { - Config: testAccTkeAddonAttachment(), + Config: testAccTkeAddonAttachmentBasic(), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon_attachment.cos", "response_body"), resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon_attachment.cos", "name", "cos"), resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon_attachment.cos", "version"), + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon_attachment.cos", "request_body"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon_attachment.cos", "version", "1.0.2"), + ), + }, + { + Config: testAccTkeAddonAttachmentUpdate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_addon_attachment.cos", "response_body"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon_attachment.cos", "name", "cos"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_addon_attachment.cos", "version", "1.0.3"), ), }, }, }) } +func testAccTkeAddonAttachmentBasic() string { + return fmt.Sprintf(` +%s + +resource "tencentcloud_kubernetes_addon_attachment" "cos" { + cluster_id = local.cluster_id + name = "%s" + request_body = jsonencode({ + kind = "App" + spec = { + chart = { + chartName = "cos" + chartVersion = "1.0.2" + } + values = { + values = [] + rawValues = "e30=" + rawValuesType = "json" + } + } + }) +} +`, tcacctest.TkeDataSource, DefaultAddonName) +} -func testAccTkeAddonAttachment() string { +func testAccTkeAddonAttachmentUpdate() string { return fmt.Sprintf(` %s resource "tencentcloud_kubernetes_addon_attachment" "cos" { cluster_id = local.cluster_id name = "%s" + version = "1.0.3" } `, tcacctest.TkeDataSource, DefaultAddonName) } diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment.go b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment.go index 18953f0af8..dfa5f7045b 100644 --- a/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment.go +++ b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment.go @@ -1,277 +1,388 @@ +// Code generated by iacg; DO NOT EDIT. package tke import ( "context" - - tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" - + "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" ) -func ResourceTencentCloudTKEAuthAttachment() *schema.Resource { +func ResourceTencentCloudKubernetesAuthAttachment() *schema.Resource { return &schema.Resource{ + Create: resourceTencentCloudKubernetesAuthAttachmentCreate, + Read: resourceTencentCloudKubernetesAuthAttachmentRead, + Update: resourceTencentCloudKubernetesAuthAttachmentUpdate, + Delete: resourceTencentCloudKubernetesAuthAttachmentDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "cluster_id": { Type: schema.TypeString, Required: true, Description: "ID of clusters.", }, + "use_tke_default": { Type: schema.TypeBool, Optional: true, ConflictsWith: []string{"issuer", "jwks_uri"}, Description: "If set to `true`, the issuer and jwks_uri will be generated automatically by tke, please do not set issuer and jwks_uri.", }, + "issuer": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"use_tke_default"}, Description: "Specify service-account-issuer. If use_tke_default is set to `true`, please do not set this field.", }, + "jwks_uri": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"use_tke_default"}, Description: "Specify service-account-jwks-uri. If use_tke_default is set to `true`, please do not set this field.", }, + "auto_create_discovery_anonymous_auth": { Type: schema.TypeBool, Optional: true, Default: false, Description: "If set to `true`, the rbac rule will be created automatically which allow anonymous user to access '/.well-known/openid-configuration' and '/openid/v1/jwks'.", }, + "auto_create_oidc_config": { Type: schema.TypeBool, Optional: true, Computed: true, Description: "Creating an identity provider.", }, + "auto_create_client_id": { - Type: schema.TypeSet, - Optional: true, - Computed: true, + Type: schema.TypeSet, + Optional: true, + Computed: true, + Description: "Creating ClientId of the identity provider.", Elem: &schema.Schema{ Type: schema.TypeString, }, - Description: "Creating ClientId of the identity provider.", }, + "auto_install_pod_identity_webhook_addon": { Type: schema.TypeBool, Optional: true, Computed: true, Description: "Creating the PodIdentityWebhook component. if `auto_create_oidc_config` is true, this field must set true.", }, + "tke_default_issuer": { Type: schema.TypeString, Computed: true, Description: "The default issuer of tke. If use_tke_default is set to `true`, this parameter will be set to the default value.", }, + "tke_default_jwks_uri": { Type: schema.TypeString, Computed: true, Description: "The default jwks_uri of tke. If use_tke_default is set to `true`, this parameter will be set to the default value.", }, }, - Create: resourceTencentCloudTKEAuthAttachmentCreate, - Update: resourceTencentCloudTKEAuthAttachmentUpdate, - Read: resourceTencentCloudTKEAuthAttachmentRead, - Delete: resourceTencentCloudTKEAuthAttachmentDelete, } } -func resourceTencentCloudTKEAuthAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_auth_attachment.create")() +func resourceTencentCloudKubernetesAuthAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_auth_attachment.create")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id := d.Get("cluster_id").(string) - service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - request := tke.NewModifyClusterAuthenticationOptionsRequest() - request.ClusterId = &id - request.ServiceAccounts = &tke.ServiceAccountAuthenticationOptions{} + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) + + var ( + clusterId string + ) + var ( + request = tke.NewModifyClusterAuthenticationOptionsRequest() + response = tke.NewModifyClusterAuthenticationOptionsResponse() + ) - if v, ok := d.GetOk("auto_create_discovery_anonymous_auth"); ok { - request.ServiceAccounts.AutoCreateDiscoveryAnonymousAuth = helper.Bool(v.(bool)) + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) } - if v, ok := d.GetOk("use_tke_default"); ok && v.(bool) { - request.ServiceAccounts.UseTKEDefault = helper.Bool(true) - } else { - if v, ok := d.GetOk("issuer"); ok { - request.ServiceAccounts.Issuer = helper.String(v.(string)) - } - if v, ok := d.GetOk("jwks_uri"); ok { - request.ServiceAccounts.JWKSURI = helper.String(v.(string)) - } + if v, ok := d.GetOk("cluster_id"); ok { + request.ClusterId = helper.String(v.(string)) } - request.OIDCConfig = &tke.OIDCConfigAuthenticationOptions{} + + serviceAccountAuthenticationOptions := tke.ServiceAccountAuthenticationOptions{} + if v, ok := d.GetOkExists("use_tke_default"); ok { + serviceAccountAuthenticationOptions.UseTKEDefault = helper.Bool(v.(bool)) + } + if v, ok := d.GetOk("issuer"); ok { + serviceAccountAuthenticationOptions.Issuer = helper.String(v.(string)) + } + if v, ok := d.GetOk("jwksuri"); ok { + serviceAccountAuthenticationOptions.JWKSURI = helper.String(v.(string)) + } + if v, ok := d.GetOkExists("auto_create_discovery_anonymous_auth"); ok { + serviceAccountAuthenticationOptions.AutoCreateDiscoveryAnonymousAuth = helper.Bool(v.(bool)) + } + request.ServiceAccounts = &serviceAccountAuthenticationOptions + + oIDCConfigAuthenticationOptions := tke.OIDCConfigAuthenticationOptions{} if v, ok := d.GetOkExists("auto_create_oidc_config"); ok { - request.OIDCConfig.AutoCreateOIDCConfig = helper.Bool(v.(bool)) + oIDCConfigAuthenticationOptions.AutoCreateOIDCConfig = helper.Bool(v.(bool)) } - if v, ok := d.GetOkExists("auto_create_client_id"); ok { - clientsSet := v.(*schema.Set).List() - for i := range clientsSet { - client := clientsSet[i].(string) - request.OIDCConfig.AutoCreateClientId = append(request.OIDCConfig.AutoCreateClientId, &client) + if v, ok := d.GetOk("auto_create_client_id"); ok { + autoCreateClientIdSet := v.(*schema.Set).List() + for i := range autoCreateClientIdSet { + autoCreateClientId := autoCreateClientIdSet[i].(string) + oIDCConfigAuthenticationOptions.AutoCreateClientId = append(oIDCConfigAuthenticationOptions.AutoCreateClientId, helper.String(autoCreateClientId)) } } if v, ok := d.GetOkExists("auto_install_pod_identity_webhook_addon"); ok { - request.OIDCConfig.AutoInstallPodIdentityWebhookAddon = helper.Bool(v.(bool)) + oIDCConfigAuthenticationOptions.AutoInstallPodIdentityWebhookAddon = helper.Bool(v.(bool)) } + request.OIDCConfig = &oIDCConfigAuthenticationOptions err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { - err := service.ModifyClusterAuthenticationOptions(ctx, request) - if err != nil { - return tccommon.RetryError(err, tke.RESOURCEUNAVAILABLE_CLUSTERSTATE) + if err := resourceTencentCloudKubernetesAuthAttachmentCreatePreRequest0(ctx, request); err != nil { + return err } + + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ModifyClusterAuthenticationOptionsWithContext(ctx, request) + if e != nil { + if err := resourceTencentCloudKubernetesAuthAttachmentCreateRequestOnError0(ctx, request, e); err != nil { + return err + } + 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 auth attachment failed, reason:%+v", logId, err) return err } - d.SetId(id) - return resourceTencentCloudTKEAuthAttachmentRead(d, meta) + _ = response + + d.SetId(clusterId) + + return resourceTencentCloudKubernetesAuthAttachmentRead(d, meta) } -func resourceTencentCloudTKEAuthAttachmentRead(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_auth_attachment.read")() + +func resourceTencentCloudKubernetesAuthAttachmentRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_auth_attachment.read")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id := d.Id() + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - info, oidc, err := service.WaitForAuthenticationOptionsUpdateSuccess(ctx, id) + clusterId := d.Id() + + _ = d.Set("cluster_id", clusterId) + + respData, err := service.DescribeKubernetesAuthAttachmentById(ctx, clusterId) if err != nil { - d.SetId("") return err } - d.SetId(id) - - if v, ok := d.GetOk("use_tke_default"); ok && v.(bool) { - _ = d.Set("tke_default_issuer", info.Issuer) - _ = d.Set("tke_default_jwks_uri", info.JWKSURI) - } else { - _ = d.Set("jwks_uri", info.JWKSURI) - _ = d.Set("issuer", info.Issuer) + err = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError { + result, e := service.DescribeKubernetesAuthAttachmentById(ctx, clusterId) + if e != nil { + return tccommon.RetryError(e) + } + if err := resourceTencentCloudKubernetesAuthAttachmentReadRequestOnSuccess0(ctx, result); err != nil { + return err + } + respData = result + return nil + }) + if err != nil { + log.Printf("[CRITAL]%s read kubernetes auth attachment failed, reason:%+v", logId, err) + return err } - if oidc.AutoCreateOIDCConfig != nil { - _ = d.Set("auto_create_oidc_config", oidc.AutoCreateOIDCConfig) + if respData == nil { + d.SetId("") + log.Printf("[WARN]%s resource `kubernetes_auth_attachment` [%s] not found, please check if it has been deleted.\n", logId, d.Id()) + return nil } + if respData.ServiceAccounts != nil { + if respData.ServiceAccounts.UseTKEDefault != nil { + _ = d.Set("use_tke_default", respData.ServiceAccounts.UseTKEDefault) + } + + if respData.ServiceAccounts.Issuer != nil { + _ = d.Set("issuer", respData.ServiceAccounts.Issuer) + } + + if respData.ServiceAccounts.JWKSURI != nil { + _ = d.Set("jwks_uri", respData.ServiceAccounts.JWKSURI) + } + + if respData.ServiceAccounts.AutoCreateDiscoveryAnonymousAuth != nil { + _ = d.Set("auto_create_discovery_anonymous_auth", respData.ServiceAccounts.AutoCreateDiscoveryAnonymousAuth) + } - if oidc.AutoCreateClientId != nil { - _ = d.Set("auto_create_client_id", oidc.AutoCreateClientId) } - if oidc.AutoInstallPodIdentityWebhookAddon != nil { - _ = d.Set("auto_install_pod_identity_webhook_addon", oidc.AutoInstallPodIdentityWebhookAddon) + if respData.OIDCConfig != nil { + if respData.OIDCConfig.AutoCreateOIDCConfig != nil { + _ = d.Set("auto_create_oidc_config", respData.OIDCConfig.AutoCreateOIDCConfig) + } + + if respData.OIDCConfig.AutoCreateClientId != nil { + _ = d.Set("auto_create_client_id", respData.OIDCConfig.AutoCreateClientId) + } + + if respData.OIDCConfig.AutoInstallPodIdentityWebhookAddon != nil { + _ = d.Set("auto_install_pod_identity_webhook_addon", respData.OIDCConfig.AutoInstallPodIdentityWebhookAddon) + } + } + return nil } -func resourceTencentCloudTKEAuthAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_auth_attachment.update")() - logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) +func resourceTencentCloudKubernetesAuthAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_auth_attachment.update")() + defer tccommon.InconsistentCheck(d, meta)() - id := d.Id() + logId := tccommon.GetLogId(tccommon.ContextNil) - service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - request := tke.NewModifyClusterAuthenticationOptionsRequest() - request.ClusterId = &id - request.ServiceAccounts = &tke.ServiceAccountAuthenticationOptions{} - - useTkeDefault := false - if v, ok := d.GetOk("use_tke_default"); ok { - request.ServiceAccounts.UseTKEDefault = helper.Bool(v.(bool)) - useTkeDefault = v.(bool) - } + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) - if !useTkeDefault { - if d.HasChange("jwks_uri") { - request.ServiceAccounts.JWKSURI = helper.String(d.Get("jwks_uri").(string)) + immutableArgs := []string{"cluster_id"} + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) } - if d.HasChange("issuer") { - issuer := d.Get("issuer").(string) - request.ServiceAccounts.Issuer = helper.String(issuer) + } + clusterId := d.Id() + + needChange := false + mutableArgs := []string{"use_tke_default", "issuer", "jwksuri", "auto_create_discovery_anonymous_auth", "auto_create_oidc_config", "auto_create_client_id", "auto_install_pod_identity_webhook_addon"} + for _, v := range mutableArgs { + if d.HasChange(v) { + needChange = true + break } } - if d.HasChange("auto_create_discovery_anonymous_auth") { - if v, ok := d.GetOk("auto_create_discovery_anonymous_auth"); ok { - request.ServiceAccounts.AutoCreateDiscoveryAnonymousAuth = helper.Bool(v.(bool)) + if needChange { + request := tke.NewModifyClusterAuthenticationOptionsRequest() + + request.ClusterId = &clusterId + + serviceAccountAuthenticationOptions := tke.ServiceAccountAuthenticationOptions{} + if v, ok := d.GetOkExists("use_tke_default"); ok { + serviceAccountAuthenticationOptions.UseTKEDefault = helper.Bool(v.(bool)) } - } + if v, ok := d.GetOk("issuer"); ok { + serviceAccountAuthenticationOptions.Issuer = helper.String(v.(string)) + } + if v, ok := d.GetOk("jwks_uri"); ok { + serviceAccountAuthenticationOptions.JWKSURI = helper.String(v.(string)) + } + if v, ok := d.GetOkExists("auto_create_discovery_anonymous_auth"); ok { + serviceAccountAuthenticationOptions.AutoCreateDiscoveryAnonymousAuth = helper.Bool(v.(bool)) + } + request.ServiceAccounts = &serviceAccountAuthenticationOptions - request.OIDCConfig = &tke.OIDCConfigAuthenticationOptions{} - if d.HasChange("auto_create_oidc_config") { + oIDCConfigAuthenticationOptions := tke.OIDCConfigAuthenticationOptions{} if v, ok := d.GetOkExists("auto_create_oidc_config"); ok { - request.OIDCConfig.AutoCreateOIDCConfig = helper.Bool(v.(bool)) + oIDCConfigAuthenticationOptions.AutoCreateOIDCConfig = helper.Bool(v.(bool)) } - } - - if d.HasChange("auto_create_client_id") { - if v, ok := d.GetOkExists("auto_create_client_id"); ok { - clientsSet := v.(*schema.Set).List() - for i := range clientsSet { - client := clientsSet[i].(string) - request.OIDCConfig.AutoCreateClientId = append(request.OIDCConfig.AutoCreateClientId, &client) + if v, ok := d.GetOk("auto_create_client_id"); ok { + autoCreateClientIdSet := v.(*schema.Set).List() + for i := range autoCreateClientIdSet { + autoCreateClientId := autoCreateClientIdSet[i].(string) + oIDCConfigAuthenticationOptions.AutoCreateClientId = append(oIDCConfigAuthenticationOptions.AutoCreateClientId, helper.String(autoCreateClientId)) } } - } - - if d.HasChange("auto_install_pod_identity_webhook_addon") { if v, ok := d.GetOkExists("auto_install_pod_identity_webhook_addon"); ok { - request.OIDCConfig.AutoInstallPodIdentityWebhookAddon = helper.Bool(v.(bool)) + oIDCConfigAuthenticationOptions.AutoInstallPodIdentityWebhookAddon = helper.Bool(v.(bool)) } - } + request.OIDCConfig = &oIDCConfigAuthenticationOptions + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + if err := resourceTencentCloudKubernetesAuthAttachmentUpdatePreRequest0(ctx, request); err != nil { + return err + } - err := resource.Retry(3*tccommon.WriteRetryTimeout, func() *resource.RetryError { - err := service.ModifyClusterAuthenticationOptions(ctx, request) + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ModifyClusterAuthenticationOptionsWithContext(ctx, request) + if e != nil { + if err := resourceTencentCloudKubernetesAuthAttachmentUpdateRequestOnError0(ctx, request, e); err != nil { + return err + } + 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 { - return tccommon.RetryError(err, tke.RESOURCEUNAVAILABLE_CLUSTERSTATE) + log.Printf("[CRITAL]%s update kubernetes auth attachment failed, reason:%+v", logId, err) + return err } - return nil - }) - - if err != nil { - return err } - return resourceTencentCloudTKEAuthAttachmentRead(d, meta) + return resourceTencentCloudKubernetesAuthAttachmentRead(d, meta) } -func resourceTencentCloudTKEAuthAttachmentDelete(d *schema.ResourceData, meta interface{}) error { - defer tccommon.LogElapsed("resource.resource_tc_kubernetes_auth_attachment.delete")() +func resourceTencentCloudKubernetesAuthAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_kubernetes_auth_attachment.delete")() + defer tccommon.InconsistentCheck(d, meta)() + logId := tccommon.GetLogId(tccommon.ContextNil) - ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + ctx := tccommon.NewResourceLifeCycleHandleFuncContext(context.Background(), logId, d, meta) - id := d.Id() + clusterId := d.Id() - service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} - request := tke.NewModifyClusterAuthenticationOptionsRequest() - request.ClusterId = &id - request.ServiceAccounts = &tke.ServiceAccountAuthenticationOptions{ - JWKSURI: helper.String(""), - Issuer: helper.String(DefaultAuthenticationOptionsIssuer), - } + var ( + request = tke.NewModifyClusterAuthenticationOptionsRequest() + response = tke.NewModifyClusterAuthenticationOptionsResponse() + ) - if err := service.ModifyClusterAuthenticationOptions(ctx, request); err != nil { - return err + if v, ok := d.GetOk("cluster_id"); ok { + clusterId = v.(string) } - _, _, err := service.WaitForAuthenticationOptionsUpdateSuccess(ctx, id) + request.ClusterId = &clusterId + + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + if err := resourceTencentCloudKubernetesAuthAttachmentDeletePreRequest0(ctx, request); err != nil { + return err + } + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTkeClient().ModifyClusterAuthenticationOptionsWithContext(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 auth attachment failed, reason:%+v", logId, err) + return err + } + + _ = response + if err := resourceTencentCloudKubernetesAuthAttachmentDeletePostHandleResponse0(ctx, response); err != nil { return err } diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_extension.go b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_extension.go new file mode 100644 index 0000000000..89f6ec9385 --- /dev/null +++ b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_extension.go @@ -0,0 +1,105 @@ +package tke + +import ( + "context" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + 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" +) + +func resourceTencentCloudKubernetesAuthAttachmentCreateRequestOnError0(ctx context.Context, req *tke.ModifyClusterAuthenticationOptionsRequest, e error) *resource.RetryError { + return tccommon.RetryError(e, tke.RESOURCEUNAVAILABLE_CLUSTERSTATE) +} + +func resourceTencentCloudKubernetesAuthAttachmentCreatePreRequest0(ctx context.Context, req *tke.ModifyClusterAuthenticationOptionsRequest) *resource.RetryError { + d := tccommon.ResourceDataFromContext(ctx) + tmpReqServiceAccount := tke.ServiceAccountAuthenticationOptions{} + if v, ok := d.GetOk("use_tke_default"); ok && v.(bool) { + req.ServiceAccounts.Issuer = tmpReqServiceAccount.Issuer + req.ServiceAccounts.JWKSURI = tmpReqServiceAccount.JWKSURI + } + + return nil +} +func resourceTencentCloudKubernetesAuthAttachmentReadRequestOnSuccess0(ctx context.Context, resp *tke.DescribeClusterAuthenticationOptionsResponseParams) *resource.RetryError { + tmpRespServiceAccount := tke.ServiceAccountAuthenticationOptions{} + d := tccommon.ResourceDataFromContext(ctx) + + if resp != nil && resp.ServiceAccounts != nil { + if v, ok := d.GetOk("use_tke_default"); ok && v.(bool) { + resp.ServiceAccounts.Issuer = tmpRespServiceAccount.Issuer + resp.ServiceAccounts.JWKSURI = tmpRespServiceAccount.JWKSURI + _ = d.Set("tke_default_issuer", resp.ServiceAccounts.Issuer) + _ = d.Set("tke_default_jwks_uri", resp.ServiceAccounts.JWKSURI) + } + + resp.ServiceAccounts.UseTKEDefault = tmpRespServiceAccount.UseTKEDefault + resp.ServiceAccounts.AutoCreateDiscoveryAnonymousAuth = tmpRespServiceAccount.AutoCreateDiscoveryAnonymousAuth + } + + return nil +} +func resourceTencentCloudKubernetesAuthAttachmentUpdatePreRequest0(ctx context.Context, req *tke.ModifyClusterAuthenticationOptionsRequest) *resource.RetryError { + d := tccommon.ResourceDataFromContext(ctx) + + useTkeDefault := false + tmpReqServiceAccount := tke.ServiceAccountAuthenticationOptions{} + req.ServiceAccounts.JWKSURI = tmpReqServiceAccount.JWKSURI + req.ServiceAccounts.Issuer = tmpReqServiceAccount.Issuer + req.ServiceAccounts.UseTKEDefault = tmpReqServiceAccount.UseTKEDefault + + if v, ok := d.GetOk("use_tke_default"); ok { + req.ServiceAccounts.UseTKEDefault = helper.Bool(v.(bool)) + useTkeDefault = v.(bool) + } + + if !useTkeDefault { + if d.HasChange("jwks_uri") { + req.ServiceAccounts.JWKSURI = helper.String(d.Get("jwks_uri").(string)) + } + if d.HasChange("issuer") { + issuer := d.Get("issuer").(string) + req.ServiceAccounts.Issuer = helper.String(issuer) + } + } + return nil +} + +func resourceTencentCloudKubernetesAuthAttachmentUpdateRequestOnError0(ctx context.Context, req *tke.ModifyClusterAuthenticationOptionsRequest, e error) *resource.RetryError { + return tccommon.RetryError(e, tke.RESOURCEUNAVAILABLE_CLUSTERSTATE) +} +func resourceTencentCloudKubernetesAuthAttachmentReadPostFillRequest0(ctx context.Context, req *tke.DescribeClusterAuthenticationOptionsRequest) error { + d := tccommon.ResourceDataFromContext(ctx) + + meta := tccommon.ProviderMetaFromContext(ctx) + + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + _, _, err := service.WaitForAuthenticationOptionsUpdateSuccess(ctx, d.Id()) + + if err != nil { + d.SetId("") + return err + } + return nil +} +func resourceTencentCloudKubernetesAuthAttachmentDeletePreRequest0(ctx context.Context, req *tke.ModifyClusterAuthenticationOptionsRequest) *resource.RetryError { + req.ServiceAccounts = &tke.ServiceAccountAuthenticationOptions{ + JWKSURI: helper.String(""), + Issuer: helper.String(DefaultAuthenticationOptionsIssuer), + } + return nil +} +func resourceTencentCloudKubernetesAuthAttachmentDeletePostHandleResponse0(ctx context.Context, resp *tke.ModifyClusterAuthenticationOptionsResponse) error { + d := tccommon.ResourceDataFromContext(ctx) + + meta := tccommon.ProviderMetaFromContext(ctx) + + service := TkeService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + _, _, err := service.WaitForAuthenticationOptionsUpdateSuccess(ctx, d.Id()) + + if err != nil { + return err + } + return nil +} diff --git a/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_test.go b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_test.go index 3ebfc11007..9310d5a8cb 100644 --- a/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_test.go +++ b/tencentcloud/services/tke/resource_tc_kubernetes_auth_attachment_test.go @@ -15,45 +15,59 @@ func TestAccTencentCloudKubernetesAuthAttachResource(t *testing.T) { Providers: tcacctest.AccProviders, Steps: []resource.TestStep{ { - Config: testAccTkeAuthAttach(), + Config: testAccTkeAuthAttachDefault, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "cluster_id"), resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_create_discovery_anonymous_auth", "true"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "use_tke_default", "true"), + ), + }, + { + Config: testAccTkeAuthAttachNonDefault, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "cluster_id"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_create_discovery_anonymous_auth", "true"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "jwks_uri", "https://ap-guangzhou-oidc.tke.tencentcs.com/id/7cbe7ca92eba3abc76a17de1/openid/v1/jwks"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "issuer", "https://ap-guangzhou-oidc.tke.tencentcs.com/id/7cbe7ca92eba3abc76a17de1"), + ), + }, + { + Config: testAccTkeAuthAttachOidcUpdateOidc, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "cluster_id"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_create_discovery_anonymous_auth", "true"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "use_tke_default", "true"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_create_oidc_config", "true"), + resource.TestCheckResourceAttrSet("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_create_client_id.#"), + resource.TestCheckResourceAttr("tencentcloud_kubernetes_auth_attachment.test_auth_attach", "auto_install_pod_identity_webhook_addon", "true"), ), }, }, }) } -func testAccTkeAuthAttach() string { - return tcacctest.TkeCIDRs + ` -variable "availability_zone" { - default = "ap-guangzhou-3" -} +const testAccTkeAuthAttachDefault = tcacctest.TkeDataSource + ` -data "tencentcloud_vpc_subnets" "vpc" { - is_default = true - availability_zone = var.availability_zone -} +resource "tencentcloud_kubernetes_auth_attachment" "test_auth_attach" { + cluster_id = local.cluster_id + auto_create_discovery_anonymous_auth = true + use_tke_default = true +}` -resource "tencentcloud_kubernetes_cluster" "managed_cluster" { - vpc_id = data.tencentcloud_vpc_subnets.vpc.instance_list.0.vpc_id - cluster_cidr = var.tke_cidr_a.1 - cluster_max_pod_num = 32 - cluster_name = "for-auth-attachment" - cluster_desc = "test cluster desc" - cluster_version = "1.20.6" - cluster_max_service_num = 32 - cluster_os = "tlinux2.2(tkernel3)x86_64" - - cluster_deploy_type = "MANAGED_CLUSTER" -} +const testAccTkeAuthAttachNonDefault = tcacctest.TkeDataSource + ` +resource "tencentcloud_kubernetes_auth_attachment" "test_auth_attach" { + cluster_id = local.cluster_id + auto_create_discovery_anonymous_auth = true + jwks_uri = "https://ap-guangzhou-oidc.tke.tencentcs.com/id/7cbe7ca92eba3abc76a17de1/openid/v1/jwks" + issuer = "https://ap-guangzhou-oidc.tke.tencentcs.com/id/7cbe7ca92eba3abc76a17de1" +}` +const testAccTkeAuthAttachOidcUpdateOidc = tcacctest.TkeDataSource + ` resource "tencentcloud_kubernetes_auth_attachment" "test_auth_attach" { - cluster_id = tencentcloud_kubernetes_cluster.managed_cluster.id - issuer = "" + cluster_id = local.cluster_id auto_create_discovery_anonymous_auth = true use_tke_default = true -} -` -} + auto_create_oidc_config = true + auto_create_client_id = ["xxx"] + auto_install_pod_identity_webhook_addon=true +}` diff --git a/tencentcloud/services/tke/service_tencentcloud_tke.go b/tencentcloud/services/tke/service_tencentcloud_tke.go index fc4618e132..ebbf505db8 100644 --- a/tencentcloud/services/tke/service_tencentcloud_tke.go +++ b/tencentcloud/services/tke/service_tencentcloud_tke.go @@ -2788,3 +2788,58 @@ func (me *TkeService) DescribeKubernetesClusterNodePoolsByFilter(ctx context.Con clusterNodePools = response.Response.NodePoolSet return } + +func (me *TkeService) DescribeKubernetesAuthAttachmentById(ctx context.Context, clusterId string) (ret *tke.DescribeClusterAuthenticationOptionsResponseParams, errRet error) { + logId := tccommon.GetLogId(ctx) + + request := tke.NewDescribeClusterAuthenticationOptionsRequest() + request.ClusterId = &clusterId + if err := resourceTencentCloudKubernetesAuthAttachmentReadPostFillRequest0(ctx, request); err != nil { + return nil, err + } + 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().DescribeClusterAuthenticationOptions(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()) + + ret = response.Response + return +} + +func (me *TkeService) DeleteKubernetesAuthAttachmentById(ctx context.Context, clusterId string) (errRet error) { + logId := tccommon.GetLogId(ctx) + + request := tke.NewModifyClusterAuthenticationOptionsRequest() + request.ClusterId = &clusterId + request.ServiceAccounts = &tke.ServiceAccountAuthenticationOptions{ + Issuer: helper.String("https://kubernetes.default.svc.cluster.local"), + JWKSURI: helper.String(""), + } + + 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().ModifyClusterAuthenticationOptions(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()) + + return +} diff --git a/tencentcloud/services/tke/service_tencentcloud_tke_addons.go b/tencentcloud/services/tke/service_tencentcloud_tke_addons.go index 57e1d53056..3c5b3a4046 100644 --- a/tencentcloud/services/tke/service_tencentcloud_tke_addons.go +++ b/tencentcloud/services/tke/service_tencentcloud_tke_addons.go @@ -303,3 +303,52 @@ func (me *TkeService) GetAddonNameFromJson(reqJson string) (name string, err err } return } +func (me *TkeService) DescribeKubernetesAddonAttachmentById(ctx context.Context) (ret *tke.ForwardApplicationRequestV3ResponseParams, errRet error) { + logId := tccommon.GetLogId(ctx) + + request := tke.NewForwardApplicationRequestV3Request() + + 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()) + + if err := resourceTencentCloudKubernetesAddonAttachmentReadPreRequest0(ctx, request); err != nil { + return nil, err + } + + response, err := me.client.UseTkeClient().ForwardApplicationRequestV3(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()) + + ret = response.Response + return +} +func (me *TkeService) DeleteKubernetesAddonAttachmentById(ctx context.Context) (errRet error) { + logId := tccommon.GetLogId(ctx) + + request := tke.NewForwardApplicationRequestV3Request() + + 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().ForwardApplicationRequestV3(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()) + + return +}