diff --git a/.changelog/3009.txt b/.changelog/3009.txt new file mode 100644 index 0000000000..04c18ba680 --- /dev/null +++ b/.changelog/3009.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/tencentcloud_clb_instance: spport `eip_address_id` +``` \ No newline at end of file diff --git a/tencentcloud/services/clb/resource_tc_clb_instance.go b/tencentcloud/services/clb/resource_tc_clb_instance.go index ad2f46f45d..edbc7347e9 100644 --- a/tencentcloud/services/clb/resource_tc_clb_instance.go +++ b/tencentcloud/services/clb/resource_tc_clb_instance.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/pkg/errors" clb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317" + vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312" "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" ) @@ -218,6 +219,11 @@ func ResourceTencentCloudClbInstance() *schema.Resource { Optional: true, Description: "If create dynamic vip CLB instance, `true` or `false`.", }, + "eip_address_id": { + Type: schema.TypeString, + Optional: true, + Description: "The unique ID of the EIP, such as eip-1v2rmbwk, is only applicable to the intranet load balancing binding EIP. During the EIP change, there may be a brief network interruption.", + }, "domain": { Type: schema.TypeString, Computed: true, @@ -406,6 +412,10 @@ func resourceTencentCloudClbInstanceCreate(d *schema.ResourceData, meta interfac request.DynamicVip = helper.Bool(v.(bool)) } + if v, ok := d.GetOk("eip_address_id"); ok { + request.EipAddressId = helper.String(v.(string)) + } + if tags := helper.GetTags(d, "tags"); len(tags) > 0 { for k, v := range tags { tmpKey := k @@ -675,6 +685,40 @@ func resourceTencentCloudClbInstanceRead(d *schema.ResourceData, meta interface{ _ = d.Set("snat_pro", instance.SnatPro) } + if *instance.LoadBalancerType == "INTERNAL" { + request := vpc.NewDescribeAddressesRequest() + request.Filters = []*vpc.Filter{ + { + Name: helper.String("instance-id"), + Values: helper.Strings([]string{clbId}), + }, + } + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().DescribeAddresses(request) + if e != nil { + return tccommon.RetryError(e) + } + + if result == nil || result.Response == nil || result.Response.AddressSet == nil { + e = fmt.Errorf("Describe CLB instance EIP failed") + return resource.NonRetryableError(e) + } + + if len(result.Response.AddressSet) == 1 { + if result.Response.AddressSet[0].AddressId != nil { + _ = d.Set("eip_address_id", result.Response.AddressSet[0].AddressId) + } + } + + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s Describe CLB instance EIP failed, reason:%+v", logId, err) + return err + } + } + tcClient := meta.(tccommon.ProviderMeta).GetAPIV3Conn() tagService := svctag.NewTagService(tcClient) tags, err := tagService.DescribeResourceTags(ctx, "clb", "clb", tcClient.Region, d.Id()) @@ -932,6 +976,102 @@ func resourceTencentCloudClbInstanceUpdate(d *schema.ResourceData, meta interfac } } + if d.HasChange("eip_address_id") { + oldEip, newEip := d.GetChange("eip_address_id") + oldEipStr := oldEip.(string) + newEipStr := newEip.(string) + // delete old first + if oldEipStr != "" { + request := vpc.NewDisassociateAddressRequest() + request.AddressId = helper.String(oldEipStr) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + _, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().DisassociateAddress(request) + if e != nil { + return tccommon.RetryError(e) + } + + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s Disassociate EIP failed, reason:%+v", logId, err) + return err + } + + // wait + eipRequest := vpc.NewDescribeAddressesRequest() + eipRequest.AddressIds = helper.Strings([]string{oldEipStr}) + err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().DescribeAddresses(eipRequest) + if e != nil { + return tccommon.RetryError(e) + } + + if result == nil || result.Response == nil || result.Response.AddressSet == nil || len(result.Response.AddressSet) != 1 { + e = fmt.Errorf("Describe CLB instance EIP failed") + return resource.NonRetryableError(e) + } + + if *result.Response.AddressSet[0].AddressStatus != "UNBIND" { + return resource.RetryableError(fmt.Errorf("EIP status is still %s", *result.Response.AddressSet[0].AddressStatus)) + } + + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s Describe CLB instance EIP failed, reason:%+v", logId, err) + return err + } + } + + // attach new + if newEipStr != "" { + request := vpc.NewAssociateAddressRequest() + request.AddressId = helper.String(newEipStr) + request.InstanceId = helper.String(clbId) + err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + _, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().AssociateAddress(request) + if e != nil { + return tccommon.RetryError(e) + } + + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s Associate EIP failed, reason:%+v", logId, err) + return err + } + + // wait + eipRequest := vpc.NewDescribeAddressesRequest() + eipRequest.AddressIds = helper.Strings([]string{newEipStr}) + err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().DescribeAddresses(eipRequest) + if e != nil { + return tccommon.RetryError(e) + } + + if result == nil || result.Response == nil || result.Response.AddressSet == nil || len(result.Response.AddressSet) != 1 { + e = fmt.Errorf("Describe CLB instance EIP failed") + return resource.NonRetryableError(e) + } + + if *result.Response.AddressSet[0].AddressStatus != "BIND" { + return resource.RetryableError(fmt.Errorf("EIP status is still %s", *result.Response.AddressSet[0].AddressStatus)) + } + + return nil + }) + + if err != nil { + log.Printf("[CRITAL]%s Describe CLB instance EIP failed, reason:%+v", logId, err) + return err + } + } + } + if d.HasChange("tags") { oldValue, newValue := d.GetChange("tags") replaceTags, deleteTags := svctag.DiffTags(oldValue.(map[string]interface{}), newValue.(map[string]interface{})) diff --git a/tencentcloud/services/clb/resource_tc_clb_instance.md b/tencentcloud/services/clb/resource_tc_clb_instance.md index 3a8139ddcb..f2f70ea270 100644 --- a/tencentcloud/services/clb/resource_tc_clb_instance.md +++ b/tencentcloud/services/clb/resource_tc_clb_instance.md @@ -38,6 +38,43 @@ resource "tencentcloud_clb_instance" "example" { } ``` +Create CLB with eip_address_id, Only support INTERNAL CLB + +```hcl +variable "availability_zone" { + default = "ap-guangzhou-4" +} + +// create vpc +resource "tencentcloud_vpc" "vpc" { + cidr_block = "10.0.0.0/16" + name = "vpc" +} + +// create subnet +resource "tencentcloud_subnet" "subnet" { + vpc_id = tencentcloud_vpc.vpc.id + availability_zone = var.availability_zone + name = "subnet" + cidr_block = "10.0.1.0/24" + is_multicast = false +} + +// create clb +resource "tencentcloud_clb_instance" "example" { + network_type = "INTERNAL" + clb_name = "tf-example" + project_id = 0 + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + eip_address_id = "eip-lt0w6jhq" + + tags = { + tagKey = "tagValue" + } +} +``` + Create dedicated cluster clb ```hcl diff --git a/website/docs/r/clb_instance.html.markdown b/website/docs/r/clb_instance.html.markdown index 7e74232202..9d3770993f 100644 --- a/website/docs/r/clb_instance.html.markdown +++ b/website/docs/r/clb_instance.html.markdown @@ -49,6 +49,43 @@ resource "tencentcloud_clb_instance" "example" { } ``` +### Create CLB with eip_address_id, Only support INTERNAL CLB + +```hcl +variable "availability_zone" { + default = "ap-guangzhou-4" +} + +// create vpc +resource "tencentcloud_vpc" "vpc" { + cidr_block = "10.0.0.0/16" + name = "vpc" +} + +// create subnet +resource "tencentcloud_subnet" "subnet" { + vpc_id = tencentcloud_vpc.vpc.id + availability_zone = var.availability_zone + name = "subnet" + cidr_block = "10.0.1.0/24" + is_multicast = false +} + +// create clb +resource "tencentcloud_clb_instance" "example" { + network_type = "INTERNAL" + clb_name = "tf-example" + project_id = 0 + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + eip_address_id = "eip-lt0w6jhq" + + tags = { + tagKey = "tagValue" + } +} +``` + ### Create dedicated cluster clb ```hcl @@ -486,6 +523,7 @@ The following arguments are supported: * `cluster_id` - (Optional, String, ForceNew) Cluster ID. * `delete_protect` - (Optional, Bool) Whether to enable delete protection. * `dynamic_vip` - (Optional, Bool) If create dynamic vip CLB instance, `true` or `false`. +* `eip_address_id` - (Optional, String) The unique ID of the EIP, such as eip-1v2rmbwk, is only applicable to the intranet load balancing binding EIP. During the EIP change, there may be a brief network interruption. * `internet_bandwidth_max_out` - (Optional, Int) Max bandwidth out, only applicable to open CLB. Valid value ranges is [1, 2048]. Unit is MB. * `internet_charge_type` - (Optional, String) Internet charge type, only applicable to open CLB. Valid values are `TRAFFIC_POSTPAID_BY_HOUR`, `BANDWIDTH_POSTPAID_BY_HOUR` and `BANDWIDTH_PACKAGE`. * `load_balancer_pass_to_target` - (Optional, Bool) Whether the target allow flow come from clb. If value is true, only check security group of clb, or check both clb and backend instance security group.