Skip to content

Commit 205a9d5

Browse files
VPC Dual Stack: Add support for IPv6 VPC in linode_interface resource (#2096)
* VPC Dual Stack: Add support for IPv6 VPC in linode_interface resource * fix ordering * Update docs/data-sources/vpc_subnets.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/data-sources/vpc_subnet.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add validation to VPC and Subnet creation to prevent unexpected errors without VPC IPv6 enrollment * minor rework * oops --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 5fa026b commit 205a9d5

20 files changed

+757
-24
lines changed

docs/data-sources/vpc_subnet.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,19 @@ In addition to all arguments above, the following attributes are exported:
4040

4141
* `ipv4` - The IPv4 range of this subnet in CIDR format.
4242

43+
* [`ipv6`](#ipv6) - A list of IPv6 ranges under this subnet.
44+
4345
* `linodes` - A list of Linodes added to this subnet.
46+
4447
* `id` - ID of the Linode
48+
4549
* `interfaces` - A list of networking interfaces objects.
50+
4651
* `id` - ID of the interface.
52+
4753
* `config_id` - ID of Linode Config that the interface is associated with. `null` for a Linode Interface.
48-
* `active` - Whether the Interface is actively in use.
4954

50-
* [`ipv6`](#ipv6) - A list of IPv6 ranges under this subnet.
55+
* `active` - Whether the Interface is actively in use.
5156

5257
* `created` - The date and time when the VPC Subnet was created.
5358

docs/data-sources/vpc_subnets.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,19 @@ Each Linode VPC subnet will be stored in the `vpc_subnets` attribute and will ex
5353

5454
* `ipv4` - The IPv4 range of this subnet in CIDR format.
5555

56+
* [`ipv6`](#ipv6) - A list of IPv6 ranges under this subnet.
57+
5658
* `linodes` - A list of Linodes added to this subnet.
59+
5760
* `id` - ID of the Linode
61+
5862
* `interfaces` - A list of networking interfaces objects.
63+
5964
* `id` - ID of the interface.
65+
6066
* `config_id` - ID of Linode Config that the interface is associated with. `null` for a Linode Interface.
61-
* `active` - Whether the Interface is actively in use.
6267

63-
* [`ipv6`](#ipv6) - A list of IPv6 ranges under this subnet.
68+
* `active` - Whether the Interface is actively in use.
6469

6570
* `created` - The date and time when the VPC Subnet was created.
6671

docs/resources/interface.md

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ resource "linode_interface" "vpc" {
9393
}
9494
```
9595

96+
### VPC (IPv6) Interface Example
97+
98+
The following example shows how to create a public VPC interface with a custom IPv6 configuration.
99+
100+
```hcl
101+
resource "linode_interface" "vpc" {
102+
linode_id = linode_instance.my-instance.id
103+
104+
vpc = {
105+
subnet_id = 12345
106+
107+
ipv6 = {
108+
is_public = true
109+
110+
slaac = [
111+
{
112+
range = "auto"
113+
}
114+
]
115+
116+
ranges = [
117+
{
118+
range = "auto"
119+
}
120+
]
121+
}
122+
}
123+
}
124+
```
125+
96126
### VLAN Interface Example
97127

98128
The following example shows how to create a VLAN interface.
@@ -174,25 +204,25 @@ The following arguments are supported:
174204

175205
* `firewall_id` - (Optional) The ID of an enabled firewall to secure a VPC or public interface. Not allowed for VLAN interfaces.
176206

177-
* `default_route` - (Optional) Indicates whether the interface serves as the default route when multiple interfaces are eligible for this role.
207+
* `default_route` - (Optional) Indicates if the interface serves as the default route when multiple interfaces are eligible for this role.
178208

179-
* `ipv4` - (Optional) When set to true, the interface is used for the IPv4 default route.
209+
* `ipv4` - (Optional) If set to true, the interface is used for the IPv4 default route.
180210

181-
* `ipv6` - (Optional) When set to true, the interface is used for the IPv6 default route.
211+
* `ipv6` - (Optional) If set to true, the interface is used for the IPv6 default route.
182212

183-
* `public` - (Optional) Configuration for a Linode public interface. Exactly one of `public`, `vlan`, or `vpc` must be specified.
213+
* `public` - (Optional) Nested attributes object for a Linode public interface. Exactly one of `public`, `vlan`, or `vpc` must be specified.
184214

185-
* `ipv4` - (Optional) IPv4 configuration for this interface.
215+
* `ipv4` - (Optional) IPv4 addresses for this interface.
186216

187217
* `addresses` - (Optional) IPv4 addresses configured for this Linode interface. Each object in this list supports:
188218

189219
* `address` - (Optional) The IPv4 address. Defaults to "auto" for automatic assignment.
190220

191221
* `primary` - (Optional) Whether this address is the primary address for the interface.
192222

193-
* `ipv6` - (Optional) IPv6 configuration for this interface.
223+
* `ipv6` - (Optional) IPv6 addresses for this interface.
194224

195-
* `ranges` - (Optional) IPv6 ranges in CIDR notation (2600:0db8::1/64) or prefix-only (/64). Each object in this list supports:
225+
* `ranges` - (Optional) Configured IPv6 range in CIDR notation (2600:0db8::1/64) or prefix-only (/64). Each object in this list supports:
196226

197227
* `range` - (Required) The IPv6 range.
198228

@@ -222,6 +252,18 @@ The following arguments are supported:
222252

223253
* `range` - (Required) The IPv4 range.
224254

255+
* `ipv6` - (Optional) IPv6 assigned through `slaac` and `ranges`. If you create a VPC interface in a subnet with IPv6 and don’t specify `slaac` or `ranges`, a SLAAC range is added automatically. **NOTE: IPv6 VPCs may not currently be available to all users.**
256+
257+
* `is_public` - (Optional) Indicates whether the IPv6 configuration profile interface is public. (Default `false`)
258+
259+
* `slaac` - (Optional) Defines IPv6 SLAAC address ranges. An address is automatically generated from the assigned /64 prefix using the Linode’s MAC address, just like on public IPv6 interfaces. Router advertisements (RA) are sent to the Linode, so standard SLAAC configuration works without any changes.
260+
261+
* `range` - (Optional) The IPv6 network range in CIDR notation.
262+
263+
* `ranges` - (Optional) Defines additional IPv6 network ranges.
264+
265+
* `range` - (Optional) The IPv6 network range in CIDR notation.
266+
225267
## Attributes Reference
226268

227269
In addition to all arguments above, the following attributes are exported:
@@ -280,12 +322,22 @@ In addition to all arguments above, the following attributes are exported:
280322

281323
* `range` - The assigned IPv4 range.
282324

325+
* `ipv6` - IPv6 assigned through `slaac` and `ranges`. **NOTE: IPv6 VPCs may not currently be available to all users.**
326+
327+
* `assigned_slaac` - Assigned IPv6 SLAAC address ranges to use in the VPC subnet, calculated from `slaac` input.
328+
329+
* `range` - The IPv6 network range in CIDR notation.
330+
331+
* `assigned_ranges` - Assigned additional IPv6 ranges to use in the VPC subnet, calculated from `ranges` input.
332+
333+
* `range` - The IPv6 network range in CIDR notation.
334+
283335
## Import
284336

285337
Interfaces can be imported using a Linode ID followed by an Interface ID, separated by a comma, e.g.
286338

287339
```sh
288-
terraform import linode_interface.example 67890,12345
340+
terraform import linode_interface.example 12345,67890
289341
```
290342

291343
## Notes

linode/linodeinterface/framework_models.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ func (data *LinodeInterfaceModel) FlattenInterface(
203203
vpc.IPv4 = helper.KeepOrUpdateValue(
204204
vpc.IPv4, types.ObjectNull(vpcIPv4Attribute.GetType().(types.ObjectType).AttrTypes), pk,
205205
)
206+
vpc.IPv6 = helper.KeepOrUpdateValue(
207+
vpc.IPv6, types.ObjectNull(vpcIPv6Attribute.GetType().(types.ObjectType).AttrTypes), pk,
208+
)
206209
vpc.SubnetID = helper.KeepOrUpdateValue(vpc.SubnetID, types.Int64Null(), pk)
207210
return
208211
}

linode/linodeinterface/framework_resource.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ func (r *Resource) ImportState(
250250

251251
func populateLogAttributes(ctx context.Context, model LinodeInterfaceModel) context.Context {
252252
return helper.SetLogFieldBulk(ctx, map[string]any{
253-
"linode_id": model.LinodeID.ValueInt64(),
254253
"id": model.ID.ValueString(),
254+
"linode_id": model.LinodeID.ValueInt64(),
255255
})
256256
}

linode/linodeinterface/framework_resource_schema.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,50 @@ var computedVPCInterfaceIPv4Range = schema.NestedAttributeObject{
145145
},
146146
}
147147

148+
var configuredVPCInterfaceIPv6SLAAC = schema.NestedAttributeObject{
149+
Attributes: map[string]schema.Attribute{
150+
"range": schema.StringAttribute{
151+
Description: "The IPv6 network range in CIDR notation.",
152+
Optional: true,
153+
Computed: true,
154+
Default: stringdefault.StaticString("auto"),
155+
},
156+
},
157+
}
158+
159+
var computedVPCInterfaceIPv6SLAAC = schema.NestedAttributeObject{
160+
Attributes: map[string]schema.Attribute{
161+
"range": schema.StringAttribute{
162+
Description: "The IPv6 network range in CIDR notation.",
163+
Computed: true,
164+
},
165+
"address": schema.StringAttribute{
166+
Description: "The assigned IPv6 address within the range.",
167+
Computed: true,
168+
},
169+
},
170+
}
171+
172+
var configuredVPCInterfaceIPv6Range = schema.NestedAttributeObject{
173+
Attributes: map[string]schema.Attribute{
174+
"range": schema.StringAttribute{
175+
Description: "The IPv6 network range in CIDR notation.",
176+
Optional: true,
177+
Computed: true,
178+
Default: stringdefault.StaticString("auto"),
179+
},
180+
},
181+
}
182+
183+
var computedVPCInterfaceIPv6Range = schema.NestedAttributeObject{
184+
Attributes: map[string]schema.Attribute{
185+
"range": schema.StringAttribute{
186+
Description: "The IPv6 network range in CIDR notation.",
187+
Computed: true,
188+
},
189+
},
190+
}
191+
148192
var publicIPv4Attribute = schema.SingleNestedAttribute{
149193
Description: "IPv4 addresses for this interface.",
150194
Optional: true,
@@ -289,6 +333,57 @@ var vpcIPv4Attribute = schema.SingleNestedAttribute{
289333
},
290334
}
291335

336+
var vpcIPv6Attribute = schema.SingleNestedAttribute{
337+
Optional: true,
338+
Computed: true,
339+
PlanModifiers: []planmodifier.Object{
340+
objectplanmodifier.UseStateForUnknown(),
341+
},
342+
Attributes: map[string]schema.Attribute{
343+
"is_public": schema.BoolAttribute{
344+
Description: "Indicates whether the IPv6 configuration on the Linode interface is public.",
345+
Optional: true,
346+
Computed: true,
347+
},
348+
"slaac": schema.ListNestedAttribute{
349+
Description: "Defines IPv6 SLAAC address ranges.",
350+
Optional: true,
351+
NestedObject: configuredVPCInterfaceIPv6SLAAC,
352+
Validators: []validator.List{
353+
listvalidator.NoNullValues(),
354+
},
355+
},
356+
"assigned_slaac": schema.SetNestedAttribute{
357+
Description: "Assigned IPv6 SLAAC address ranges, calculated from `addresses` input.",
358+
Computed: true,
359+
NestedObject: computedVPCInterfaceIPv6SLAAC,
360+
PlanModifiers: []planmodifier.Set{
361+
linodesetplanmodifier.UseStateForUnknownUnlessTheseChanged(
362+
path.MatchRoot("vpc").AtName("ipv6").AtName("slaac"),
363+
),
364+
},
365+
},
366+
"ranges": schema.ListNestedAttribute{
367+
Description: "CIDR notation of a range (1.2.3.4/24) or prefix only (/24).",
368+
Optional: true,
369+
NestedObject: configuredVPCInterfaceIPv6Range,
370+
Validators: []validator.List{
371+
listvalidator.NoNullValues(),
372+
},
373+
},
374+
"assigned_ranges": schema.SetNestedAttribute{
375+
Description: "Assigned IPv6 ranges to use in the VPC subnet, calculated from `ranges` input.",
376+
Computed: true,
377+
NestedObject: computedVPCInterfaceIPv6Range,
378+
PlanModifiers: []planmodifier.Set{
379+
linodesetplanmodifier.UseStateForUnknownUnlessTheseChanged(
380+
path.MatchRoot("vpc").AtName("ipv6").AtName("ranges"),
381+
),
382+
},
383+
},
384+
},
385+
}
386+
292387
var vpcInterfaceSchema = schema.SingleNestedAttribute{
293388
Description: "Linode VPC interface.",
294389
Optional: true,
@@ -300,6 +395,7 @@ var vpcInterfaceSchema = schema.SingleNestedAttribute{
300395
},
301396
Attributes: map[string]schema.Attribute{
302397
"ipv4": vpcIPv4Attribute,
398+
"ipv6": vpcIPv6Attribute,
303399
"subnet_id": schema.Int64Attribute{
304400
Required: true,
305401
Description: "The VPC subnet identifier for this interface.",

0 commit comments

Comments
 (0)