195 lines
7 KiB
Go
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
|
|
}
|
|
}
|