Skip to content

fix(eni): [121355574] tencentcloud_eni_attachment support retry #3043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/3043.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/tencentcloud_eni_attachment: support retry
```
32 changes: 17 additions & 15 deletions tencentcloud/services/vpc/resource_tc_eni_attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ func ResourceTencentCloudEniAttachment() *schema.Resource {

func resourceTencentCloudEniAttachmentCreate(d *schema.ResourceData, m interface{}) error {
defer tccommon.LogElapsed("resource.tencentcloud_eni_attachment.create")()
logId := tccommon.GetLogId(tccommon.ContextNil)
ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId)

var (
logId = tccommon.GetLogId(tccommon.ContextNil)
ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
service = VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}
)

eniId := d.Get("eni_id").(string)
cvmId := d.Get("instance_id").(string)

service := VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}

if err := service.AttachEniToCvm(ctx, eniId, cvmId); err != nil {
return err
}
Expand All @@ -60,8 +62,11 @@ func resourceTencentCloudEniAttachmentRead(d *schema.ResourceData, m interface{}
defer tccommon.LogElapsed("resource.tencentcloud_eni_attachment.read")()
defer tccommon.InconsistentCheck(d, m)()

logId := tccommon.GetLogId(tccommon.ContextNil)
ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
var (
logId = tccommon.GetLogId(tccommon.ContextNil)
ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
service = VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}
)

id := d.Id()
split := strings.Split(id, "+")
Expand All @@ -72,9 +77,6 @@ func resourceTencentCloudEniAttachmentRead(d *schema.ResourceData, m interface{}
}

eniId := split[0]

service := VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}

enis, err := service.DescribeEniById(ctx, []string{eniId})
if err != nil {
return err
Expand All @@ -86,7 +88,6 @@ func resourceTencentCloudEniAttachmentRead(d *schema.ResourceData, m interface{}
}

eni := enis[0]

if eni.Attachment == nil {
d.SetId("")
return nil
Expand All @@ -100,8 +101,12 @@ func resourceTencentCloudEniAttachmentRead(d *schema.ResourceData, m interface{}

func resourceTencentCloudEniAttachmentDelete(d *schema.ResourceData, m interface{}) error {
defer tccommon.LogElapsed("resource.tencentcloud_eni_attachment.delete")()
logId := tccommon.GetLogId(tccommon.ContextNil)
ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId)

var (
logId = tccommon.GetLogId(tccommon.ContextNil)
ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
service = VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}
)

id := d.Id()
split := strings.Split(id, "+")
Expand All @@ -112,8 +117,5 @@ func resourceTencentCloudEniAttachmentDelete(d *schema.ResourceData, m interface
}

eniId, cvmId := split[0], split[1]

service := VpcService{client: m.(tccommon.ProviderMeta).GetAPIV3Conn()}

return service.DetachEniFromCvm(ctx, eniId, cvmId)
}
67 changes: 33 additions & 34 deletions tencentcloud/services/vpc/resource_tc_eni_attachment.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,12 @@ Provides a resource to detailed information of attached backend server to an ENI
Example Usage

```hcl
resource "tencentcloud_vpc" "foo" {
name = "ci-test-eni-vpc"
cidr_block = "10.0.0.0/16"
}

resource "tencentcloud_subnet" "foo" {
availability_zone = "ap-guangzhou-3"
name = "ci-test-eni-subnet"
vpc_id = tencentcloud_vpc.foo.id
cidr_block = "10.0.0.0/16"
is_multicast = false
}

resource "tencentcloud_eni" "foo" {
name = "ci-test-eni"
vpc_id = tencentcloud_vpc.foo.id
subnet_id = tencentcloud_subnet.foo.id
description = "eni desc"
ipv4_count = 1
}

data "tencentcloud_images" "my_favorite_image" {
data "tencentcloud_images" "images" {
image_type = ["PUBLIC_IMAGE"]
os_name = "centos"
}

data "tencentcloud_instance_types" "my_favorite_instance_types" {
data "tencentcloud_instance_types" "instance_types" {
filter {
name = "instance-family"
values = ["S3"]
Expand All @@ -39,24 +18,44 @@ data "tencentcloud_instance_types" "my_favorite_instance_types" {
memory_size = 1
}

data "tencentcloud_availability_zones" "my_favorite_zones" {
data "tencentcloud_availability_zones" "zones" {}

resource "tencentcloud_vpc" "vpc" {
name = "ci-test-eni-vpc"
cidr_block = "10.0.0.0/16"
}

resource "tencentcloud_subnet" "subnet" {
availability_zone = "ap-guangzhou-3"
name = "ci-test-eni-subnet"
vpc_id = tencentcloud_vpc.vpc.id
cidr_block = "10.0.0.0/16"
is_multicast = false
}

resource "tencentcloud_eni" "eni" {
name = "ci-test-eni"
vpc_id = tencentcloud_vpc.vpc.id
subnet_id = tencentcloud_subnet.subnet.id
description = "eni desc"
ipv4_count = 1
}

resource "tencentcloud_instance" "foo" {
resource "tencentcloud_instance" "example" {
instance_name = "ci-test-eni-attach"
availability_zone = data.tencentcloud_availability_zones.my_favorite_zones.zones.0.name
image_id = data.tencentcloud_images.my_favorite_image.images.0.image_id
instance_type = data.tencentcloud_instance_types.my_favorite_instance_types.instance_types.0.instance_type
availability_zone = data.tencentcloud_availability_zones.zones.zones.0.name
image_id = data.tencentcloud_images.images.images.0.image_id
instance_type = data.tencentcloud_instance_types.instance_types.instance_types.0.instance_type
system_disk_type = "CLOUD_PREMIUM"
disable_security_service = true
disable_monitor_service = true
vpc_id = tencentcloud_vpc.foo.id
subnet_id = tencentcloud_subnet.foo.id
vpc_id = tencentcloud_vpc.vpc.id
subnet_id = tencentcloud_subnet.subnet.id
}

resource "tencentcloud_eni_attachment" "foo" {
eni_id = tencentcloud_eni.foo.id
instance_id = tencentcloud_instance.foo.id
resource "tencentcloud_eni_attachment" "example" {
eni_id = tencentcloud_eni.eni.id
instance_id = tencentcloud_instance.example.id
}
```

Expand All @@ -65,5 +64,5 @@ Import
ENI attachment can be imported using the id, e.g.

```
$ terraform import tencentcloud_eni_attachment.foo eni-gtlvkjvz+ins-0h3a5new
terraform import tencentcloud_eni_attachment.example eni-gtlvkjvz+ins-0h3a5new
```
42 changes: 37 additions & 5 deletions tencentcloud/services/vpc/service_tencentcloud_vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3042,6 +3042,10 @@ func (me *VpcService) describeEnis(
return tccommon.RetryError(err)
}

if response == nil && response.Response == nil && response.Response.NetworkInterfaceSet == nil {
return resource.NonRetryableError(fmt.Errorf("Read eni list failed, Response is nil."))
}

eniSet := response.Response.NetworkInterfaceSet
count = len(eniSet)
enis = append(enis, eniSet...)
Expand Down Expand Up @@ -3295,24 +3299,36 @@ func (me *VpcService) AttachEniToCvm(ctx context.Context, eniId, cvmId string) e
client := me.client.UseVpcClient()

attachRequest := vpc.NewAttachNetworkInterfaceRequest()
attachResponse := vpc.NewAttachNetworkInterfaceResponse()
attachRequest.NetworkInterfaceId = &eniId
attachRequest.InstanceId = &cvmId

if err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError {
ratelimit.Check(attachRequest.GetAction())

if _, err := client.AttachNetworkInterface(attachRequest); err != nil {
result, err := client.AttachNetworkInterface(attachRequest)
if err != nil {
log.Printf("[CRITAL]%s api[%s] fail, request body [%s], reason[%v]",
logId, attachRequest.GetAction(), attachRequest.ToJsonString(), err)
return tccommon.RetryError(err)
}

if result == nil || result.Response == nil || result.Response.RequestId == nil {
return resource.NonRetryableError(fmt.Errorf("Attach eni to instance failed, Response is nil."))
}

attachResponse = result
return nil
}); err != nil {
log.Printf("[CRITAL]%s attach eni to instance failed, reason: %v", logId, err)
return err
}

// wait
err := me.DescribeVpcTaskResult(ctx, attachResponse.Response.RequestId)
if err != nil {
return err
}

describeRequest := vpc.NewDescribeNetworkInterfacesRequest()
describeRequest.NetworkInterfaceIds = []*string{&eniId}

Expand Down Expand Up @@ -3390,13 +3406,14 @@ func (me *VpcService) DetachEniFromCvm(ctx context.Context, eniId, cvmId string)
client := me.client.UseVpcClient()

request := vpc.NewDetachNetworkInterfaceRequest()
response := vpc.NewDetachNetworkInterfaceResponse()
request.NetworkInterfaceId = &eniId
request.InstanceId = &cvmId

if err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError {
ratelimit.Check(request.GetAction())

if _, err := client.DetachNetworkInterface(request); err != nil {
result, err := client.DetachNetworkInterface(request)
if err != nil {
if sdkError, ok := err.(*sdkErrors.TencentCloudSDKError); ok {
switch sdkError.Code {
case "UnsupportedOperation.InvalidState":
Expand All @@ -3413,12 +3430,23 @@ func (me *VpcService) DetachEniFromCvm(ctx context.Context, eniId, cvmId string)
return tccommon.RetryError(err)
}

if result == nil || result.Response == nil || result.Response.RequestId == nil {
return resource.NonRetryableError(fmt.Errorf("Detach eni from instance failed, Response is nil."))
}

response = result
return nil
}); err != nil {
log.Printf("[CRITAL]%s detach eni from instance failed, reason: %v", logId, err)
return err
}

// wait
err := me.DescribeVpcTaskResult(ctx, response.Response.RequestId)
if err != nil {
return err
}

if err := waitEniDetach(ctx, eniId, client); err != nil {
log.Printf("[CRITAL]%s detach eni from instance failed, reason: %v", logId, err)
return err
Expand Down Expand Up @@ -5001,29 +5029,33 @@ func (me *VpcService) DescribeVpnGatewayRoutes(ctx context.Context, vpnGatewayId
}

func (me *VpcService) DescribeVpcTaskResult(ctx context.Context, taskId *string) (err error) {

logId := tccommon.GetLogId(ctx)
request := vpc.NewDescribeVpcTaskResultRequest()
defer func() {
if err != nil {
log.Printf("[CRITAL]%s api[%s] fail,reason[%s]", logId, request.GetAction(), err.Error())
}
}()

request.TaskId = taskId
err = resource.Retry(tccommon.ReadRetryTimeout, func() *resource.RetryError {
ratelimit.Check(request.GetAction())
response, err := me.client.UseVpcClient().DescribeVpcTaskResult(request)
if err != nil {
return tccommon.RetryError(err)
}

if response.Response.Status != nil && *response.Response.Status == VPN_TASK_STATUS_RUNNING {
return resource.RetryableError(errors.New("VPN task is running"))
}

return nil
})

if err != nil {
return err
}

return
}

Expand Down
Loading
Loading