-
Notifications
You must be signed in to change notification settings - Fork 107
Implement Linode Interface data source #2159
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
base: dev
Are you sure you want to change the base?
Implement Linode Interface data source #2159
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a new Linode Interface data source that allows users to query information about Linode network interfaces. The data source supports retrieving details about public, VLAN, and VPC interfaces including their IPv4/IPv6 configurations and routing information.
- Adds comprehensive schema definitions for interface types (public, VLAN, VPC)
- Implements data models and flattening logic for all interface configurations
- Includes test coverage with Terraform configuration templates
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| linode/linodeinterface/tmpl/template.go | Adds template function for generating basic data source test configuration |
| linode/linodeinterface/tmpl/datasource_basic.gotf | Terraform template for testing data source with instance and interface resources |
| linode/linodeinterface/framework_datasource_test.go | Integration test for the data source with basic functionality checks |
| linode/linodeinterface/framework_datasource_schema.go | Schema definitions for all interface types and their nested attributes |
| linode/linodeinterface/framework_datasource_models.go | Data models and flattening logic for converting API responses to Terraform state |
| linode/linodeinterface/framework_datasource.go | Main data source implementation with read logic and API client interaction |
| linode/framework_provider.go | Registers the new data source with the provider |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | ||
|
|
||
| // Flatten IPv6 SLAAC | ||
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | ||
| for i, s := range vpcInterface.IPv6.SLAAC { | ||
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | ||
| Address: iptypes.NewIPv6AddressValue(s.Address), | ||
| } | ||
| } | ||
|
|
||
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | ||
| diags.Append(slaacDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.SLAAC = slaacSet | ||
|
|
||
| // Flatten IPv6 ranges | ||
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | ||
| for i, r := range vpcInterface.IPv6.Ranges { | ||
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | ||
| } | ||
| } | ||
|
|
||
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | ||
| diags.Append(ipv6RangesDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.Ranges = ipv6RangesSet | ||
|
|
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will panic if vpcInterface.IPv6 is nil. The IPv6 field should be checked for nil before accessing its IsPublic field.
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| if vpcInterface.IPv6 != nil { | |
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| } else { | |
| vpcIPv6.IsPublic = types.BoolNull() | |
| vpcIPv6.SLAAC = types.SetNull(dataSourceVPCIPv6SLAACAttribute.Type().(types.SetType).ElemType) | |
| vpcIPv6.Ranges = types.SetNull(dataSourceVPCIPv6RangeAttribute.Type().(types.SetType).ElemType) | |
| } |
| addresses := make([]DataSourceVPCIPv4AddressModel, len(vpcInterface.IPv4.Addresses)) | ||
| for i, addr := range vpcInterface.IPv4.Addresses { |
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will panic if vpcInterface.IPv4 is nil. The IPv4 field should be checked for nil before accessing its Addresses field.
| ranges := make([]DataSourceVPCIPv4RangeModel, len(vpcInterface.IPv4.Ranges)) | ||
| for i, r := range vpcInterface.IPv4.Ranges { |
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will panic if vpcInterface.IPv4 is nil. The IPv4 field should be checked for nil before accessing its Ranges field.
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | ||
|
|
||
| // Flatten IPv6 SLAAC | ||
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | ||
| for i, s := range vpcInterface.IPv6.SLAAC { | ||
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | ||
| Address: iptypes.NewIPv6AddressValue(s.Address), | ||
| } | ||
| } | ||
|
|
||
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | ||
| diags.Append(slaacDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.SLAAC = slaacSet | ||
|
|
||
| // Flatten IPv6 ranges | ||
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | ||
| for i, r := range vpcInterface.IPv6.Ranges { | ||
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | ||
| } | ||
| } | ||
|
|
||
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | ||
| diags.Append(ipv6RangesDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.Ranges = ipv6RangesSet | ||
|
|
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will panic if vpcInterface.IPv6 is nil. The IPv6 field should be checked for nil before accessing its SLAAC field.
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| if vpcInterface.IPv6 != nil { | |
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| } else { | |
| vpcIPv6.IsPublic = types.BoolNull() | |
| // Set SLAAC to empty set | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), []DataSourceVPCIPv6SLAACModel{}) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Set Ranges to empty set | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), []DataSourceVPCIPv6RangeModel{}) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| } |
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | ||
|
|
||
| // Flatten IPv6 SLAAC | ||
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | ||
| for i, s := range vpcInterface.IPv6.SLAAC { | ||
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | ||
| Address: iptypes.NewIPv6AddressValue(s.Address), | ||
| } | ||
| } | ||
|
|
||
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | ||
| diags.Append(slaacDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.SLAAC = slaacSet | ||
|
|
||
| // Flatten IPv6 ranges | ||
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | ||
| for i, r := range vpcInterface.IPv6.Ranges { | ||
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | ||
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | ||
| } | ||
| } | ||
|
|
||
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | ||
| diags.Append(ipv6RangesDiags...) | ||
| if diags.HasError() { | ||
| return | ||
| } | ||
| vpcIPv6.Ranges = ipv6RangesSet |
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will panic if vpcInterface.IPv6 is nil. The IPv6 field should be checked for nil before accessing its Ranges field.
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| if vpcInterface.IPv6 != nil { | |
| vpcIPv6.IsPublic = types.BoolPointerValue(vpcInterface.IPv6.IsPublic) | |
| // Flatten IPv6 SLAAC | |
| slaac := make([]DataSourceVPCIPv6SLAACModel, len(vpcInterface.IPv6.SLAAC)) | |
| for i, s := range vpcInterface.IPv6.SLAAC { | |
| slaac[i] = DataSourceVPCIPv6SLAACModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(s.Range), | |
| Address: iptypes.NewIPv6AddressValue(s.Address), | |
| } | |
| } | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), slaac) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| // Flatten IPv6 ranges | |
| ipv6Ranges := make([]DataSourceVPCIPv6RangeModel, len(vpcInterface.IPv6.Ranges)) | |
| for i, r := range vpcInterface.IPv6.Ranges { | |
| ipv6Ranges[i] = DataSourceVPCIPv6RangeModel{ | |
| Range: cidrtypes.NewIPv6PrefixValue(r.Range), | |
| } | |
| } | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), ipv6Ranges) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| } else { | |
| vpcIPv6.IsPublic = types.BoolPointerValue(nil) | |
| // Set empty sets for SLAAC and Ranges if IPv6 is nil | |
| slaacSet, slaacDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6SLAACAttribute.Type(), []DataSourceVPCIPv6SLAACModel{}) | |
| diags.Append(slaacDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.SLAAC = slaacSet | |
| ipv6RangesSet, ipv6RangesDiags := types.SetValueFrom(ctx, dataSourceVPCIPv6RangeAttribute.Type(), []DataSourceVPCIPv6RangeModel{}) | |
| diags.Append(ipv6RangesDiags...) | |
| if diags.HasError() { | |
| return | |
| } | |
| vpcIPv6.Ranges = ipv6RangesSet | |
| } |
📝 Description
Add Linode Interface data source
✔️ How to Test