274 lines
9.3 KiB
Go
274 lines
9.3 KiB
Go
// Port of LLDPConfig.html's "Global Mode" table only. The page also has a
|
|
// per-port "Interface Mode" table (Transmit/Receive Enable etc, one row per
|
|
// port with per-port field names like "1.0.24.v_2_1_2") -- that's a
|
|
// separate, more involved write target (needs the same per-port-field-name
|
|
// handling as resource_port.go) and isn't built yet; only requested was
|
|
// "LLDP Configuration" which maps to the global settings.
|
|
package provider
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
|
|
"terraform-provider-hpe1810/internal/provider/client"
|
|
)
|
|
|
|
const (
|
|
lldpConfigPath = "/LLDPConfig.html"
|
|
lldpGlobalModeCaption = "Global Mode"
|
|
lldpTransmitIntervalLabel = "Transmit Interval"
|
|
lldpTransmitHoldLabel = "Transmit Hold"
|
|
lldpReinitDelayLabel = "Re-Initialization Delay"
|
|
lldpNotificationIntervalLabel = "Notification Interval"
|
|
)
|
|
|
|
var (
|
|
_ resource.Resource = &lldpConfigurationResource{}
|
|
_ resource.ResourceWithConfigure = &lldpConfigurationResource{}
|
|
)
|
|
|
|
func NewLLDPConfigurationResource() resource.Resource {
|
|
return &lldpConfigurationResource{}
|
|
}
|
|
|
|
type lldpConfigurationResource struct {
|
|
client *client.Client
|
|
}
|
|
|
|
type lldpConfigurationResourceModel struct {
|
|
ID types.String `tfsdk:"id"`
|
|
TransmitInterval types.Int64 `tfsdk:"transmit_interval"`
|
|
TransmitHold types.Int64 `tfsdk:"transmit_hold"`
|
|
ReinitDelay types.Int64 `tfsdk:"reinit_delay"`
|
|
NotificationInterval types.Int64 `tfsdk:"notification_interval"`
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
|
resp.TypeName = req.ProviderTypeName + "_lldp_configuration"
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
|
resp.Schema = schema.Schema{
|
|
Description: "Controls the switch's LLDP Global Mode settings (LLDPConfig.html). Singleton -- there is only ever one of these per switch. Does NOT cover the page's per-port Interface Mode table -- see the package doc comment. Delete resets all four fields to their documented factory defaults.",
|
|
Attributes: map[string]schema.Attribute{
|
|
"id": schema.StringAttribute{
|
|
Computed: true,
|
|
Description: "Always \"lldp_configuration\" -- this is a singleton resource.",
|
|
},
|
|
"transmit_interval": schema.Int64Attribute{
|
|
Required: true,
|
|
Description: "Seconds between LLDP transmissions. Range 5-32768 (switch default: 30).",
|
|
},
|
|
"transmit_hold": schema.Int64Attribute{
|
|
Required: true,
|
|
Description: "Multiplier for how long a receiver holds LLDP info before aging it out. Range 2-10 (switch default: 4).",
|
|
},
|
|
"reinit_delay": schema.Int64Attribute{
|
|
Required: true,
|
|
Description: "Seconds to wait before re-initializing LLDP on a port after it's disabled. Range 1-10 (switch default: 2).",
|
|
},
|
|
"notification_interval": schema.Int64Attribute{
|
|
Required: true,
|
|
Description: "Minimum seconds between LLDP change notifications. Range 5-3600 (switch default: 5).",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
|
if req.ProviderData == nil {
|
|
return
|
|
}
|
|
c, ok := req.ProviderData.(*client.Client)
|
|
if !ok {
|
|
resp.Diagnostics.AddError("Unexpected resource configure type", fmt.Sprintf("expected *client.Client, got %T", req.ProviderData))
|
|
return
|
|
}
|
|
r.client = c
|
|
}
|
|
|
|
type lldpConfigurationState struct {
|
|
TransmitInterval int64
|
|
TransmitHold int64
|
|
ReinitDelay int64
|
|
NotificationInterval int64
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) readState() (lldpConfigurationState, error) {
|
|
tables, err := r.client.FetchTables(lldpConfigPath)
|
|
if err != nil {
|
|
return lldpConfigurationState{}, err
|
|
}
|
|
table, ok := tables[lldpGlobalModeCaption]
|
|
if !ok {
|
|
return lldpConfigurationState{}, fmt.Errorf("table captioned %q not found on %s", lldpGlobalModeCaption, lldpConfigPath)
|
|
}
|
|
|
|
parse := func(label string) (int64, error) {
|
|
v, err := strconv.ParseInt(table.Record[label], 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("parsing %q (%q) as int: %w", label, table.Record[label], err)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
transmitInterval, err := parse(lldpTransmitIntervalLabel)
|
|
if err != nil {
|
|
return lldpConfigurationState{}, err
|
|
}
|
|
transmitHold, err := parse(lldpTransmitHoldLabel)
|
|
if err != nil {
|
|
return lldpConfigurationState{}, err
|
|
}
|
|
reinitDelay, err := parse(lldpReinitDelayLabel)
|
|
if err != nil {
|
|
return lldpConfigurationState{}, err
|
|
}
|
|
notificationInterval, err := parse(lldpNotificationIntervalLabel)
|
|
if err != nil {
|
|
return lldpConfigurationState{}, err
|
|
}
|
|
|
|
return lldpConfigurationState{
|
|
TransmitInterval: transmitInterval,
|
|
TransmitHold: transmitHold,
|
|
ReinitDelay: reinitDelay,
|
|
NotificationInterval: notificationInterval,
|
|
}, nil
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) setState(desired lldpConfigurationState) error {
|
|
tables, err := r.client.FetchTables(lldpConfigPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
table, ok := tables[lldpGlobalModeCaption]
|
|
if !ok {
|
|
return fmt.Errorf("table captioned %q not found on %s", lldpGlobalModeCaption, lldpConfigPath)
|
|
}
|
|
|
|
field := func(label string) (string, error) {
|
|
f, ok := table.FieldNames[label]
|
|
if !ok {
|
|
return "", fmt.Errorf("field %q not found in table %q", label, lldpGlobalModeCaption)
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
transmitIntervalField, err := field(lldpTransmitIntervalLabel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transmitHoldField, err := field(lldpTransmitHoldLabel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
reinitDelayField, err := field(lldpReinitDelayLabel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
notificationIntervalField, err := field(lldpNotificationIntervalLabel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = r.client.SubmitForm(lldpConfigPath, map[string]string{
|
|
transmitIntervalField: strconv.FormatInt(desired.TransmitInterval, 10),
|
|
transmitHoldField: strconv.FormatInt(desired.TransmitHold, 10),
|
|
reinitDelayField: strconv.FormatInt(desired.ReinitDelay, 10),
|
|
notificationIntervalField: strconv.FormatInt(desired.NotificationInterval, 10),
|
|
})
|
|
return err
|
|
}
|
|
|
|
func lldpConfigStateToModel(s lldpConfigurationState) lldpConfigurationResourceModel {
|
|
return lldpConfigurationResourceModel{
|
|
ID: types.StringValue("lldp_configuration"),
|
|
TransmitInterval: types.Int64Value(s.TransmitInterval),
|
|
TransmitHold: types.Int64Value(s.TransmitHold),
|
|
ReinitDelay: types.Int64Value(s.ReinitDelay),
|
|
NotificationInterval: types.Int64Value(s.NotificationInterval),
|
|
}
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
|
var plan lldpConfigurationResourceModel
|
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
|
if resp.Diagnostics.HasError() {
|
|
return
|
|
}
|
|
|
|
desired := lldpConfigurationState{
|
|
TransmitInterval: plan.TransmitInterval.ValueInt64(),
|
|
TransmitHold: plan.TransmitHold.ValueInt64(),
|
|
ReinitDelay: plan.ReinitDelay.ValueInt64(),
|
|
NotificationInterval: plan.NotificationInterval.ValueInt64(),
|
|
}
|
|
if err := r.setState(desired); err != nil {
|
|
resp.Diagnostics.AddError("Unable to set LLDP Configuration state", err.Error())
|
|
return
|
|
}
|
|
|
|
actual, err := r.readState()
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Unable to read back LLDP Configuration state", err.Error())
|
|
return
|
|
}
|
|
|
|
state := lldpConfigStateToModel(actual)
|
|
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Read(ctx context.Context, _ resource.ReadRequest, resp *resource.ReadResponse) {
|
|
actual, err := r.readState()
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Unable to read LLDP Configuration state", err.Error())
|
|
return
|
|
}
|
|
|
|
state := lldpConfigStateToModel(actual)
|
|
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
|
}
|
|
|
|
func (r *lldpConfigurationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
|
var plan lldpConfigurationResourceModel
|
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
|
if resp.Diagnostics.HasError() {
|
|
return
|
|
}
|
|
|
|
desired := lldpConfigurationState{
|
|
TransmitInterval: plan.TransmitInterval.ValueInt64(),
|
|
TransmitHold: plan.TransmitHold.ValueInt64(),
|
|
ReinitDelay: plan.ReinitDelay.ValueInt64(),
|
|
NotificationInterval: plan.NotificationInterval.ValueInt64(),
|
|
}
|
|
if err := r.setState(desired); err != nil {
|
|
resp.Diagnostics.AddError("Unable to set LLDP Configuration state", err.Error())
|
|
return
|
|
}
|
|
|
|
actual, err := r.readState()
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Unable to read back LLDP Configuration state", err.Error())
|
|
return
|
|
}
|
|
|
|
state := lldpConfigStateToModel(actual)
|
|
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
|
}
|
|
|
|
// Delete resets all four fields to their documented factory defaults --
|
|
// safe, no traffic impact.
|
|
func (r *lldpConfigurationResource) Delete(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) {
|
|
defaults := lldpConfigurationState{TransmitInterval: 30, TransmitHold: 4, ReinitDelay: 2, NotificationInterval: 5}
|
|
if err := r.setState(defaults); err != nil {
|
|
resp.Diagnostics.AddError("Unable to reset LLDP Configuration state on delete", err.Error())
|
|
}
|
|
}
|