From 1338d26c2d4dacb01357b6a3fe3f8fb282a6102d Mon Sep 17 00:00:00 2001 From: xuyaming Date: Wed, 21 Jun 2023 17:22:35 +0800 Subject: [PATCH 1/5] feat: support unsubscribe --- common/common_volcengine_dispatcher.go | 18 +++- common/common_volcengine_unsubscribe.go | 91 +++++++++++++++++++ .../service_volcengine_ecs_instance.go | 12 +++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 common/common_volcengine_unsubscribe.go diff --git a/common/common_volcengine_dispatcher.go b/common/common_volcengine_dispatcher.go index 5324328a..75c320df 100644 --- a/common/common_volcengine_dispatcher.go +++ b/common/common_volcengine_dispatcher.go @@ -211,7 +211,23 @@ func (d *Dispatcher) Delete(resourceService ResourceService, resourceDate *schem } } } - callbacks := resourceService.RemoveResource(resourceDate, resource) + var ( + callbacks []Callback + unsubscribeInfo *UnsubscribeInfo + ) + + // 自动退订逻辑 + if unsubscribeEnabled, ok := resourceService.(UnsubscribeEnabled); ok { + unsubscribeInfo = unsubscribeEnabled.UnsubscribeInfo(resourceDate, resource) + } + + if unsubscribeInfo != nil && unsubscribeInfo.NeedUnsubscribe { + unsubscribeCallback := NewUnsubscribeService(resourceService.GetClient()).UnsubscribeInstance(unsubscribeInfo) + callbacks = append(callbacks, unsubscribeCallback...) + } else { + callbacks = resourceService.RemoveResource(resourceDate, resource) + } + var calls []SdkCall for _, callback := range callbacks { if callback.Err != nil { diff --git a/common/common_volcengine_unsubscribe.go b/common/common_volcengine_unsubscribe.go new file mode 100644 index 00000000..35a44cf8 --- /dev/null +++ b/common/common_volcengine_unsubscribe.go @@ -0,0 +1,91 @@ +package common + +import ( + "context" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/volcengine/terraform-provider-volcengine/logger" + "golang.org/x/sync/semaphore" + "golang.org/x/time/rate" +) + +type UnsubscribeEnabled interface { + // UnsubscribeInfo 判断是否需要退订 + UnsubscribeInfo(*schema.ResourceData, *schema.Resource) *UnsubscribeInfo +} + +type UnsubscribeInfo struct { + Product string + InstanceId string + NeedUnsubscribe bool +} + +var unsubscribeRate *Rate + +func init() { + unsubscribeRate = &Rate{ + Limiter: rate.NewLimiter(10, 10), + Semaphore: semaphore.NewWeighted(20), + } +} + +type UnsubscribeService struct { + Client *SdkClient +} + +func NewUnsubscribeService(c *SdkClient) *UnsubscribeService { + return &UnsubscribeService{ + Client: c, + } +} + +func (u *UnsubscribeService) UnsubscribeInstance(info *UnsubscribeInfo) []Callback { + var call []Callback + unsubscribe := Callback{ + Call: SdkCall{ + Action: "UnsubscribeInstance", + ConvertMode: RequestConvertIgnore, + ContentType: ContentTypeJson, + BeforeCall: func(d *schema.ResourceData, client *SdkClient, call SdkCall) (bool, error) { + (*call.SdkParam)["InstanceID"] = info.InstanceId + (*call.SdkParam)["Product"] = info.Product + (*call.SdkParam)["UnsubscribeRelatedInstance"] = false + (*call.SdkParam)["ClientToken"] = uuid.New().String() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *SdkClient, call SdkCall) (*map[string]interface{}, error) { + defer func() { + unsubscribeRate.Semaphore.Release(1) + }() + var err error + ctx := context.Background() + err = unsubscribeRate.Limiter.Wait(ctx) + if err != nil { + return nil, err + } + err = unsubscribeRate.Semaphore.Acquire(ctx, 1) + if err != nil { + return nil, err + } + + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return u.Client.UniversalClient.DoCall(u.getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *SdkClient, resp *map[string]interface{}, call SdkCall) error { + return nil + }, + }, + } + call = append(call, unsubscribe) + return call +} + +func (u *UnsubscribeService) getUniversalInfo(actionName string) UniversalInfo { + return UniversalInfo{ + ServiceName: "billing", + Version: "2022-01-01", + HttpMethod: POST, + Action: actionName, + } +} diff --git a/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go b/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go index 185b69a2..1bbf6642 100644 --- a/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go +++ b/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go @@ -1420,3 +1420,15 @@ func (s *VolcengineEcsService) ProjectTrn() *ve.ProjectTrn { ProjectSchemaField: "project_name", } } + +func (s *VolcengineEcsService) UnsubscribeInfo(resourceData *schema.ResourceData, resource *schema.Resource) *ve.UnsubscribeInfo { + info := ve.UnsubscribeInfo{ + Product: "ECS", + InstanceId: s.ReadResourceId(resourceData.Id()), + } + //这里需要区分下不同的ecs实例 + if resourceData.Get("instance_charge_type") == "PrePaid" { + info.NeedUnsubscribe = true + } + return &info +} From d878066a6893547b0a1dd6146edeb0bb684b9691 Mon Sep 17 00:00:00 2001 From: xuyaming Date: Mon, 26 Jun 2023 17:33:21 +0800 Subject: [PATCH 2/5] bugfix: fix acl entry computed in acl provider --- common/common_volcengine_callback_test.go | 10 +++--- common/common_volcengine_dispatcher.go | 5 ++- common/common_volcengine_error.go | 10 ++++-- common/common_volcengine_unsubscribe.go | 32 ++++++++++++++--- .../service_volcengine_ecs_instance.go | 36 ++++++++++++++++--- 5 files changed, 76 insertions(+), 17 deletions(-) diff --git a/common/common_volcengine_callback_test.go b/common/common_volcengine_callback_test.go index 9f519cfe..ffcd17e4 100644 --- a/common/common_volcengine_callback_test.go +++ b/common/common_volcengine_callback_test.go @@ -16,12 +16,12 @@ func TestSortAndStartTransJson1(t *testing.T) { "ClusterId": "12345", }, } - resp := SortAndStartTransJson(req) + resp, _ := SortAndStartTransJson(req) assert.Equal(t, resp, target) } func TestSortAndStartTransJson2(t *testing.T) { - req := SortAndStartTransJson(map[string]interface{}{ + req, _ := SortAndStartTransJson(map[string]interface{}{ "Filter.Ids.1": "id123", "Filter.Ids.2": "id456", }) @@ -30,12 +30,12 @@ func TestSortAndStartTransJson2(t *testing.T) { "Ids": []interface{}{"id123", "id456"}, }, } - resp := SortAndStartTransJson(req) + resp, _ := SortAndStartTransJson(req) assert.Equal(t, resp, target) } func TestSortAndStartTransJson3(t *testing.T) { - req := SortAndStartTransJson(map[string]interface{}{ + req, _ := SortAndStartTransJson(map[string]interface{}{ "Filter.ClusterId": "12345", "Filter.Ids.1": "id123", "Filter.Ids.2": "id456", @@ -61,7 +61,7 @@ func TestSortAndStartTransJson3(t *testing.T) { }, }, } - resp := SortAndStartTransJson(req) + resp, _ := SortAndStartTransJson(req) assert.Equal(t, resp, target) str := `{"Filter":{"ClusterId":"12345","Ids":["id123","id456"],"Nets":[{"Subnet":"subnet1"},{"Subnet":"subnet2"},{"Subnet":"subnet3"}]}}` diff --git a/common/common_volcengine_dispatcher.go b/common/common_volcengine_dispatcher.go index 75c320df..419af26e 100644 --- a/common/common_volcengine_dispatcher.go +++ b/common/common_volcengine_dispatcher.go @@ -218,7 +218,10 @@ func (d *Dispatcher) Delete(resourceService ResourceService, resourceDate *schem // 自动退订逻辑 if unsubscribeEnabled, ok := resourceService.(UnsubscribeEnabled); ok { - unsubscribeInfo = unsubscribeEnabled.UnsubscribeInfo(resourceDate, resource) + unsubscribeInfo, err = unsubscribeEnabled.UnsubscribeInfo(resourceDate, resource) + if err != nil { + return err + } } if unsubscribeInfo != nil && unsubscribeInfo.NeedUnsubscribe { diff --git a/common/common_volcengine_error.go b/common/common_volcengine_error.go index 60450242..41495a94 100644 --- a/common/common_volcengine_error.go +++ b/common/common_volcengine_error.go @@ -24,8 +24,14 @@ func ResourceNotFoundError(err error) bool { } func ResourceFlowLimitExceededError(err error) bool { - errMessage := strings.ToLower(err.Error()) - if strings.Contains(errMessage, "FlowLimitExceeded") { + if strings.Contains(err.Error(), "FlowLimitExceeded") { + return true + } + return false +} + +func UnsubscribeProductError(err error) bool { + if strings.Contains(err.Error(), "The product code is inconsistent with the instance product") { return true } return false diff --git a/common/common_volcengine_unsubscribe.go b/common/common_volcengine_unsubscribe.go index 35a44cf8..48f4b2d6 100644 --- a/common/common_volcengine_unsubscribe.go +++ b/common/common_volcengine_unsubscribe.go @@ -2,8 +2,11 @@ package common import ( "context" + "fmt" + "time" "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/volcengine/terraform-provider-volcengine/logger" "golang.org/x/sync/semaphore" @@ -12,13 +15,14 @@ import ( type UnsubscribeEnabled interface { // UnsubscribeInfo 判断是否需要退订 - UnsubscribeInfo(*schema.ResourceData, *schema.Resource) *UnsubscribeInfo + UnsubscribeInfo(*schema.ResourceData, *schema.Resource) (*UnsubscribeInfo, error) } type UnsubscribeInfo struct { - Product string + Products []string InstanceId string NeedUnsubscribe bool + productIndex int } var unsubscribeRate *Rate @@ -42,6 +46,9 @@ func NewUnsubscribeService(c *SdkClient) *UnsubscribeService { func (u *UnsubscribeService) UnsubscribeInstance(info *UnsubscribeInfo) []Callback { var call []Callback + if len(info.Products) == 0 || info.InstanceId == "" { + return call + } unsubscribe := Callback{ Call: SdkCall{ Action: "UnsubscribeInstance", @@ -49,8 +56,7 @@ func (u *UnsubscribeService) UnsubscribeInstance(info *UnsubscribeInfo) []Callba ContentType: ContentTypeJson, BeforeCall: func(d *schema.ResourceData, client *SdkClient, call SdkCall) (bool, error) { (*call.SdkParam)["InstanceID"] = info.InstanceId - (*call.SdkParam)["Product"] = info.Product - (*call.SdkParam)["UnsubscribeRelatedInstance"] = false + (*call.SdkParam)["UnsubscribeRelatedInstance"] = true (*call.SdkParam)["ClientToken"] = uuid.New().String() return true, nil }, @@ -69,12 +75,30 @@ func (u *UnsubscribeService) UnsubscribeInstance(info *UnsubscribeInfo) []Callba return nil, err } + (*call.SdkParam)["Product"] = info.Products[info.productIndex] logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) return u.Client.UniversalClient.DoCall(u.getUniversalInfo(call.Action), call.SdkParam) }, AfterCall: func(d *schema.ResourceData, client *SdkClient, resp *map[string]interface{}, call SdkCall) error { return nil }, + CallError: func(d *schema.ResourceData, client *SdkClient, call SdkCall, baseErr error) error { + return resource.Retry(15*time.Minute, func() *resource.RetryError { + if UnsubscribeProductError(baseErr) { + info.productIndex = info.productIndex + 1 + if info.productIndex >= len(info.Products) { + return resource.NonRetryableError(fmt.Errorf(" Can not support this instance %s Unsubscribe", info.InstanceId)) + } + _, callErr := call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + } else { + return resource.NonRetryableError(baseErr) + } + }) + }, }, } call = append(call, unsubscribe) diff --git a/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go b/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go index 1bbf6642..59992095 100644 --- a/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go +++ b/volcengine/ecs/ecs_instance/service_volcengine_ecs_instance.go @@ -1421,14 +1421,40 @@ func (s *VolcengineEcsService) ProjectTrn() *ve.ProjectTrn { } } -func (s *VolcengineEcsService) UnsubscribeInfo(resourceData *schema.ResourceData, resource *schema.Resource) *ve.UnsubscribeInfo { +func (s *VolcengineEcsService) UnsubscribeInfo(resourceData *schema.ResourceData, resource *schema.Resource) (*ve.UnsubscribeInfo, error) { info := ve.UnsubscribeInfo{ - Product: "ECS", InstanceId: s.ReadResourceId(resourceData.Id()), } - //这里需要区分下不同的ecs实例 if resourceData.Get("instance_charge_type") == "PrePaid" { - info.NeedUnsubscribe = true + //查询实例类型的配置 + action := "DescribeInstanceTypes" + input := map[string]interface{}{ + "InstanceTypeIds.1": resourceData.Get("instance_type"), + } + var ( + output *map[string]interface{} + err error + t interface{} + ) + output, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &input) + if err != nil { + return &info, err + } + t, err = ve.ObtainSdkValue("Result.InstanceTypes.0", *output) + if err != nil { + return &info, err + } + if tt, ok := t.(map[string]interface{}); ok { + if tt["Gpu"] != nil && tt["Rdma"] != nil { + info.Products = []string{"HPC_GPU", "ECS", "ECS_BareMetal", "GPU_Server"} + } else if tt["Gpu"] != nil && tt["Rdma"] == nil { + info.Products = []string{"GPU_Server", "ECS", "ECS_BareMetal", "HPC_GPU"} + } else { + info.Products = []string{"ECS", "ECS_BareMetal", "GPU_Server", "HPC_GPU"} + } + info.NeedUnsubscribe = true + } + } - return &info + return &info, nil } From 6350c5190a5b1fd8ed2308b90d9b209ed3da31af Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Mon, 26 Jun 2023 18:12:56 +0800 Subject: [PATCH 3/5] feat: update ecs unsub --- common/common_volcengine_unsubscribe.go | 1 + 1 file changed, 1 insertion(+) diff --git a/common/common_volcengine_unsubscribe.go b/common/common_volcengine_unsubscribe.go index 48f4b2d6..2d49e935 100644 --- a/common/common_volcengine_unsubscribe.go +++ b/common/common_volcengine_unsubscribe.go @@ -111,5 +111,6 @@ func (u *UnsubscribeService) getUniversalInfo(actionName string) UniversalInfo { Version: "2022-01-01", HttpMethod: POST, Action: actionName, + ContentType: ApplicationJSON, } } From eec2a2a912cc043c2de8bcc8e200ec286fed1448 Mon Sep 17 00:00:00 2001 From: zhangpeihua Date: Mon, 26 Jun 2023 18:14:58 +0800 Subject: [PATCH 4/5] feat: update tf version --- common/common_volcengine_version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/common_volcengine_version.go b/common/common_volcengine_version.go index 4b5507e2..03baa664 100644 --- a/common/common_volcengine_version.go +++ b/common/common_volcengine_version.go @@ -2,5 +2,5 @@ package common const ( TerraformProviderName = "terraform-provider-volcengine" - TerraformProviderVersion = "0.0.84" + TerraformProviderVersion = "0.0.85" ) From 4635a5d232b62708ea1fb332882ad7438d078be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=B2=9B=E5=8D=8E?= Date: Tue, 27 Jun 2023 06:21:11 +0000 Subject: [PATCH 5/5] feat: add network interface private ip address modify * feat: add network interface private ip address modify * feat: Merge branch * feat: add doc https://code.byted.org/iaasng/terraform-provider-volcengine/merge_requests/296 --- example/networkInterface/main.tf | 8 +- .../resource_volcengine_network_interface.go | 17 +- .../service_volcengine_network_interface.go | 149 +++++++++++++++++- .../docs/r/network_interface.html.markdown | 12 +- 4 files changed, 171 insertions(+), 15 deletions(-) diff --git a/example/networkInterface/main.tf b/example/networkInterface/main.tf index 57e555b3..e0d78367 100644 --- a/example/networkInterface/main.tf +++ b/example/networkInterface/main.tf @@ -1,9 +1,11 @@ resource "volcengine_network_interface" "foo" { - subnet_id = "subnet-im67x70vxla88gbssz1hy1z2" - security_group_ids = ["sg-im67wp9lx3i88gbssz3d22b2"] - primary_ip_address = "192.168.0.253" + subnet_id = "subnet-2fe79j7c8o5c059gp68ksxr93" + security_group_ids = ["sg-2fepz3c793g1s59gp67y21r34"] + primary_ip_address = "192.168.5.253" network_interface_name = "tf-test-up" description = "tf-test-up" port_security_enabled = false project_name = "default" + private_ip_address = ["192.168.5.2"] + //secondary_private_ip_address_count = 0 } \ No newline at end of file diff --git a/volcengine/vpc/network_interface/resource_volcengine_network_interface.go b/volcengine/vpc/network_interface/resource_volcengine_network_interface.go index 926fb056..493a51a0 100644 --- a/volcengine/vpc/network_interface/resource_volcengine_network_interface.go +++ b/volcengine/vpc/network_interface/resource_volcengine_network_interface.go @@ -74,17 +74,22 @@ func ResourceVolcengineNetworkInterface() *schema.Resource { Description: "Set port security enable or disable.", }, "secondary_private_ip_address_count": { - Type: schema.TypeInt, - Optional: true, - Description: "The count of secondary private ip address.", + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"private_ip_address"}, + Description: "The count of secondary private ip address. This field conflicts with `private_ip_address`.", }, "private_ip_address": { - Type: schema.TypeSet, - Optional: true, - Description: "The list of private ip address.", + Type: schema.TypeSet, Elem: &schema.Schema{ Type: schema.TypeString, }, + Optional: true, + Computed: true, + Set: schema.HashString, + ConflictsWith: []string{"secondary_private_ip_address_count"}, + Description: "The list of private ip address. This field conflicts with `secondary_private_ip_address_count`.", }, "project_name": { Type: schema.TypeString, diff --git a/volcengine/vpc/network_interface/service_volcengine_network_interface.go b/volcengine/vpc/network_interface/service_volcengine_network_interface.go index b908d542..c6c630d4 100644 --- a/volcengine/vpc/network_interface/service_volcengine_network_interface.go +++ b/volcengine/vpc/network_interface/service_volcengine_network_interface.go @@ -3,6 +3,7 @@ package network_interface import ( "errors" "fmt" + "strconv" "time" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -46,7 +47,7 @@ func (s *VolcengineNetworkInterfaceService) ReadResources(m map[string]interface return data, err } } - + logger.Debug(logger.RespFormat, action, *resp) results, err = ve.ObtainSdkValue("Result.NetworkInterfaceSets", *resp) if err != nil { return data, err @@ -84,6 +85,22 @@ func (s *VolcengineNetworkInterfaceService) ReadResource(resourceData *schema.Re if len(data) == 0 { return data, fmt.Errorf("network_interface %s not exist ", id) } + privateIpAddress := make([]string, 0) + if privateIpMap, ok := data["PrivateIpSets"].(map[string]interface{}); ok { + if privateIpSets, ok := privateIpMap["PrivateIpSet"].([]interface{}); ok { + for _, p := range privateIpSets { + if pMap, ok := p.(map[string]interface{}); ok { + isPrimary := pMap["Primary"].(bool) + ip := pMap["PrivateIpAddress"].(string) + if !isPrimary { + privateIpAddress = append(privateIpAddress, ip) + } + } + } + } + } + data["PrivateIpAddress"] = privateIpAddress + data["SecondaryPrivateIpAddressCount"] = len(privateIpAddress) return data, err } @@ -186,11 +203,141 @@ func (s *VolcengineNetworkInterfaceService) ModifyResource(resourceData *schema. TargetField: "SecurityGroupIds", ConvertType: ve.ConvertWithN, }, + "private_ip_address": { + Ignore: true, + }, + "secondary_private_ip_address_count": { + Ignore: true, + }, }, }, } callbacks = append(callbacks, callback) + // 检查private_ip_address改变 + if resourceData.HasChange("private_ip_address") { + add, remove, _, _ := ve.GetSetDifference("private_ip_address", resourceData, schema.HashString, false) + if remove.Len() > 0 { + callback = ve.Callback{ + Call: ve.SdkCall{ + Action: "UnassignPrivateIpAddresses", + ConvertMode: ve.RequestConvertInConvert, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["NetworkInterfaceId"] = d.Id() + for index, r := range remove.List() { + (*call.SdkParam)["PrivateIpAddress."+strconv.Itoa(index+1)] = r + } + return true, nil + }, + Convert: map[string]ve.RequestConvert{ + "private_ip_address": { + Ignore: true, + }, + "secondary_private_ip_address_count": { + Ignore: true, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + } + if add.Len() > 0 { + callback = ve.Callback{ + Call: ve.SdkCall{ + Action: "AssignPrivateIpAddresses", + ConvertMode: ve.RequestConvertInConvert, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["NetworkInterfaceId"] = d.Id() + for index, r := range add.List() { + (*call.SdkParam)["PrivateIpAddress."+strconv.Itoa(index+1)] = r + } + return true, nil + }, + Convert: map[string]ve.RequestConvert{ + "private_ip_address": { + Ignore: true, + }, + "secondary_private_ip_address_count": { + Ignore: true, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + } + } + // 检查secondary_private_ip_address_count改变 + if resourceData.HasChange("secondary_private_ip_address_count") { + privateIpAddress := resourceData.Get("private_ip_address").(*schema.Set).List() + oldCount, newCount := resourceData.GetChange("secondary_private_ip_address_count") + if oldCount != nil && newCount != nil && newCount != len(privateIpAddress) { + diff := newCount.(int) - oldCount.(int) + if diff > 0 { + callback = ve.Callback{ + Call: ve.SdkCall{ + Action: "AssignPrivateIpAddresses", + ConvertMode: ve.RequestConvertInConvert, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["NetworkInterfaceId"] = d.Id() + (*call.SdkParam)["SecondaryPrivateIpAddressCount"] = diff + return true, nil + }, + Convert: map[string]ve.RequestConvert{ + "private_ip_address": { + Ignore: true, + }, + "secondary_private_ip_address_count": { + Ignore: true, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + } else { + diff *= -1 + removeIpAddress := privateIpAddress[:diff] + callback = ve.Callback{ + Call: ve.SdkCall{ + Action: "UnassignPrivateIpAddresses", + ConvertMode: ve.RequestConvertInConvert, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["NetworkInterfaceId"] = d.Id() + for index, r := range removeIpAddress { + (*call.SdkParam)["PrivateIpAddress."+strconv.Itoa(index+1)] = r + } + return true, nil + }, + Convert: map[string]ve.RequestConvert{ + "private_ip_address": { + Ignore: true, + }, + "secondary_private_ip_address_count": { + Ignore: true, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + } + } + } + // 更新Tags setResourceTagsCallbacks := ve.SetResourceTags(s.Client, "TagResources", "UntagResources", "eni", resourceData, getUniversalInfo) callbacks = append(callbacks, setResourceTagsCallbacks...) diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index ed8c24d5..9d5bb498 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -11,13 +11,15 @@ Provides a resource to manage network interface ## Example Usage ```hcl resource "volcengine_network_interface" "foo" { - subnet_id = "subnet-im67x70vxla88gbssz1hy1z2" - security_group_ids = ["sg-im67wp9lx3i88gbssz3d22b2"] - primary_ip_address = "192.168.0.253" + subnet_id = "subnet-2fe79j7c8o5c059gp68ksxr93" + security_group_ids = ["sg-2fepz3c793g1s59gp67y21r34"] + primary_ip_address = "192.168.5.253" network_interface_name = "tf-test-up" description = "tf-test-up" port_security_enabled = false project_name = "default" + private_ip_address = ["192.168.5.2"] + //secondary_private_ip_address_count = 0 } ``` ## Argument Reference @@ -28,9 +30,9 @@ The following arguments are supported: * `network_interface_name` - (Optional) The name of the ENI. * `port_security_enabled` - (Optional) Set port security enable or disable. * `primary_ip_address` - (Optional, ForceNew) The primary IP address of the ENI. -* `private_ip_address` - (Optional) The list of private ip address. +* `private_ip_address` - (Optional) The list of private ip address. This field conflicts with `secondary_private_ip_address_count`. * `project_name` - (Optional) The ProjectName of the ENI. -* `secondary_private_ip_address_count` - (Optional) The count of secondary private ip address. +* `secondary_private_ip_address_count` - (Optional) The count of secondary private ip address. This field conflicts with `private_ip_address`. * `tags` - (Optional) Tags. The `tags` object supports the following: