189 lines
6.4 KiB
Go
189 lines
6.4 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
|
"github.com/hashicorp/terraform-plugin-framework/provider"
|
|
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
|
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
|
|
"terraform-provider-hpe1810/internal/provider/client"
|
|
)
|
|
|
|
var _ provider.Provider = &hpe1810Provider{}
|
|
|
|
type hpe1810Provider struct {
|
|
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,
|
|
// 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"`
|
|
SaveRunningConfig types.Bool `tfsdk:"save_running_config"`
|
|
AdminPort types.Int64 `tfsdk:"admin_port"`
|
|
}
|
|
|
|
// 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) {
|
|
resp.TypeName = "hpe1810"
|
|
resp.Version = p.version
|
|
}
|
|
|
|
func (p *hpe1810Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
|
|
resp.Schema = schema.Schema{
|
|
Description: "Manages an HP ProCurve/OfficeConnect 1810 switch over its built-in web UI.",
|
|
Attributes: map[string]schema.Attribute{
|
|
"host": schema.StringAttribute{
|
|
Optional: true,
|
|
Description: "Switch IP or hostname. Falls back to the HPE1810_HOST env var, then \"192.168.2.10\".",
|
|
},
|
|
"https": schema.BoolAttribute{
|
|
Optional: true,
|
|
Description: "Use HTTPS instead of HTTP. Falls back to the HPE1810_HTTPS env var, then false.",
|
|
},
|
|
"password": schema.StringAttribute{
|
|
Optional: true,
|
|
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.",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (p *hpe1810Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
|
|
var config hpe1810ProviderModel
|
|
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
|
|
if resp.Diagnostics.HasError() {
|
|
return
|
|
}
|
|
|
|
host := os.Getenv("HPE1810_HOST")
|
|
if host == "" {
|
|
host = "192.168.2.10"
|
|
}
|
|
if !config.Host.IsNull() {
|
|
host = config.Host.ValueString()
|
|
}
|
|
|
|
https := false
|
|
if envHTTPS := os.Getenv("HPE1810_HTTPS"); envHTTPS != "" {
|
|
https, _ = strconv.ParseBool(envHTTPS)
|
|
}
|
|
if !config.HTTPS.IsNull() {
|
|
https = config.HTTPS.ValueBool()
|
|
}
|
|
|
|
password := os.Getenv("HPE1810_PASSWORD")
|
|
if !config.Password.IsNull() {
|
|
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
|
|
}
|
|
|
|
// DataSources: one entry per extractors/*.py equivalent.
|
|
func (p *hpe1810Provider) DataSources(_ context.Context) []func() datasource.DataSource {
|
|
return []func() datasource.DataSource{
|
|
NewSystemDescriptionDataSource,
|
|
NewNetworkSetupDataSource,
|
|
NewPortSummaryDataSource,
|
|
NewLLDPStatisticsDataSource,
|
|
NewBufferedLogDataSource,
|
|
NewMACTableDataSource,
|
|
NewTrunkStatusDataSource,
|
|
NewLoopProtectionStatusDataSource,
|
|
NewDualImageStatusDataSource,
|
|
NewClockDataSource,
|
|
NewSNTPDataSource,
|
|
NewLogConfigurationDataSource,
|
|
NewBackupManagerDataSource,
|
|
}
|
|
}
|
|
|
|
// Resources: one entry per actions/*.py equivalent, as they're ported.
|
|
func (p *hpe1810Provider) Resources(_ context.Context) []func() resource.Resource {
|
|
return []func() resource.Resource{
|
|
NewLocatorResource,
|
|
NewGreenFeaturesResource,
|
|
NewPortResource,
|
|
NewSystemDescriptionResource,
|
|
}
|
|
}
|