Skip to content

Commit 2480012

Browse files
authored
feat(eni): [116613116] add eni ipv6 address (#2573)
* add eni ipv6 * add eni ipv6 * update doc * update doc * add test * add changelog
1 parent 2c57ea4 commit 2480012

15 files changed

+534
-9
lines changed

.changelog/2573.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:deprecation
2+
resource/tencentcloud_vpc_ipv6_eni_address
3+
```
4+
5+
```release-note:new-resource
6+
tencentcloud_eni_ipv6_address
7+
```

tencentcloud/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ func Provider() *schema.Provider {
10501050
"tencentcloud_eni": vpc.ResourceTencentCloudEni(),
10511051
"tencentcloud_eni_attachment": vpc.ResourceTencentCloudEniAttachment(),
10521052
"tencentcloud_eni_sg_attachment": vpc.ResourceTencentCloudEniSgAttachment(),
1053+
"tencentcloud_eni_ipv6_address": vpc.ResourceTencentCloudEniIpv6Address(),
10531054
"tencentcloud_ccn": ccn.ResourceTencentCloudCcn(),
10541055
"tencentcloud_ccn_attachment": ccn.ResourceTencentCloudCcnAttachment(),
10551056
"tencentcloud_ccn_bandwidth_limit": ccn.ResourceTencentCloudCcnBandwidthLimit(),

tencentcloud/provider.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@ Virtual Private Cloud(VPC)
11991199
tencentcloud_eni
12001200
tencentcloud_eni_attachment
12011201
tencentcloud_eni_sg_attachment
1202+
tencentcloud_eni_ipv6_address
12021203
tencentcloud_vpc
12031204
tencentcloud_vpc_acl
12041205
tencentcloud_vpc_acl_attachment
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package vpc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"time"
8+
9+
tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
14+
15+
"github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper"
16+
)
17+
18+
func ResourceTencentCloudEniIpv6Address() *schema.Resource {
19+
return &schema.Resource{
20+
Create: resourceTencentCloudEniIpv6AddressCreate,
21+
Read: resourceTencentCloudEniIpv6AddressRead,
22+
Delete: resourceTencentCloudEniIpv6AddressDelete,
23+
Importer: &schema.ResourceImporter{
24+
State: schema.ImportStatePassthrough,
25+
},
26+
Schema: map[string]*schema.Schema{
27+
"network_interface_id": {
28+
Required: true,
29+
Type: schema.TypeString,
30+
ForceNew: true,
31+
Description: "ENI instance `ID`, in the form of `eni-m6dyj72l`.",
32+
},
33+
34+
"ipv6_addresses": {
35+
Optional: true,
36+
Type: schema.TypeSet,
37+
Computed: true,
38+
ForceNew: true,
39+
ConflictsWith: []string{"ipv6_address_count"},
40+
Description: "The specified `IPv6` address list, up to 10 can be specified at a time. Combined with the input parameter `Ipv6AddressCount` to calculate the quota. Mandatory one with Ipv6AddressCount.",
41+
Elem: &schema.Resource{
42+
Schema: map[string]*schema.Schema{
43+
"address": {
44+
Type: schema.TypeString,
45+
Required: true,
46+
ForceNew: true,
47+
Description: "`IPv6` address, in the form of: `3402:4e00:20:100:0:8cd9:2a67:71f3`.",
48+
},
49+
"description": {
50+
Type: schema.TypeString,
51+
Optional: true,
52+
ForceNew: true,
53+
Description: "Description.",
54+
},
55+
"primary": {
56+
Type: schema.TypeBool,
57+
Optional: true,
58+
Computed: true,
59+
ForceNew: true,
60+
Description: "Whether to master `IP`.",
61+
},
62+
"address_id": {
63+
Type: schema.TypeString,
64+
Optional: true,
65+
Computed: true,
66+
ForceNew: true,
67+
Description: "`EIP` instance `ID`, such as:`eip-hxlqja90`.",
68+
},
69+
"is_wan_ip_blocked": {
70+
Type: schema.TypeBool,
71+
Optional: true,
72+
Computed: true,
73+
ForceNew: true,
74+
Description: "Whether the public network IP is blocked.",
75+
},
76+
"state": {
77+
Type: schema.TypeString,
78+
Optional: true,
79+
Computed: true,
80+
ForceNew: true,
81+
Description: "`IPv6` address status: `PENDING`: pending, `MIGRATING`: migrating, `DELETING`: deleting, `AVAILABLE`: available.",
82+
},
83+
},
84+
},
85+
},
86+
87+
"ipv6_address_count": {
88+
Optional: true,
89+
Computed: true,
90+
ForceNew: true,
91+
Type: schema.TypeInt,
92+
ConflictsWith: []string{"ipv6_addresses"},
93+
Description: "The number of automatically assigned IPv6 addresses and the total number of private IP addresses cannot exceed the quota. This should be combined with the input parameter `ipv6_addresses` for quota calculation. At least one of them, either this or 'Ipv6Addresses', must be provided.",
94+
},
95+
},
96+
}
97+
}
98+
99+
func resourceTencentCloudEniIpv6AddressCreate(d *schema.ResourceData, meta interface{}) error {
100+
defer tccommon.LogElapsed("resource.tencentcloud_eni_ipv6_address.create")()
101+
defer tccommon.InconsistentCheck(d, meta)()
102+
103+
logId := tccommon.GetLogId(tccommon.ContextNil)
104+
105+
var (
106+
request = vpc.NewAssignIpv6AddressesRequest()
107+
response = vpc.NewAssignIpv6AddressesResponse()
108+
networkInterfaceId string
109+
)
110+
111+
if v, ok := d.GetOk("network_interface_id"); ok {
112+
networkInterfaceId = v.(string)
113+
request.NetworkInterfaceId = helper.String(v.(string))
114+
}
115+
116+
if v, ok := d.GetOk("ipv6_addresses"); ok {
117+
for _, item := range v.(*schema.Set).List() {
118+
dMap := item.(map[string]interface{})
119+
ipv6Address := vpc.Ipv6Address{}
120+
if v, ok := dMap["address"]; ok {
121+
ipv6Address.Address = helper.String(v.(string))
122+
}
123+
if v, ok := dMap["primary"]; ok {
124+
ipv6Address.Primary = helper.Bool(v.(bool))
125+
}
126+
if v, ok := dMap["address_id"]; ok {
127+
ipv6Address.AddressId = helper.String(v.(string))
128+
}
129+
if v, ok := dMap["description"]; ok {
130+
ipv6Address.Description = helper.String(v.(string))
131+
}
132+
if v, ok := dMap["is_wan_ip_blocked"]; ok {
133+
ipv6Address.IsWanIpBlocked = helper.Bool(v.(bool))
134+
}
135+
if v, ok := dMap["state"]; ok {
136+
ipv6Address.State = helper.String(v.(string))
137+
}
138+
request.Ipv6Addresses = append(request.Ipv6Addresses, &ipv6Address)
139+
}
140+
}
141+
142+
if v, ok := d.GetOkExists("ipv6_address_count"); ok {
143+
request.Ipv6AddressCount = helper.IntUint64(v.(int))
144+
}
145+
146+
err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError {
147+
result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVpcClient().AssignIpv6Addresses(request)
148+
if e != nil {
149+
return tccommon.RetryError(e)
150+
} else {
151+
log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString())
152+
}
153+
response = result
154+
return nil
155+
})
156+
if err != nil {
157+
log.Printf("[CRITAL]%s create vpc ipv6EniAddress failed, reason:%+v", logId, err)
158+
return err
159+
}
160+
161+
addressSet := response.Response.Ipv6AddressSet
162+
if len(addressSet) < 1 {
163+
return fmt.Errorf("assign ipv6 addresses failed.")
164+
}
165+
166+
time.Sleep(5 * time.Second)
167+
168+
d.SetId(networkInterfaceId)
169+
170+
return resourceTencentCloudEniIpv6AddressRead(d, meta)
171+
}
172+
173+
func resourceTencentCloudEniIpv6AddressRead(d *schema.ResourceData, meta interface{}) error {
174+
defer tccommon.LogElapsed("resource.tencentcloud_eni_ipv6_address.read")()
175+
defer tccommon.InconsistentCheck(d, meta)()
176+
177+
logId := tccommon.GetLogId(tccommon.ContextNil)
178+
179+
ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
180+
181+
service := VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()}
182+
183+
networkInterfaceId := d.Id()
184+
185+
enis, err := service.DescribeEniById(ctx, []string{networkInterfaceId})
186+
187+
if err != nil {
188+
return err
189+
}
190+
191+
if len(enis) < 1 {
192+
d.SetId("")
193+
log.Printf("[WARN]%s resource `VpcIpv6EniAddress` [%s] not found, please check if it has been deleted.\n", logId, d.Id())
194+
return nil
195+
}
196+
197+
eni := enis[0]
198+
199+
ipv6s := make([]map[string]interface{}, 0, len(eni.Ipv6AddressSet))
200+
for _, ipv6 := range eni.Ipv6AddressSet {
201+
ipv6s = append(ipv6s, map[string]interface{}{
202+
"address": ipv6.Address,
203+
"primary": ipv6.Primary,
204+
"address_id": ipv6.AddressId,
205+
"description": ipv6.Description,
206+
"is_wan_ip_blocked": ipv6.IsWanIpBlocked,
207+
"state": ipv6.State,
208+
})
209+
}
210+
211+
_ = d.Set("network_interface_id", networkInterfaceId)
212+
_ = d.Set("ipv6_addresses", ipv6s)
213+
_ = d.Set("ipv6_address_count", len(eni.Ipv6AddressSet))
214+
215+
return nil
216+
}
217+
218+
func resourceTencentCloudEniIpv6AddressDelete(d *schema.ResourceData, meta interface{}) error {
219+
defer tccommon.LogElapsed("resource.tencentcloud_eni_ipv6_address.delete")()
220+
defer tccommon.InconsistentCheck(d, meta)()
221+
222+
logId := tccommon.GetLogId(tccommon.ContextNil)
223+
ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId)
224+
225+
service := VpcService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()}
226+
networkInterfaceId := d.Id()
227+
228+
enis, err := service.DescribeEniById(ctx, []string{networkInterfaceId})
229+
230+
if err != nil {
231+
return err
232+
}
233+
234+
if len(enis) < 1 {
235+
d.SetId("")
236+
log.Printf("[WARN]%s resource `VpcIpv6EniAddress` [%s] not found, please check if it has been deleted.\n", logId, d.Id())
237+
return nil
238+
}
239+
240+
eni := enis[0]
241+
ipv6s := make([]*string, 0, len(eni.Ipv6AddressSet))
242+
for _, ipv6 := range eni.Ipv6AddressSet {
243+
ipv6s = append(ipv6s, ipv6.Address)
244+
}
245+
246+
if err := service.DeleteEniIpv6AddressById(ctx, networkInterfaceId, ipv6s); err != nil {
247+
return err
248+
}
249+
250+
return nil
251+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
Provides a resource to create a vpc eni_ipv6_address
2+
3+
Example Usage
4+
5+
```hcl
6+
data "tencentcloud_availability_zones" "zones" {}
7+
8+
resource "tencentcloud_vpc" "vpc" {
9+
name = "vpc-example"
10+
cidr_block = "10.0.0.0/16"
11+
}
12+
13+
resource "tencentcloud_subnet" "subnet" {
14+
availability_zone = data.tencentcloud_availability_zones.zones.zones.0.name
15+
name = "subnet-example"
16+
vpc_id = tencentcloud_vpc.vpc.id
17+
cidr_block = "10.0.0.0/16"
18+
is_multicast = false
19+
}
20+
21+
resource "tencentcloud_eni" "eni" {
22+
name = "eni-example"
23+
vpc_id = tencentcloud_vpc.vpc.id
24+
subnet_id = tencentcloud_subnet.subnet.id
25+
description = "eni desc."
26+
ipv4_count = 1
27+
}
28+
29+
resource "tencentcloud_vpc_ipv6_cidr_block" "example" {
30+
vpc_id = tencentcloud_vpc.vpc.id
31+
}
32+
33+
resource "tencentcloud_vpc_ipv6_subnet_cidr_block" "example" {
34+
vpc_id = tencentcloud_vpc.vpc.id
35+
ipv6_subnet_cidr_blocks {
36+
subnet_id = tencentcloud_subnet.subnet.id
37+
ipv6_cidr_block = "2402:4e00:1018:6700::/64"
38+
}
39+
}
40+
41+
resource "tencentcloud_eni_ipv6_address" "ipv6_eni_address" {
42+
network_interface_id = tencentcloud_eni.eni.id
43+
ipv6_address_count = 1
44+
}
45+
```
46+
47+
Import
48+
49+
vpc eni_ipv6_address can be imported using the id, e.g.
50+
51+
```
52+
terraform import tencentcloud_eni_ipv6_address.ipv6_eni_address eni_id
53+
```

0 commit comments

Comments
 (0)