-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from browningluke/add_interface_data_source
Add interface data source
- Loading branch information
Showing
7 changed files
with
387 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--- | ||
page_title: "opnsense_interface Data Source - terraform-provider-opnsense" | ||
subcategory: Interfaces | ||
description: |- | ||
Interfaces can be used to get configurations of OPNsense interfaces. | ||
--- | ||
|
||
# opnsense_interface (Data Source) | ||
|
||
Interfaces can be used to get configurations of OPNsense interfaces. | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `device` (String) Name of the interface device. | ||
|
||
### Read-Only | ||
|
||
- `capabilities` (Set of String) List of capabilities the interface supports. | ||
- `flags` (Set of String) List of flags configured on the interface (equiv. to flags=xxxx in output of ifconfig). | ||
- `groups` (Set of String) List of groups the interface is a member of. | ||
- `ipv4` (Attributes List) (see [below for nested schema](#nestedatt--ipv4)) | ||
- `ipv6` (Attributes List) (see [below for nested schema](#nestedatt--ipv6)) | ||
- `is_physical` (Boolean) Whether the interface is physical or virtual. | ||
- `macaddr` (String) MAC address assigned to the interface. | ||
- `media` (String) Interface media type settings (see https://man.openbsd.org/ifmedia.4). | ||
- `media_raw` (String) User-friendly interface media type. | ||
- `mtu` (Number) Maximum Transmission Unit for the interface. This is typically 1500 bytes but can vary in some circumstances. | ||
- `options` (Set of String) List of options configured on the interface (equiv. to options=xx in output of ifconfig). | ||
- `status` (String) Status of the interface (e.g. `"active"`). | ||
- `supported_media` (Set of String) List of supported media type settings (see https://man.openbsd.org/ifmedia.4). | ||
|
||
<a id="nestedatt--ipv4"></a> | ||
### Nested Schema for `ipv4` | ||
|
||
Read-Only: | ||
|
||
- `ipaddr` (String) IPv4 address assigned to the interface. | ||
- `subnetbits` (Number) Number of subnet bits (i.e. CIDR). | ||
- `tunnel` (Boolean) Whether IPv4 tunnelling is enabled. | ||
|
||
|
||
<a id="nestedatt--ipv6"></a> | ||
### Nested Schema for `ipv6` | ||
|
||
Read-Only: | ||
|
||
- `autoconf` (Boolean) Whether auto-configuration is enabled for the address. | ||
- `deprecated` (Boolean) Whether the address is deprecated. | ||
- `ipaddr` (String) IPv6 address assigned to the interface. | ||
- `link_local` (Boolean) Whether the address is link-local. | ||
- `subnetbits` (Number) Number of subnet bits (i.e. CIDR). | ||
- `tentative` (Boolean) Whether the address is tentative. | ||
- `tunnel` (Boolean) Whether IPv6 tunnelling is enabled. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package service | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/browningluke/opnsense-go/pkg/api" | ||
"github.com/browningluke/opnsense-go/pkg/opnsense" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
) | ||
|
||
// Ensure provider defined types fully satisfy framework interfaces. | ||
var _ datasource.DataSource = &InterfaceDataSource{} | ||
|
||
func NewInterfaceDataSource() datasource.DataSource { | ||
return &InterfaceDataSource{} | ||
} | ||
|
||
// InterfaceDataSource defines the data source implementation. | ||
type InterfaceDataSource struct { | ||
client opnsense.Client | ||
} | ||
|
||
func (d *InterfaceDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = req.ProviderTypeName + "_interface" | ||
} | ||
|
||
func (d *InterfaceDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
resp.Schema = InterfaceDataSourceSchema() | ||
} | ||
|
||
func (d *InterfaceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
// Prevent panic if the provider has not been configured. | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
apiClient, ok := req.ProviderData.(*api.Client) | ||
if !ok { | ||
resp.Diagnostics.AddError( | ||
"Unexpected Resource Configure Type", | ||
fmt.Sprintf("Expected *opnsense.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), | ||
) | ||
return | ||
} | ||
|
||
d.client = opnsense.NewClient(apiClient) | ||
} | ||
|
||
func (d *InterfaceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var data *InterfaceDataSourceModel | ||
|
||
// Read Terraform configuration data into the model | ||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) | ||
|
||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
// Get resource from OPNsense API | ||
resource, err := d.client.Diagnostics().GetInterface(ctx, data.Device.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Client Error", | ||
fmt.Sprintf("Unable to read interface, got error: %s", err)) | ||
return | ||
} | ||
|
||
// Convert OPNsense struct to TF schema | ||
model, err := convertInterfaceConfigStructToSchema(resource) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Client Error", | ||
fmt.Sprintf("Unable to read interface, got error: %s", err)) | ||
return | ||
} | ||
|
||
// Save updated data into Terraform state | ||
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
package service | ||
|
||
import ( | ||
"context" | ||
"github.com/browningluke/opnsense-go/pkg/diagnostics" | ||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"terraform-provider-opnsense/internal/tools" | ||
) | ||
|
||
type InterfaceDataSourceModel struct { | ||
Device types.String `tfsdk:"device"` | ||
Media types.String `tfsdk:"media"` | ||
MediaRaw types.String `tfsdk:"media_raw"` | ||
MacAddr types.String `tfsdk:"macaddr"` | ||
IsPhysical types.Bool `tfsdk:"is_physical"` | ||
MTU types.Int64 `tfsdk:"mtu"` | ||
Status types.String `tfsdk:"status"` | ||
|
||
Flags types.Set `tfsdk:"flags"` | ||
Capabilities types.Set `tfsdk:"capabilities"` | ||
Options types.Set `tfsdk:"options"` | ||
SupportedMedia types.Set `tfsdk:"supported_media"` | ||
Groups types.Set `tfsdk:"groups"` | ||
|
||
Ipv4 types.List `tfsdk:"ipv4"` | ||
Ipv6 types.List `tfsdk:"ipv6"` | ||
} | ||
|
||
type Ipv4Model struct { | ||
Ipaddr types.String `tfsdk:"ipaddr"` | ||
SubnetBits types.Int64 `tfsdk:"subnetbits"` | ||
Tunnel types.Bool `tfsdk:"tunnel"` | ||
} | ||
|
||
type Ipv6Model struct { | ||
Ipaddr types.String `tfsdk:"ipaddr"` | ||
SubnetBits types.Int64 `tfsdk:"subnetbits"` | ||
Tunnel types.Bool `tfsdk:"tunnel"` | ||
Autoconf types.Bool `tfsdk:"autoconf"` | ||
Deprecated types.Bool `tfsdk:"deprecated"` | ||
LinkLocal types.Bool `tfsdk:"link_local"` | ||
Tentative types.Bool `tfsdk:"tentative"` | ||
} | ||
|
||
var ipv4AttrTypes = map[string]attr.Type{ | ||
"ipaddr": types.StringType, | ||
"subnetbits": types.Int64Type, | ||
"tunnel": types.BoolType, | ||
} | ||
|
||
var ipv6AttrTypes = map[string]attr.Type{ | ||
"ipaddr": types.StringType, | ||
"subnetbits": types.Int64Type, | ||
"tunnel": types.BoolType, | ||
"autoconf": types.BoolType, | ||
"deprecated": types.BoolType, | ||
"link_local": types.BoolType, | ||
"tentative": types.BoolType, | ||
} | ||
|
||
func InterfaceDataSourceSchema() schema.Schema { | ||
return schema.Schema{ | ||
MarkdownDescription: "Interfaces can be used to get configurations of OPNsense interfaces.", | ||
|
||
Attributes: map[string]schema.Attribute{ | ||
"device": schema.StringAttribute{ | ||
MarkdownDescription: "Name of the interface device.", | ||
Required: true, | ||
}, | ||
"media": schema.StringAttribute{ | ||
MarkdownDescription: "Interface media type settings (see https://man.openbsd.org/ifmedia.4).", | ||
Computed: true, | ||
}, | ||
"media_raw": schema.StringAttribute{ | ||
MarkdownDescription: "User-friendly interface media type.", | ||
Computed: true, | ||
}, | ||
"macaddr": schema.StringAttribute{ | ||
MarkdownDescription: "MAC address assigned to the interface.", | ||
Computed: true, | ||
}, | ||
"is_physical": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether the interface is physical or virtual.", | ||
Computed: true, | ||
}, | ||
"mtu": schema.Int64Attribute{ | ||
MarkdownDescription: "Maximum Transmission Unit for the interface. This is typically 1500 bytes but can vary in some circumstances.", | ||
Computed: true, | ||
}, | ||
"status": schema.StringAttribute{ | ||
MarkdownDescription: "Status of the interface (e.g. `\"active\"`).", | ||
Computed: true, | ||
}, | ||
"flags": schema.SetAttribute{ | ||
MarkdownDescription: "List of flags configured on the interface (equiv. to flags=xxxx in output of ifconfig).", | ||
Computed: true, | ||
ElementType: types.StringType, | ||
}, | ||
"capabilities": schema.SetAttribute{ | ||
MarkdownDescription: "List of capabilities the interface supports.", | ||
Computed: true, | ||
ElementType: types.StringType, | ||
}, | ||
"options": schema.SetAttribute{ | ||
MarkdownDescription: "List of options configured on the interface (equiv. to options=xx in output of ifconfig).", | ||
Computed: true, | ||
ElementType: types.StringType, | ||
}, | ||
"supported_media": schema.SetAttribute{ | ||
MarkdownDescription: "List of supported media type settings (see https://man.openbsd.org/ifmedia.4).", | ||
Computed: true, | ||
ElementType: types.StringType, | ||
}, | ||
"groups": schema.SetAttribute{ | ||
MarkdownDescription: "List of groups the interface is a member of.", | ||
Computed: true, | ||
ElementType: types.StringType, | ||
}, | ||
"ipv4": schema.ListNestedAttribute{ | ||
Computed: true, | ||
NestedObject: schema.NestedAttributeObject{ | ||
Attributes: map[string]schema.Attribute{ | ||
"ipaddr": schema.StringAttribute{ | ||
MarkdownDescription: "IPv4 address assigned to the interface.", | ||
Computed: true, | ||
}, | ||
"subnetbits": schema.Int64Attribute{ | ||
MarkdownDescription: "Number of subnet bits (i.e. CIDR).", | ||
Computed: true, | ||
}, | ||
"tunnel": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether IPv4 tunnelling is enabled.", | ||
Computed: true, | ||
}, | ||
}, | ||
}}, | ||
"ipv6": schema.ListNestedAttribute{ | ||
Computed: true, | ||
NestedObject: schema.NestedAttributeObject{ | ||
Attributes: map[string]schema.Attribute{ | ||
"ipaddr": schema.StringAttribute{ | ||
MarkdownDescription: "IPv6 address assigned to the interface.", | ||
Computed: true, | ||
}, | ||
"subnetbits": schema.Int64Attribute{ | ||
MarkdownDescription: "Number of subnet bits (i.e. CIDR).", | ||
Computed: true, | ||
}, | ||
"tunnel": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether IPv6 tunnelling is enabled.", | ||
Computed: true, | ||
}, | ||
"autoconf": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether auto-configuration is enabled for the address.", | ||
Computed: true, | ||
}, | ||
"deprecated": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether the address is deprecated.", | ||
Computed: true, | ||
}, | ||
"link_local": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether the address is link-local.", | ||
Computed: true, | ||
}, | ||
"tentative": schema.BoolAttribute{ | ||
MarkdownDescription: "Whether the address is tentative.", | ||
Computed: true, | ||
}, | ||
}, | ||
}}, | ||
}, | ||
} | ||
} | ||
|
||
func convertInterfaceConfigStructToSchema(d *diagnostics.Interface) (*InterfaceDataSourceModel, error) { | ||
model := &InterfaceDataSourceModel{ | ||
Device: types.StringValue(d.Device), | ||
Media: types.StringValue(d.Media), | ||
MediaRaw: types.StringValue(d.MediaRaw), | ||
MacAddr: types.StringValue(d.MacAddr), | ||
IsPhysical: types.BoolValue(d.IsPhysical), | ||
MTU: tools.StringToInt64Null(d.MTU), | ||
Status: types.StringValue(d.Status), | ||
Flags: tools.StringSliceToSet(d.Flags), | ||
Capabilities: tools.StringSliceToSet(d.Capabilities), | ||
Options: tools.StringSliceToSet(d.Options), | ||
SupportedMedia: tools.StringSliceToSet(d.SupportedMedia), | ||
Groups: tools.StringSliceToSet(d.Groups), | ||
} | ||
|
||
// Creating an empty slice results in `[]` rather than `null` if OPNsense API returned an empty list. | ||
ipv4s := []Ipv4Model{} | ||
for _, elem := range d.Ipv4 { | ||
ipv4s = append(ipv4s, Ipv4Model{ | ||
Ipaddr: types.StringValue(elem.IpAddr), | ||
SubnetBits: types.Int64Value(elem.SubnetBits), | ||
Tunnel: types.BoolValue(elem.Tunnel), | ||
}) | ||
} | ||
|
||
ipv6s := []Ipv6Model{} | ||
for _, elem := range d.Ipv6 { | ||
ipv6s = append(ipv6s, Ipv6Model{ | ||
Ipaddr: types.StringValue(elem.IpAddr), | ||
SubnetBits: types.Int64Value(elem.SubnetBits), | ||
Tunnel: types.BoolValue(elem.Tunnel), | ||
Autoconf: types.BoolValue(elem.Autoconf), | ||
Deprecated: types.BoolValue(elem.Deprecated), | ||
LinkLocal: types.BoolValue(elem.LinkLocal), | ||
Tentative: types.BoolValue(elem.Tentative), | ||
}) | ||
} | ||
|
||
model.Ipv4, _ = types.ListValueFrom( | ||
context.Background(), | ||
types.ObjectType{}.WithAttributeTypes(ipv4AttrTypes), | ||
ipv4s, | ||
) | ||
|
||
model.Ipv6, _ = types.ListValueFrom( | ||
context.Background(), | ||
types.ObjectType{}.WithAttributeTypes(ipv6AttrTypes), | ||
ipv6s, | ||
) | ||
|
||
return model, nil | ||
} |
Oops, something went wrong.