Plenty of writes now works and an expanded example exists in the terraform directory

This commit is contained in:
Joachim Friberg committed 2026-08-25 20:25:08 +02:00
1 parent a6f1019175
commit fb8d468943
15 files changed
+1344 -74

No files matched your search

@@ -17,21 +17,48 @@ import (
var _ provider.Provider = &hpe1810Provider{}
type hpe1810Provider struct {
version string
version string
client *client.Client
saveRunningConfig bool
}
// hpe1810ProviderModel mirrors config.py's three settings (SWITCH_HOST,
// SWITCH_HTTPS, SWITCH_PASSWORD) from the Python reference implementation.
// SWITCH_HTTPS, SWITCH_PASSWORD) from the Python reference implementation,
// plus save_running_config which has no Python-side equivalent.
type hpe1810ProviderModel struct {
Host types.String `tfsdk:"host"`
HTTPS types.Bool `tfsdk:"https"`
Password types.String `tfsdk:"password"`
Host types.String `tfsdk:"host"`
HTTPS types.Bool `tfsdk:"https"`
Password types.String `tfsdk:"password"`
SaveRunningConfig types.Bool `tfsdk:"save_running_config"`
AdminPort types.Int64 `tfsdk:"admin_port"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &hpe1810Provider{version: version}
// New returns a single provider instance (not a fresh one per call) so that
// main.go can hold onto it and call Shutdown() after providerserver.Serve
// returns -- see Shutdown() below.
func New(version string) *hpe1810Provider {
return &hpe1810Provider{version: version}
}
// Shutdown runs once, when the provider process is exiting (main.go calls
// it right after providerserver.Serve returns). It optionally persists any
// changes made this run to the switch's non-volatile config, then always
// releases the session slot.
//
// The save only happens if save_running_config=true AND the client actually
// wrote something this run (client.Dirty()) -- a plan-only invocation, or a
// run where nothing changed, does not trigger a save. This matters because
// "Save Configuration" writes to flash, and doing that on every single
// `tofu` invocation regardless of whether anything changed would wear it
// out for no reason.
func (p *hpe1810Provider) Shutdown() {
if p.client == nil {
return
}
if p.saveRunningConfig && p.client.Dirty() {
_ = p.client.SaveRunningConfig()
}
_ = p.client.Logout()
}
func (p *hpe1810Provider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
@@ -56,6 +83,14 @@ func (p *hpe1810Provider) Schema(_ context.Context, _ provider.SchemaRequest, re
Sensitive: true,
Description: "Switch login password. Falls back to the HPE1810_PASSWORD env var, then empty.",
},
"save_running_config": schema.BoolAttribute{
Optional: true,
Description: "If true, persist changes to the switch's non-volatile config (\"Save Configuration\") at the end of this run, but only when this run actually wrote something. Falls back to the HPE1810_SAVE_RUNNING_CONFIG env var, then false. Leave false while iterating -- IaC already has the config as source of truth, and saving unnecessarily wears the switch's flash.",
},
"admin_port": schema.Int64Attribute{
Optional: true,
Description: "The interface number hpe1810_port refuses to write to under any circumstances -- protects the switch's uplink/management port. Falls back to the HPE1810_ADMIN_PORT env var, then 24. An int, not a string, so it can't be set to a non-numeric value that would silently never match a real interface.",
},
},
}
}
@@ -88,16 +123,37 @@ func (p *hpe1810Provider) Configure(ctx context.Context, req provider.ConfigureR
password = config.Password.ValueString()
}
saveRunningConfig := false
if envSave := os.Getenv("HPE1810_SAVE_RUNNING_CONFIG"); envSave != "" {
saveRunningConfig, _ = strconv.ParseBool(envSave)
}
if !config.SaveRunningConfig.IsNull() {
saveRunningConfig = config.SaveRunningConfig.ValueBool()
}
p.saveRunningConfig = saveRunningConfig
adminPort := int64(24)
if envAdminPort := os.Getenv("HPE1810_ADMIN_PORT"); envAdminPort != "" {
if parsed, err := strconv.ParseInt(envAdminPort, 10, 64); err == nil {
adminPort = parsed
}
}
if !config.AdminPort.IsNull() {
adminPort = config.AdminPort.ValueInt64()
}
c, err := client.NewClient(host, https, password)
if err != nil {
resp.Diagnostics.AddError("Unable to create switch client", err.Error())
return
}
c.AdminPort = adminPort
if err := c.Login(); err != nil {
resp.Diagnostics.AddError("Unable to log in to switch", err.Error())
return
}
p.client = c
resp.DataSourceData = c
resp.ResourceData = c
}
@@ -121,8 +177,12 @@ func (p *hpe1810Provider) DataSources(_ context.Context) []func() datasource.Dat
}
}
// Resources will grow one entry per actions/*.py equivalent (locator first)
// as they're ported.
// Resources: one entry per actions/*.py equivalent, as they're ported.
func (p *hpe1810Provider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{}
return []func() resource.Resource{
NewLocatorResource,
NewGreenFeaturesResource,
NewPortResource,
NewSystemDescriptionResource,
}
}