alicloud/resource_alicloud_cs_managed_kubernetes.go (1,441 lines of code) (raw):

package alicloud import ( "encoding/json" "fmt" "log" "regexp" "strconv" "strings" "time" "github.com/aliyun/alibaba-cloud-sdk-go/services/vpc" "github.com/alibabacloud-go/tea/tea" util "github.com/alibabacloud-go/tea-utils/service" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" roacs "github.com/alibabacloud-go/cs-20151215/v5/client" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/denverdino/aliyungo/cs" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAlicloudCSManagedKubernetes() *schema.Resource { return &schema.Resource{ Create: resourceAlicloudCSManagedKubernetesCreate, Read: resourceAlicloudCSManagedKubernetesRead, Update: resourceAlicloudCSManagedKubernetesUpdate, Delete: resourceAlicloudCSKubernetesDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(90 * time.Minute), Update: schema.DefaultTimeout(60 * time.Minute), Delete: schema.DefaultTimeout(60 * time.Minute), }, Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringLenBetween(1, 63), ConflictsWith: []string{"name_prefix"}, }, "name_prefix": { Type: schema.TypeString, Optional: true, Default: "Terraform-Creation", ValidateFunc: StringLenBetween(0, 37), ConflictsWith: []string{"name"}, }, "worker_vswitch_ids": { Type: schema.TypeList, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: StringMatch(regexp.MustCompile(`^vsw-[a-z0-9]*$`), "should start with 'vsw-'."), }, Optional: true, Deprecated: "Field 'worker_vswitch_ids' has been deprecated from provider version 1.241.0. Please use 'vswitch_ids' to managed control plane vswtiches", }, "worker_instance_types": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, MaxItems: 10, Removed: "Field 'worker_instance_types' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'instance_types' to replace it.", }, "worker_number": { Type: schema.TypeInt, Optional: true, Removed: "Field 'worker_number' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes., by using field 'desired_size' to replace it.", }, "worker_disk_size": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntBetween(20, 32768), Removed: "Field 'worker_disk_size' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'system_disk_size' to replace it.", }, "worker_disk_category": { Type: schema.TypeString, Optional: true, Removed: "Field 'worker_disk_category' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'system_disk_category' to replace it.", }, "worker_disk_performance_level": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"PL0", "PL1", "PL2", "PL3"}, false), DiffSuppressFunc: workerDiskPerformanceLevelDiffSuppressFunc, Removed: "Field 'worker_disk_performance_level' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'system_disk_performance_level' to replace it", }, "worker_disk_snapshot_policy_id": { Type: schema.TypeString, Optional: true, Removed: "Field 'worker_disk_snapshot_policy_id' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'system_disk_snapshot_policy_id' to replace it", }, "worker_data_disk_size": { Type: schema.TypeInt, Optional: true, ValidateFunc: IntBetween(20, 32768), DiffSuppressFunc: workerDataDiskSizeSuppressFunc, Removed: "Field 'worker_data_disk_size' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'data_disks.size' to replace it", }, "worker_data_disk_category": { Type: schema.TypeString, Optional: true, Removed: "Field 'worker_data_disk_category' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'data_disks.category' to replace it", }, "worker_instance_charge_type": { Type: schema.TypeString, Computed: true, Optional: true, Removed: "Field 'worker_instance_charge_type' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'instance_charge_type' to replace it", }, "worker_data_disks": { Optional: true, Type: schema.TypeList, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "size": { Type: schema.TypeString, Optional: true, }, "category": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"all", "cloud", "ephemeral_ssd", "cloud_essd", "cloud_efficiency", "cloud_ssd", "local_disk"}, false), }, "snapshot_id": { Type: schema.TypeString, Optional: true, }, "name": { Type: schema.TypeString, Optional: true, }, "device": { Type: schema.TypeString, Optional: true, }, "kms_key_id": { Type: schema.TypeString, Optional: true, }, "encrypted": { Type: schema.TypeString, Optional: true, }, "auto_snapshot_policy_id": { Type: schema.TypeString, Optional: true, }, "performance_level": { Type: schema.TypeString, Optional: true, }, }, }, Removed: "Field 'worker_data_disks' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'data_disks' to replace it", }, "worker_period_unit": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"Week", "Month"}, false), DiffSuppressFunc: csKubernetesWorkerPostPaidDiffSuppressFunc, Removed: "Field 'worker_period_unit' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'period_unit' to replace it", }, "worker_period": { Type: schema.TypeInt, Optional: true, Computed: true, DiffSuppressFunc: csKubernetesWorkerPostPaidDiffSuppressFunc, Removed: "Field 'worker_period' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'period' to replace it", }, "worker_auto_renew": { Type: schema.TypeBool, Optional: true, DiffSuppressFunc: csKubernetesWorkerPostPaidDiffSuppressFunc, Removed: "Field 'worker_auto_renew' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'auto_renew' to replace it", }, "worker_auto_renew_period": { Type: schema.TypeInt, Optional: true, Computed: true, ValidateFunc: IntInSlice([]int{1, 2, 3, 6, 12}), DiffSuppressFunc: csKubernetesWorkerPostPaidDiffSuppressFunc, Removed: "Field 'worker_auto_renew_period' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'auto_renew_period' to replace it", }, "exclude_autoscaler_nodes": { Type: schema.TypeBool, Optional: true, Removed: "Field 'exclude_autoscaler_nodes' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes", }, // global configurations "zone_ids": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, MinItems: 1, MaxItems: 5, }, "vswitch_ids": { Type: schema.TypeList, Optional: true, Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: StringMatch(regexp.MustCompile(`^vsw-[a-z0-9]*$`), "should start with 'vsw-'."), }, MinItems: 1, MaxItems: 5, ExactlyOneOf: []string{"worker_vswitch_ids", "vswitch_ids", "zone_ids"}, }, "pod_vswitch_ids": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: StringMatch(regexp.MustCompile(`^vsw-[a-z0-9]*$`), "should start with 'vsw-'."), }, }, "pod_cidr": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "service_cidr": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "node_cidr_mask": { Type: schema.TypeInt, Optional: true, ForceNew: true, Default: KubernetesClusterNodeCIDRMasksByDefault, ValidateFunc: IntBetween(24, 28), }, "enable_ssh": { Type: schema.TypeBool, Optional: true, Removed: "Field 'enable_ssh' has been removed from provider version 1.212.0.", }, "new_nat_gateway": { Type: schema.TypeBool, Optional: true, Default: true, }, "password": { Type: schema.TypeString, Optional: true, Sensitive: true, ConflictsWith: []string{"key_name", "kms_encrypted_password"}, Removed: "Field 'password' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'password' to replace it", }, "key_name": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"password", "kms_encrypted_password"}, Removed: "Field 'key_name' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'key_name' to replace it", }, "kms_encrypted_password": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"password", "key_name"}, Removed: "Field 'kms_encrypted_password' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'kms_encrypted_password' to replace it", }, "kms_encryption_context": { Type: schema.TypeMap, Optional: true, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { return d.Get("kms_encrypted_password").(string) == "" }, Elem: schema.TypeString, Removed: "Field 'kms_encryption_context' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'kms_encryption_context' to replace it", }, "user_ca": { Type: schema.TypeString, Optional: true, }, "image_id": { Type: schema.TypeString, Optional: true, Removed: "Field 'image_id' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'image_id' to replace it", }, "install_cloud_monitor": { Type: schema.TypeBool, Optional: true, Computed: true, Removed: "Field 'install_cloud_monitor' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'install_cloud_monitor' to replace it", }, "version": { Type: schema.TypeString, Optional: true, Computed: true, }, // cpu policy options of kubelet "cpu_policy": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"none", "static"}, false), Removed: "Field 'cpu_policy' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'cpu_policy' to replace it", }, "proxy_mode": { Type: schema.TypeString, Optional: true, ForceNew: true, Default: "ipvs", ValidateFunc: StringInSlice([]string{"iptables", "ipvs"}, false), }, "ip_stack": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ValidateFunc: StringInSlice([]string{"ipv4", "dual"}, false), }, "addons": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, Optional: true, }, "config": { Type: schema.TypeString, Optional: true, }, "version": { Type: schema.TypeString, Optional: true, }, "disabled": { Type: schema.TypeBool, Optional: true, Default: false, }, }, }, }, "slb_internet_enabled": { Type: schema.TypeBool, Optional: true, Default: true, }, "load_balancer_spec": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"slb.s1.small", "slb.s2.small", "slb.s2.medium", "slb.s3.small", "slb.s3.medium", "slb.s3.large"}, false), Computed: true, Deprecated: "Field 'load_balancer_spec' has been deprecated from provider version 1.232.0. The spec will not take effect because the charge of the load balancer has been changed to PayByCLCU", }, "deletion_protection": { Type: schema.TypeBool, Optional: true, Default: false, }, "enable_rrsa": { Type: schema.TypeBool, Optional: true, }, "timezone": { Type: schema.TypeString, Optional: true, }, "os_type": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"Windows", "Linux"}, false), Removed: "Field 'os_type' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes.", }, "platform": { Type: schema.TypeString, Optional: true, Computed: true, Removed: "Field 'platform' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'platform' to replace it.", }, "node_port_range": { Type: schema.TypeString, Optional: true, Computed: true, Removed: "Field 'node_port_range' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes.", }, "cluster_domain": { Type: schema.TypeString, Optional: true, Default: "cluster.local", ForceNew: true, Description: "cluster local domain ", }, "runtime": { Type: schema.TypeMap, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, Optional: true, }, "version": { Type: schema.TypeString, Optional: true, }, }, }, Removed: "Field 'runtime' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'runtime_name' and 'runtime_version' to replace it.", }, "taints": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "key": { Type: schema.TypeString, Optional: true, }, "value": { Type: schema.TypeString, Optional: true, }, "effect": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"NoSchedule", "NoExecute", "PreferNoSchedule"}, false), }, }, }, Removed: "Field 'taints' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'taints' to replace it.", }, "rds_instances": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, Removed: "Field 'rds_instances' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'rds_instances' to replace it.", }, "user_data": { Type: schema.TypeString, Optional: true, Removed: "Field 'user_data' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'user_data' to replace it.", }, "node_name_mode": { Type: schema.TypeString, Optional: true, ValidateFunc: StringMatch(regexp.MustCompile(`^customized,[a-z0-9]([-a-z0-9\.])*,([5-9]|[1][0-2]),([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`), "Each node name consists of a prefix, an IP substring, and a suffix. For example, if the node IP address is 192.168.0.55, the prefix is aliyun.com, IP substring length is 5, and the suffix is test, the node name will be aliyun.com00055test."), Removed: "Field 'node_name_mode' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes, by using field 'node_name_mode' to replace it.", }, "worker_nodes": { Type: schema.TypeList, Optional: true, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { Type: schema.TypeString, Computed: true, }, "name": { Type: schema.TypeString, Computed: true, }, "private_ip": { Type: schema.TypeString, Computed: true, }, }, }, Removed: "Field 'worker_nodes' has been removed from provider version 1.212.0. Please use resource 'alicloud_cs_kubernetes_node_pool' to manage cluster nodes.", }, "custom_san": { Type: schema.TypeString, Optional: true, }, "encryption_provider_key": { Type: schema.TypeString, Optional: true, ForceNew: true, Description: "The ID of the Key Management Service (KMS) key that is used to encrypt Kubernetes Secrets.", }, // computed parameters "kube_config": { Type: schema.TypeString, Optional: true, Removed: "Field 'kube_config' has been removed from provider version 1.212.0. Please use the attribute 'output_file' of new DataSource 'alicloud_cs_cluster_credential' to replace it", }, "client_cert": { Type: schema.TypeString, Optional: true, Deprecated: "Field 'client_cert' has been deprecated from provider version 1.248.0. From version 1.248.0, new DataSource 'alicloud_cs_cluster_credential' is recommended to manage cluster's kubeconfig, you can also save the 'certificate_authority.client_cert' attribute content of new DataSource 'alicloud_cs_cluster_credential' to an appropriate path(like ~/.kube/client-cert.pem) for replace it.", }, "client_key": { Type: schema.TypeString, Optional: true, Deprecated: "Field 'client_key' has been deprecated from provider version 1.248.0. From version 1.248.0, new DataSource 'alicloud_cs_cluster_credential' is recommended to manage cluster's kubeconfig, you can also save the 'certificate_authority.client_key' attribute content of new DataSource 'alicloud_cs_cluster_credential' to an appropriate path(like ~/.kube/client-key.pem) for replace it.", }, "cluster_ca_cert": { Type: schema.TypeString, Optional: true, Deprecated: "Field 'cluster_ca_cert' has been deprecated from provider version 1.248.0. From version 1.248.0, new DataSource 'alicloud_cs_cluster_credential' is recommended to manage cluster's kubeconfig, you can also save the 'certificate_authority.cluster_cert' attribute content of new DataSource 'alicloud_cs_cluster_credential' to an appropriate path(like ~/.kube/cluster-ca-cert.pem) for replace it.", }, "certificate_authority": { Type: schema.TypeMap, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "cluster_cert": { Type: schema.TypeString, Computed: true, }, "client_cert": { Type: schema.TypeString, Computed: true, }, "client_key": { Type: schema.TypeString, Computed: true, }, }, }, Deprecated: "Field 'certificate_authority' has been deprecated from provider version 1.248.0. Please use the attribute 'certificate_authority' of new DataSource 'alicloud_cs_cluster_credential' to replace it.", }, "skip_set_certificate_authority": { Type: schema.TypeBool, Optional: true, }, "connections": { Type: schema.TypeMap, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "api_server_internet": { Type: schema.TypeString, Computed: true, }, "api_server_intranet": { Type: schema.TypeString, Computed: true, }, "master_public_ip": { Type: schema.TypeString, Computed: true, }, "service_domain": { Type: schema.TypeString, Computed: true, }, }, }, }, "slb_id": { Type: schema.TypeString, Computed: true, }, "slb_internet": { Type: schema.TypeString, Computed: true, }, "slb_intranet": { Type: schema.TypeString, Computed: true, }, "security_group_id": { Type: schema.TypeString, Optional: true, Computed: true, }, "is_enterprise_security_group": { Type: schema.TypeBool, Optional: true, ForceNew: true, Computed: true, ConflictsWith: []string{"security_group_id"}, }, "nat_gateway_id": { Type: schema.TypeString, Computed: true, }, "vpc_id": { Type: schema.TypeString, Computed: true, }, "availability_zone": { Type: schema.TypeString, Optional: true, Computed: true, Removed: "Field 'availability_zone' has been removed from provider version 1.212.0.", }, // force update is a high risk operation "force_update": { Type: schema.TypeBool, Optional: true, Removed: "Field 'force_update' has been removed from provider version 1.75.0.", }, // worker_numbers in array is a hell of management "worker_numbers": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeInt, Default: 3, }, MinItems: 1, MaxItems: 3, Removed: "Field 'worker_numbers' has been removed from provider version 1.75.0. New field 'worker_number' replaces it.", }, "cluster_network_type": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{KubernetesClusterNetworkTypeFlannel, KubernetesClusterNetworkTypeTerway}, false), Removed: "Field 'cluster_network_type' has been removed from provider version 1.75.0. New field 'addons' replaces it.", }, // too hard to use this config "log_config": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { Type: schema.TypeString, ValidateFunc: StringInSlice([]string{KubernetesClusterLoggingTypeSLS}, false), Required: true, }, "project": { Type: schema.TypeString, Optional: true, }, }, }, Removed: "Field 'log_config' has been removed from provider version 1.75.0. New field 'addons' replaces it.", }, "worker_instance_type": { Type: schema.TypeString, Optional: true, Removed: "Field 'worker_instance_type' has been removed from provider version 1.75.0. New field 'worker_instance_types' replaces it.", }, "worker_ram_role_name": { Type: schema.TypeString, Computed: true, }, "service_account_issuer": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "api_audiences": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, ForceNew: true, }, "tags": { Type: schema.TypeMap, Optional: true, }, "resource_group_id": { Type: schema.TypeString, Optional: true, Computed: true, }, "cluster_spec": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: StringInSlice([]string{"ack.standard", "ack.pro.small"}, false), }, "maintenance_window": { Type: schema.TypeList, Optional: true, Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enable": { Type: schema.TypeBool, Optional: true, Computed: true, }, "maintenance_time": { Type: schema.TypeString, Optional: true, Computed: true, }, "duration": { Type: schema.TypeString, Optional: true, Computed: true, }, "weekly_period": { Type: schema.TypeString, Optional: true, Computed: true, }, }, }, }, "operation_policy": { Type: schema.TypeList, Optional: true, Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "cluster_auto_upgrade": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enabled": { Type: schema.TypeBool, Optional: true, }, "channel": { Type: schema.TypeString, Optional: true, }, }, }, }, }, }, }, "control_plane_log_ttl": { Type: schema.TypeString, Computed: true, Optional: true, }, "control_plane_log_project": { Type: schema.TypeString, Computed: true, Optional: true, }, "control_plane_log_components": { Type: schema.TypeList, Optional: true, MinItems: 0, Elem: &schema.Schema{ Type: schema.TypeString, }, }, "retain_resources": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, }, }, "delete_options": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "resource_type": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"SLB", "ALB", "SLS_Data", "SLS_ControlPlane", "PrivateZone"}, false), }, "delete_mode": { Type: schema.TypeString, Optional: true, ValidateFunc: StringInSlice([]string{"delete", "retain"}, false), }, }, }, }, "rrsa_metadata": { Type: schema.TypeList, Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enabled": { Type: schema.TypeBool, Computed: true, }, "rrsa_oidc_issuer_url": { Type: schema.TypeString, Computed: true, }, "ram_oidc_provider_name": { Type: schema.TypeString, Computed: true, }, "ram_oidc_provider_arn": { Type: schema.TypeString, Computed: true, }, }, }, }, }, } } func resourceAlicloudCSManagedKubernetesCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) roa, _ := client.NewRoaCsClient() csClient := CsClient{roa} var clusterName string if v, ok := d.GetOk("name"); ok { clusterName = v.(string) } else { clusterName = resource.PrefixedUniqueId(d.Get("name_prefix").(string)) } tags := make([]*roacs.Tag, 0) tagsMap, ok := d.Get("tags").(map[string]interface{}) if ok { for key, value := range tagsMap { if value != nil { if v, ok := value.(string); ok { tags = append(tags, &roacs.Tag{ Key: tea.String(key), Value: tea.String(v), }) } } } } addons := make([]*roacs.Addon, 0) if v, ok := d.GetOk("addons"); ok { all, ok := v.([]interface{}) if ok { for _, a := range all { addon, ok := a.(map[string]interface{}) if ok { addons = append(addons, &roacs.Addon{ Name: tea.String(addon["name"].(string)), Config: tea.String(addon["config"].(string)), Version: tea.String(addon["version"].(string)), Disabled: tea.Bool(addon["disabled"].(bool)), }) } } } } vpcService := VpcService{client} var vSwitchIds []string if v, ok := d.GetOk("vswitch_ids"); ok { vSwitchIds = expandStringList(v.([]interface{})) } else { if v, ok := d.GetOk("worker_vswitch_ids"); ok { vSwitchIds = expandStringList(v.([]interface{})) } } var vpcId string if len(vSwitchIds) > 0 { vsw, err := vpcService.DescribeVSwitch(vSwitchIds[0]) if err != nil { return err } vpcId = vsw.VpcId } request := &roacs.CreateClusterRequest{ Name: tea.String(clusterName), RegionId: tea.String(client.RegionId), ClusterType: tea.String("ManagedKubernetes"), Profile: tea.String("Default"), Tags: tags, Addons: addons, Vpcid: tea.String(vpcId), VswitchIds: tea.StringSlice(vSwitchIds), } if v, ok := d.GetOk("version"); ok { request.SetKubernetesVersion(v.(string)) } if v, ok := d.GetOk("deletion_protection"); ok { request.SetDeletionProtection(v.(bool)) } if v, ok := d.GetOk("resource_group_id"); ok { request.SetResourceGroupId(v.(string)) } if v, ok := d.GetOk("vpc_id"); ok { request.SetVpcid(v.(string)) } if v, ok := d.GetOk("zone_ids"); ok { request.SetZoneIds(tea.StringSlice(expandStringList(v.([]interface{})))) } if v, ok := d.GetOk("new_nat_gateway"); ok { request.SetSnatEntry(v.(bool)) } if v, ok := d.GetOk("slb_internet_enabled"); ok { request.SetEndpointPublicAccess(v.(bool)) } if v, ok := d.GetOk("load_balancer_spec"); ok { request.SetLoadBalancerSpec(v.(string)) } if v, ok := d.GetOk("is_enterprise_security_group"); ok { request.SetIsEnterpriseSecurityGroup(v.(bool)) } if v, ok := d.GetOk("security_group_id"); ok { request.SetSecurityGroupId(v.(string)) } if v, ok := d.GetOk("service_cidr"); ok { request.SetServiceCidr(v.(string)) } if v, ok := d.GetOk("proxy_mode"); ok { request.SetProxyMode(v.(string)) } if v, ok := d.GetOk("ip_stack"); ok { request.SetIpStack(v.(string)) } if v, ok := d.GetOk("timezone"); ok { request.SetTimezone(v.(string)) } if v, ok := d.GetOk("pod_vswitch_ids"); ok { request.SetPodVswitchIds(tea.StringSlice(expandStringList(v.([]interface{})))) } if v, ok := d.GetOk("pod_cidr"); ok { request.SetContainerCidr(v.(string)) } if v, ok := d.GetOk("node_cidr_mask"); ok { request.SetNodeCidrMask(strconv.Itoa(v.(int))) } if v, ok := d.GetOk("cluster_spec"); ok { request.SetClusterSpec(v.(string)) } if v, ok := d.GetOk("cluster_domain"); ok { request.SetClusterDomain(v.(string)) } if v, ok := d.GetOk("service_account_issuer"); ok { request.SetServiceAccountIssuer(v.(string)) } if v, ok := d.GetOk("api_audiences"); ok { if list := expandStringList(v.([]interface{})); len(list) > 0 { request.SetApiAudiences(strings.Join(list, ",")) } } if v, ok := d.GetOk("enable_rrsa"); ok { request.SetEnableRrsa(v.(bool)) } if v, ok := d.GetOk("custom_san"); ok { request.SetCustomSan(v.(string)) } if v, ok := d.GetOk("encryption_provider_key"); ok { request.SetEncryptionProviderKey(v.(string)) } // Configure control plane log. Effective only in the professional managed cluster if v, ok := d.GetOk("control_plane_log_components"); ok { request.SetControlplaneLogComponents(tea.StringSlice(expandStringList(v.([]interface{})))) // ttl default is 30 days request.SetControlplaneLogTtl("30") } if v, ok := d.GetOk("control_plane_log_ttl"); ok { request.SetControlplaneLogTtl(v.(string)) } if v, ok := d.GetOk("control_plane_log_project"); ok { request.SetControlplaneLogProject(v.(string)) } if v, ok := d.GetOk("maintenance_window"); ok { request.SetMaintenanceWindow(expandMaintenanceWindowConfigRoa(v.([]interface{}))) } if v, ok := d.GetOk("operation_policy"); ok { request.OperationPolicy = &roacs.CreateClusterRequestOperationPolicy{} m := v.([]interface{})[0].(map[string]interface{}) if vv, ok := m["cluster_auto_upgrade"]; ok { policy := vv.([]interface{})[0].(map[string]interface{}) request.OperationPolicy.ClusterAutoUpgrade = &roacs.CreateClusterRequestOperationPolicyClusterAutoUpgrade{ Enabled: tea.Bool(policy["enabled"].(bool)), Channel: tea.String(policy["channel"].(string)), } } } var err error var resp *roacs.CreateClusterResponse wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { resp, err = csClient.client.CreateCluster(request) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_cs_managed_kubernetes", "CreateManagedKubernetesCluster", AlibabaCloudSdkGoERROR) } d.SetId(tea.StringValue(resp.Body.ClusterId)) taskId := tea.StringValue(resp.Body.TaskId) roaCsClient, err := client.NewRoaCsClient() if err == nil { csClient := CsClient{client: roaCsClient} stateConf := BuildStateConf([]string{}, []string{"success"}, d.Timeout(schema.TimeoutCreate), 10*time.Second, csClient.DescribeTaskRefreshFunc(d, taskId, []string{"fail", "failed"})) if jobDetail, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, ResponseCodeMsg, d.Id(), "createCluster", jobDetail) } } csService := CsService{client} stateConf := BuildStateConf([]string{"initial"}, []string{"running"}, d.Timeout(schema.TimeoutCreate), 10*time.Second, csService.CsKubernetesInstanceStateRefreshFunc(d.Id(), []string{"deleting", "failed"})) if _, err := stateConf.WaitForState(); err != nil { return WrapErrorf(err, IdMsg, d.Id()) } return resourceAlicloudCSManagedKubernetesRead(d, meta) } func resourceAlicloudCSManagedKubernetesRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) rosClient, err := client.NewRoaCsClient() if err != nil { return WrapErrorf(err, DefaultErrorMsg, ResourceName, "InitializeClient", err) } csClient := CsClient{rosClient} object, err := csClient.DescribeClusterDetail(d.Id()) if err != nil { if !d.IsNewResource() && NotFoundError(err) { log.Printf("[DEBUG] Resource alicloud_cs_managed_kubernetes DescribeClusterDetail Failed!!! %s", err) d.SetId("") return nil } return WrapError(err) } // compat for default value if spec := d.Get("load_balancer_spec").(string); spec != "" { d.Set("load_balancer_spec", spec) } if object.Name != nil { d.Set("name", object.Name) } if object.VpcId != nil { d.Set("vpc_id", object.VpcId) } if object.VswitchIds != nil { d.Set("vswitch_ids", tea.StringSliceValue(object.VswitchIds)) } // compat for old value if v := d.Get("worker_vswitch_ids"); v != nil { d.Set("worker_vswitch_ids", v) } if object.SecurityGroupId != nil { d.Set("security_group_id", object.SecurityGroupId) } if object.DeletionProtection != nil { d.Set("deletion_protection", object.DeletionProtection) } if object.CurrentVersion != nil { d.Set("version", object.CurrentVersion) } if object.ResourceGroupId != nil { d.Set("resource_group_id", object.ResourceGroupId) } if object.ClusterSpec != nil { d.Set("cluster_spec", object.ClusterSpec) } if object.Timezone != nil { d.Set("timezone", object.Timezone) } if object.WorkerRamRoleName != nil { d.Set("worker_ram_role_name", object.WorkerRamRoleName) } d.Set("cluster_domain", "cluster.local") if object.ClusterDomain != nil { d.Set("cluster_domain", object.ClusterDomain) } if err := d.Set("tags", flattenTags(object.Tags)); err != nil { return WrapError(err) } slbId, err := getApiServerSlbID(d, meta) if err != nil { log.Printf(DefaultErrorMsg, d.Id(), "DescribeClusterResources", err.Error()) } d.Set("slb_id", slbId) if object.ServiceCidr != nil { d.Set("service_cidr", object.ServiceCidr) } else { if v, ok := object.Parameters["ServiceCIDR"]; ok { d.Set("service_cidr", v) } } if object.ProxyMode != nil { d.Set("proxy_mode", object.ProxyMode) } else { if v, ok := object.Parameters["ProxyMode"]; ok { d.Set("proxy_mode", v) } } if object.IpStack != nil { d.Set("ip_stack", object.IpStack) } if object.ContainerCidr != nil { d.Set("pod_cidr", object.ContainerCidr) } else { if v, ok := object.Parameters["ContainerCIDR"]; ok { d.Set("pod_cidr", v) } } if object.NodeCidrMask != nil { d.Set("node_cidr_mask", formatInt(tea.StringValue(object.NodeCidrMask))) } else { // node_cidr_mask capabilities := fetchClusterCapabilities(tea.StringValue(object.MetaData)) if v, ok := capabilities["NodeCIDRMask"]; ok { d.Set("node_cidr_mask", formatInt(v)) } } metadata := fetchClusterMetaDataMap(tea.StringValue(object.MetaData)) if v, ok := metadata["ExtraCertSAN"]; ok && v != nil { l := expandStringList(v.([]interface{})) d.Set("custom_san", strings.Join(l, ",")) } // rrsa metadata only for managed, ignore attributes error if data, err := flattenRRSAMetadata(tea.StringValue(object.MetaData)); err != nil { return WrapError(err) } else { d.Set("rrsa_metadata", data) if len(data) > 0 { d.Set("enable_rrsa", data[0]["enabled"].(bool)) } } if object.MaintenanceWindow != nil { d.Set("maintenance_window", flattenMaintenanceWindowConfigRoa(object.MaintenanceWindow)) } if object.OperationPolicy != nil { m := make([]map[string]interface{}, 0) if object.OperationPolicy.ClusterAutoUpgrade != nil { m = append(m, map[string]interface{}{ "cluster_auto_upgrade": []map[string]interface{}{ { "enabled": tea.BoolValue(object.OperationPolicy.ClusterAutoUpgrade.Enabled), "channel": tea.StringValue(object.OperationPolicy.ClusterAutoUpgrade.Channel), }, }, }) } d.Set("operation_policy", m) } // Get slb information and set connect connection := make(map[string]string) masterURL := tea.StringValue(object.MasterUrl) endPoint := make(map[string]string) _ = json.Unmarshal([]byte(masterURL), &endPoint) connection["api_server_internet"] = endPoint["api_server_endpoint"] connection["api_server_intranet"] = endPoint["intranet_api_server_endpoint"] if endPoint["api_server_endpoint"] != "" { connection["master_public_ip"] = strings.Split(strings.Split(endPoint["api_server_endpoint"], ":")[1], "/")[2] } connection["service_domain"] = fmt.Sprintf("*.%s.%s.alicontainer.com", d.Id(), tea.StringValue(object.RegionId)) d.Set("connections", connection) d.Set("slb_internet", connection["master_public_ip"]) if endPoint["intranet_api_server_endpoint"] != "" { d.Set("slb_intranet", strings.Split(strings.Split(endPoint["intranet_api_server_endpoint"], ":")[1], "/")[2]) } // set nat gateway natRequest := vpc.CreateDescribeNatGatewaysRequest() natRequest.VpcId = tea.StringValue(object.VpcId) raw, err := client.WithVpcClient(func(vpcClient *vpc.Client) (interface{}, error) { return vpcClient.DescribeNatGateways(natRequest) }) if err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), natRequest.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(natRequest.GetActionName(), raw, natRequest.RpcRequest, natRequest) nat, _ := raw.(*vpc.DescribeNatGatewaysResponse) if nat != nil && len(nat.NatGateways.NatGateway) > 0 { d.Set("nat_gateway_id", nat.NatGateways.NatGateway[0].NatGatewayId) } // get cluster conn certs // If the cluster is failed, there is no need to get cluster certs if tea.StringValue(object.State) == "failed" || tea.StringValue(object.State) == "delete_failed" || tea.StringValue(object.State) == "deleting" { return nil } if err = setCerts(d, meta, d.Get("skip_set_certificate_authority").(bool)); err != nil { return WrapError(err) } if err = checkControlPlaneLogEnable(d, meta); err != nil { return WrapError(err) } return nil } func resourceAlicloudCSManagedKubernetesUpdate(d *schema.ResourceData, meta interface{}) error { d.Partial(true) invoker := NewInvoker() // modifyCluster if !d.IsNewResource() && d.HasChanges("resource_group_id", "name", "name_prefix", "deletion_protection", "maintenance_window", "operation_policy", "custom_san", "vswitch_ids", "timezone", "security_group_id", "enable_rrsa") { if err := modifyCluster(d, meta, &invoker); err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), "ModifyCluster", AlibabaCloudSdkGoERROR) } } // modify cluster tag if d.HasChange("tags") { err := updateKubernetesClusterTag(d, meta) if err != nil { return WrapErrorf(err, ResponseCodeMsg, d.Id(), "ModifyClusterTags", AlibabaCloudSdkGoERROR) } } // update control plane config if d.HasChanges([]string{"control_plane_log_ttl", "control_plane_log_project", "control_plane_log_components"}...) { if err := updateControlPlaneLog(d, meta); err != nil { return WrapErrorf(err, DefaultErrorMsg, d.Id(), "UpdateControlPlaneLog", AlibabaCloudSdkGoERROR) } } // migrate cluster to pro from standard if d.HasChange("cluster_spec") { err := migrateCluster(d, meta) if err != nil { return WrapError(err) } } err := UpgradeAlicloudKubernetesCluster(d, meta) if err != nil { return WrapError(err) } d.Partial(false) return resourceAlicloudCSManagedKubernetesRead(d, meta) } func UpgradeAlicloudKubernetesCluster(d *schema.ResourceData, meta interface{}) error { if !d.HasChange("version") { return nil } clusterId := d.Id() version := d.Get("version").(string) action := "UpgradeCluster" c := meta.(*connectivity.AliyunClient) rosCsClient, err := c.NewRoaCsClient() if err != nil { return err } args := &roacs.UpgradeClusterRequest{ NextVersion: tea.String(version), } // upgrade cluster var resp *roacs.UpgradeClusterResponse err = resource.Retry(UpgradeClusterTimeout, func() *resource.RetryError { resp, err = rosCsClient.UpgradeCluster(tea.String(clusterId), args) if NeedRetry(err) || resp == nil { return resource.RetryableError(err) } if err != nil { return resource.NonRetryableError(err) } return nil }) if err != nil { return WrapErrorf(err, ResponseCodeMsg, d.Id(), action, err) } taskId := tea.StringValue(resp.Body.TaskId) if taskId == "" { return WrapErrorf(err, ResponseCodeMsg, d.Id(), action, resp) } csClient := CsClient{client: rosCsClient} stateConf := BuildStateConf([]string{}, []string{"success"}, d.Timeout(schema.TimeoutUpdate), 5*time.Second, csClient.DescribeTaskRefreshFunc(d, taskId, []string{"fail", "failed"})) if jobDetail, err := stateConf.WaitForState(); err != nil { // try to cancel task wait := incrementalWait(3*time.Second, 3*time.Second) _ = resource.Retry(5*time.Minute, func() *resource.RetryError { _, _err := rosCsClient.CancelTask(tea.String(taskId)) if _err != nil { if NeedRetry(_err) { wait() return resource.RetryableError(_err) } log.Printf("[WARN] %s ACK Cluster cancel upgrade error: %#v", clusterId, err) } return nil }) // output error message return WrapErrorf(err, ResponseCodeMsg, d.Id(), action, jobDetail) } // ensure cluster state is running csService := CsService{client: c} stateConf = BuildStateConf([]string{}, []string{"running"}, UpgradeClusterTimeout, 10*time.Second, csService.CsKubernetesInstanceStateRefreshFunc(clusterId, []string{"deleting", "failed"})) if _, err := stateConf.WaitForState(); err != nil { return WrapError(err) } d.SetPartial("version") return nil } func migrateAlicloudManagedKubernetesCluster(d *schema.ResourceData, meta interface{}) error { action := "MigrateCluster" client := meta.(*connectivity.AliyunClient) csService := CsService{client} migrateClusterRequest := map[string]string{ "type": "ManagedKubernetes", "spec": d.Get("cluster_spec").(string), } conn, err := meta.(*connectivity.AliyunClient).NewTeaRoaCommonClient(connectivity.OpenAckService) if err != nil { return WrapError(err) } err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err := conn.DoRequestWithAction(StringPointer(action), StringPointer("2015-12-15"), nil, StringPointer("POST"), StringPointer("AK"), String(fmt.Sprintf("/clusters/%s/migrate", d.Id())), nil, nil, migrateClusterRequest, &util.RuntimeOptions{}) if err != nil { if IsExpectedErrors(err, []string{"QPS Limit Exceeded"}) || NeedRetry(err) { return resource.RetryableError(err) } addDebug(action, response, nil) return resource.NonRetryableError(err) } addDebug(action, response, nil) return nil }) stateConf := BuildStateConf([]string{"migrating"}, []string{"running"}, d.Timeout(schema.TimeoutUpdate), 20*time.Second, csService.CsKubernetesInstanceStateRefreshFunc(d.Id(), []string{"deleting", "failed"})) if _, err := stateConf.WaitForState(); err != nil { return err } d.SetPartial("cluster_spec") return nil } func updateKubernetesClusterTag(d *schema.ResourceData, meta interface{}) error { action := "ModifyClusterTags" client := meta.(*connectivity.AliyunClient) csService := CsService{client} var modifyClusterTagsRequest []cs.Tag if tags, err := ConvertCsTags(d); err == nil { modifyClusterTagsRequest = tags } d.SetPartial("tags") conn, err := meta.(*connectivity.AliyunClient).NewTeaRoaCommonClient(connectivity.OpenAckService) if err != nil { return WrapError(err) } err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err := conn.DoRequestWithAction(StringPointer(action), StringPointer("2015-12-15"), nil, StringPointer("POST"), StringPointer("AK"), String(fmt.Sprintf("/clusters/%s/tags", d.Id())), nil, nil, modifyClusterTagsRequest, &util.RuntimeOptions{}) if err != nil { if IsExpectedErrors(err, []string{"QPS Limit Exceeded"}) || NeedRetry(err) { return resource.RetryableError(err) } addDebug(action, response, nil) return resource.NonRetryableError(err) } addDebug(action, response, nil) return nil }) stateConf := BuildStateConf([]string{"updating"}, []string{"running"}, d.Timeout(schema.TimeoutUpdate), 60*time.Second, csService.CsKubernetesInstanceStateRefreshFunc(d.Id(), []string{"deleting", "failed"})) if _, err := stateConf.WaitForState(); err != nil { return err } if err != nil { return err } return nil } // versionCompare check version, // if cueVersion is newer than neededVersion return 1 // if curVersion is equal neededVersion return 0 // if curVersion is older than neededVersion return -1 // example: neededVersion = 1.20.11-aliyun.1, curVersion = 1.22.3-aliyun.1, it will return 1 func versionCompare(neededVersion, curVersion string) (int, error) { if neededVersion == "" || curVersion == "" { if neededVersion == "" && curVersion == "" { return 0, nil } else { if neededVersion == "" { return 1, nil } else { return -1, nil } } } // 取出版本号 regx := regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`) neededVersion = regx.FindString(neededVersion) curVersion = regx.FindString(curVersion) currentVersions := strings.Split(neededVersion, ".") newVersions := strings.Split(curVersion, ".") compare := 0 for index, val := range currentVersions { newVal := newVersions[index] v1, err1 := strconv.Atoi(val) v2, err2 := strconv.Atoi(newVal) if err1 != nil || err2 != nil { return -2, fmt.Errorf("NotSupport, current cluster version is not support: %s", curVersion) } if v1 > v2 { compare = -1 } else if v1 == v2 { compare = 0 } else { compare = 1 } if compare != 0 { break } } return compare, nil } func updateControlPlaneLog(d *schema.ResourceData, meta interface{}) error { request := &roacs.UpdateControlPlaneLogRequest{} client := meta.(*connectivity.AliyunClient) csClient, err := client.NewRoaCsClient() if err != nil { return err } csService := CsService{client} if d.HasChange("control_plane_log_ttl") { if v, ok := d.GetOk("control_plane_log_ttl"); ok { request.LogTtl = tea.String(v.(string)) } } if d.HasChange("control_plane_log_project") { if v, ok := d.GetOk("control_plane_log_project"); ok { request.LogProject = tea.String(v.(string)) } } if d.HasChange("control_plane_log_components") { if v, ok := d.GetOk("control_plane_log_components"); ok { list := v.([]interface{}) components := make([]*string, len(list)) for i, c := range list { components[i] = tea.String(c.(string)) } request.Components = components } } wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { _, err = csClient.UpdateControlPlaneLog(tea.String(d.Id()), request) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return err } stateConf := BuildStateConf([]string{"updating"}, []string{"running"}, d.Timeout(schema.TimeoutUpdate), 60*time.Second, csService.CsKubernetesInstanceStateRefreshFunc(d.Id(), []string{"deleting", "failed"})) if _, err := stateConf.WaitForState(); err != nil { return err } if err != nil { return err } return nil } func checkControlPlaneLogEnable(d *schema.ResourceData, meta interface{}) error { client, err := meta.(*connectivity.AliyunClient).NewRoaCsClient() if err != nil { return err } var response *roacs.CheckControlPlaneLogEnableResponse wait := incrementalWait(3*time.Second, 3*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { response, err = client.CheckControlPlaneLogEnable(tea.String(d.Id())) if err != nil { if NeedRetry(err) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { return err } if response.Body != nil { if response.Body.LogTtl != nil { d.Set("control_plane_log_ttl", *response.Body.LogTtl) } if response.Body.LogProject != nil { d.Set("control_plane_log_project", *response.Body.LogProject) } components := make([]string, len(response.Body.Components)) for i, c := range response.Body.Components { components[i] = *c } d.Set("control_plane_log_components", components) } return nil }