From 9724e36c5aa793e732577e3af44baaf6fcbf8b0b Mon Sep 17 00:00:00 2001 From: KGSN Date: Wed, 5 Jan 2022 17:41:11 +0800 Subject: [PATCH] fix: nat dettach ip error --- tencentcloud/extension_vpc.go | 4 +- tencentcloud/resource_tc_eip.go | 4 +- tencentcloud/resource_tc_nat_gateway.go | 11 +- tencentcloud/resource_tc_nat_gateway_test.go | 3 - tencentcloud/service_tencentcloud_vpc.go | 111 +++++++++++++++++++ 5 files changed, 119 insertions(+), 14 deletions(-) diff --git a/tencentcloud/extension_vpc.go b/tencentcloud/extension_vpc.go index a722f39674..c38a7b01d9 100644 --- a/tencentcloud/extension_vpc.go +++ b/tencentcloud/extension_vpc.go @@ -40,8 +40,8 @@ const ( EIP_STATUS_OFFLINING = "OFFLINING" EIP_STATUS_BIND_ENI = "BIND_ENI" - EIP_TYPE_EIP = "EIP" - EIP_TYPE_ANYCAST = "AnycastEIP" + EIP_TYPE_EIP = "EIP" + EIP_TYPE_ANYCAST = "AnycastEIP" EIP_TYPE_HIGH_QUALITY = "HighQualityEIP" EIP_ANYCAST_ZONE_GLOBAL = "ANYCAST_ZONE_GLOBAL" diff --git a/tencentcloud/resource_tc_eip.go b/tencentcloud/resource_tc_eip.go index db0a024a59..cc7af82636 100644 --- a/tencentcloud/resource_tc_eip.go +++ b/tencentcloud/resource_tc_eip.go @@ -320,8 +320,8 @@ func resourceTencentCloudEipDelete(d *schema.ResourceData, meta interface{}) err err = resource.Retry(writeRetryTimeout, func() *resource.RetryError { errRet := vpcService.DeleteEip(ctx, eipId) - if err != nil { - return retryError(errRet) + if errRet != nil { + return retryError(errRet, "DesOperation.MutexTaskRunning") } return nil }) diff --git a/tencentcloud/resource_tc_nat_gateway.go b/tencentcloud/resource_tc_nat_gateway.go index 35178c106d..49ba7bcfa7 100644 --- a/tencentcloud/resource_tc_nat_gateway.go +++ b/tencentcloud/resource_tc_nat_gateway.go @@ -240,6 +240,8 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface defer logElapsed("resource.tencentcloud_nat_gateway.update")() logId := getLogId(contextNil) + ctx := context.WithValue(context.TODO(), logIdKey, logId) + vpcService := VpcService{client: meta.(*TencentCloudClient).apiV3Conn} d.Partial(true) natGatewayId := d.Id() @@ -343,10 +345,8 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface if len(unassignedRequest.PublicIpAddresses) > 0 { err := resource.Retry(readRetryTimeout, func() *resource.RetryError { - _, e := meta.(*TencentCloudClient).apiV3Conn.UseVpcClient().DisassociateNatGatewayAddress(unassignedRequest) + e := vpcService.DisassociateNatGatewayAddress(ctx, unassignedRequest) if e != nil { - log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", - logId, unassignedRequest.GetAction(), unassignedRequest.ToJsonString(), e.Error()) return retryError(e) } return nil @@ -403,10 +403,8 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface unassignedRequest.NatGatewayId = &natGatewayId unassignedRequest.PublicIpAddresses = []*string{&backUpOldIp} err := resource.Retry(readRetryTimeout, func() *resource.RetryError { - _, e := meta.(*TencentCloudClient).apiV3Conn.UseVpcClient().DisassociateNatGatewayAddress(unassignedRequest) + e := vpcService.DisassociateNatGatewayAddress(ctx, unassignedRequest) if e != nil { - log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%s]\n", - logId, unassignedRequest.GetAction(), unassignedRequest.ToJsonString(), e.Error()) return retryError(e) } return nil @@ -440,7 +438,6 @@ func resourceTencentCloudNatGatewayUpdate(d *schema.ResourceData, meta interface } - ctx := context.WithValue(context.TODO(), logIdKey, logId) if d.HasChange("tags") { oldValue, newValue := d.GetChange("tags") diff --git a/tencentcloud/resource_tc_nat_gateway_test.go b/tencentcloud/resource_tc_nat_gateway_test.go index 0c2bdbe3b2..d553080f2d 100644 --- a/tencentcloud/resource_tc_nat_gateway_test.go +++ b/tencentcloud/resource_tc_nat_gateway_test.go @@ -145,9 +145,6 @@ data "tencentcloud_vpc_instances" "foo" { # Create EIP resource "tencentcloud_eip" "eip_dev_dnat" { name = "terraform_test" - } -resource "tencentcloud_eip" "eip_test_dnat" { - name = "terraform_test" } resource "tencentcloud_eip" "new_eip" { name = "terraform_test" diff --git a/tencentcloud/service_tencentcloud_vpc.go b/tencentcloud/service_tencentcloud_vpc.go index 1b479a3889..3903457ef7 100644 --- a/tencentcloud/service_tencentcloud_vpc.go +++ b/tencentcloud/service_tencentcloud_vpc.go @@ -2025,6 +2025,91 @@ func (me *VpcService) AttachEip(ctx context.Context, eipId, instanceId string) e return nil } +func (me *VpcService) DescribeNatGatewayById(ctx context.Context, natGateWayId string) (natGateWay *vpc.NatGateway, errRet error) { + logId := getLogId(ctx) + request := vpc.NewDescribeNatGatewaysRequest() + request.NatGatewayIds = []*string{&natGateWayId} + 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.UseVpcClient().DescribeNatGateways(request) + + if err != nil { + errRet = err + return + } + + log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", + logId, request.GetAction(), request.ToJsonString(), response.ToJsonString()) + + if len(response.Response.NatGatewaySet) > 0 { + natGateWay = response.Response.NatGatewaySet[0] + } + + return +} + +func (me *VpcService) DisassociateNatGatewayAddress(ctx context.Context, request *vpc.DisassociateNatGatewayAddressRequest) (errRet error) { + logId := getLogId(ctx) + 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()) + } + }() + + // Check if Nat Gateway Ip still associate + gateway, err := me.DescribeNatGatewayById(ctx, *request.NatGatewayId) + + if err != nil { + errRet = err + return + } + + if gateway == nil || len(gateway.PublicIpAddressSet) == 0 { + return + } + + var gatewayAddresses []string + var candidates []*string + + for i := range gateway.PublicIpAddressSet { + addr := gateway.PublicIpAddressSet[i].PublicIpAddress + gatewayAddresses = append(gatewayAddresses, *addr) + } + + for i := range request.PublicIpAddresses { + addr := request.PublicIpAddresses[i] + if helper.StringsContain(gatewayAddresses, *addr) { + candidates = append(candidates, addr) + } + } + + if len(candidates) == 0 { + return nil + } + + request.PublicIpAddresses = candidates + + ratelimit.Check(request.GetAction()) + response, err := me.client.UseVpcClient().DisassociateNatGatewayAddress(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 +} + func (me *VpcService) UnattachEip(ctx context.Context, eipId string) error { eipUnattachLocker.Lock() defer eipUnattachLocker.Unlock() @@ -2038,6 +2123,32 @@ func (me *VpcService) UnattachEip(ctx context.Context, eipId string) error { return nil } + // DisassociateAddress Doesn't support Disassociate NAT Address + if strings.HasPrefix(*eip.InstanceId, "nat-") { + request := vpc.NewDisassociateNatGatewayAddressRequest() + request.NatGatewayId = eip.InstanceId + request.PublicIpAddresses = []*string{eip.AddressIp} + err := me.DisassociateNatGatewayAddress(ctx, request) + if err != nil { + return err + } + + outErr := resource.Retry(readRetryTimeout*3, func() *resource.RetryError { + eip, err := me.DescribeEipById(ctx, eipId) + if err != nil { + return retryError(err) + } + if eip != nil && *eip.AddressStatus != EIP_STATUS_UNBIND { + return resource.RetryableError(fmt.Errorf("eip is still %s", EIP_STATUS_UNBIND)) + } + return nil + }) + + if outErr != nil { + return outErr + } + } + request := vpc.NewDisassociateAddressRequest() request.AddressId = &eipId ratelimit.Check(request.GetAction())