go-network-configurator/options.go
2026-07-01 15:17:11 -05:00

195 lines
7 KiB
Go

package netconfig
import (
"time"
log "github.com/sirupsen/logrus"
)
// Defaults for the tunable settings. They can be overridden with the
// corresponding With* Option when constructing a Configurator.
const (
// defaultConnectivityTimeout bounds the HTTP reachability test run after an
// address or gateway change so it cannot stall the rollback logic.
defaultConnectivityTimeout = 10 * time.Second
// defaultPingCount is the number of ICMP probes used to confirm a gateway or
// candidate address is reachable.
defaultPingCount = 5
// defaultPingTimeout bounds a single ping run.
defaultPingTimeout = 20 * time.Second
// defaultBackupRetention is how many .bak.* copies are kept per original
// configuration file. Older backups beyond this number are pruned on save.
defaultBackupRetention = 5
)
// Logger is the minimal logging surface used across the package. It is
// satisfied by the standard library *log.Logger, logrus, and most other
// logging libraries, so callers can plug in their own logger via SetLogger.
type Logger interface {
Printf(format string, args ...interface{})
Println(args ...interface{})
}
// logger is the package-wide logger. It defaults to the logrus standard
// logger and can be replaced with SetLogger. It is package scoped because the
// configuration backends and control panels log independently of any single
// Configurator instance.
var logger Logger = log.StandardLogger()
// SetLogger replaces the package-wide logger used for non-fatal diagnostics.
// It is package scoped (not a per-Configurator option) because the configuration
// backends and control panels log independently of any single Configurator
// instance; the setting therefore applies to every Configurator in the process.
// A nil logger is ignored.
func SetLogger(l Logger) {
if l != nil {
logger = l
}
}
// configOptions holds the tunable settings applied when constructing a
// Configurator. Use the With* Option helpers to set them.
type configOptions struct {
// testAddress is the URL fetched to confirm connectivity after an
// address or gateway change.
testAddress string
// skipConnectivityCheck disables the post-change internet reachability
// test and its automatic rollback.
skipConnectivityCheck bool
// connectivityTimeout bounds the HTTP reachability test.
connectivityTimeout time.Duration
// pingCount is the number of ICMP probes per ping test.
pingCount int
// pingTimeout bounds a single ping run.
pingTimeout time.Duration
// backupRetention is the number of .bak.* copies kept per original
// configuration file; <= 0 disables pruning (keeps all backups).
backupRetention int
// allowPrimaryRemoval lets RemoveAddress remove an address that is the
// primary of its family, which is otherwise refused.
allowPrimaryRemoval bool
// skipPanels makes RemoveAddress bypass all control-panel backends
// (cPanel/Plesk/InterWorx) and only remove the address from the running
// system and the network-manager configuration files.
skipPanels bool
}
// defaultConfigOptions returns the options used when no Option is supplied.
func defaultConfigOptions() *configOptions {
return &configOptions{
testAddress: defaultInternetTestAddress,
connectivityTimeout: defaultConnectivityTimeout,
pingCount: defaultPingCount,
pingTimeout: defaultPingTimeout,
backupRetention: defaultBackupRetention,
}
}
// newConfigOptions builds a configOptions from the supplied options, starting
// from the package defaults.
func newConfigOptions(opts ...Option) *configOptions {
o := defaultConfigOptions()
for _, opt := range opts {
if opt != nil {
opt(o)
}
}
return o
}
// Option configures a Configurator constructed with NewConfigurator.
type Option func(*configOptions)
// WithTestAddress overrides the URL used for the post-change connectivity
// test. The two sentinel values "test_success" and "test_fail" force the test
// to pass or fail without performing a request, which is useful in tests.
func WithTestAddress(addr string) Option {
return func(o *configOptions) {
if addr != "" {
o.testAddress = addr
}
}
}
// WithConnectivityCheck enables or disables the post-change internet
// reachability test (and the automatic rollback that depends on it). It is
// enabled by default; pass false to skip it, for example on hosts with no
// outbound internet access.
func WithConnectivityCheck(enabled bool) Option {
return func(o *configOptions) {
o.skipConnectivityCheck = !enabled
}
}
// WithSkipConnectivityCheck is a convenience option that disables the post-change
// internet reachability test and its automatic rollback. It is equivalent to
// WithConnectivityCheck(false).
func WithSkipConnectivityCheck() Option {
return WithConnectivityCheck(false)
}
// WithConnectivityTimeout sets the timeout for the HTTP reachability test run
// after an address or gateway change. A smaller value fails faster on a
// black-holed route; a larger value tolerates slower links.
func WithConnectivityTimeout(d time.Duration) Option {
return func(o *configOptions) {
if d > 0 {
o.connectivityTimeout = d
}
}
}
// WithPingCount sets the number of ICMP probes sent when confirming that a
// candidate address or gateway is reachable. More probes are more reliable on
// lossy links but take longer.
func WithPingCount(n int) Option {
return func(o *configOptions) {
if n > 0 {
o.pingCount = n
}
}
}
// WithPingTimeout sets the overall timeout for a single ping run.
func WithPingTimeout(d time.Duration) Option {
return func(o *configOptions) {
if d > 0 {
o.pingTimeout = d
}
}
}
// WithBackupRetention sets how many .bak.* copies are kept per original
// configuration file. The oldest backups beyond this number are pruned each
// time a backend saves. Pass 0 (or a negative value) to disable pruning and
// keep every backup.
func WithBackupRetention(n int) Option {
return func(o *configOptions) {
o.backupRetention = n
}
}
// WithAllowPrimaryRemoval permits RemoveAddress to remove an address that is
// the primary of its family on its interface. By default removing the primary
// is refused so a caller cannot accidentally change the system's source
// address or leave a control panel without a main IP; the intended flow is to
// SetPrimaryAddress on another IP first. Enable this only when you are
// deliberately tearing down the current primary.
func WithAllowPrimaryRemoval(allowed bool) Option {
return func(o *configOptions) {
o.allowPrimaryRemoval = allowed
}
}
// WithSkipPanels makes the configurator skip all control-panel backends
// (cPanel, Plesk, InterWorx) during mutating operations. When enabled,
// AddAddress, SetPrimaryAddress, and RemoveAddress do not tell the panels to
// reload, set the main IP, or release an IP; only the running system and the
// network-manager configuration files are changed. This is intended for
// maintenance paths where the panel must be left untouched, or where the panel
// is expected to be reconciled separately.
func WithSkipPanels(skip bool) Option {
return func(o *configOptions) {
o.skipPanels = skip
}
}