Documentation
¶
Index ¶
- Constants
- func ConnectDatabase(config *ConfigDB) (*gorm.DB, error)
- func FactumHTTP(cfg *ConfigFactum) (client *http.Client, baseURL string, viaSocket bool, err error)
- func FetchRemoteConfig[T any](factumConfig *ConfigFactum, path string) (*T, error)
- func FormatName(defaultDomain string, name string) string
- func GetOrCreateSettings(db *gorm.DB) (*models.Settings, error)
- func HubSocketPath(yamlOverride string) string
- func MigrateDatabase(db *gorm.DB) error
- func OrganizationEnabled(db *gorm.DB) bool
- func OxidizedEnabled(db *gorm.DB) bool
- func PinnedExecutable(local, remote, name string) (string, error)
- func PinnedPath(local, remote, name string) (string, error)
- func Pprint(data any)
- func ResolvePinnedKey(paths ConfigWorkerPaths, remote, defaultKey string, optional, executable bool) (string, error)
- func ShortName(name, defaultDomain string) string
- func StructToString(data any) string
- func ValidateWorkerPathKey(value string) error
- type CommonConfig
- type ConfigAgentRoot
- type ConfigDB
- type ConfigDNS
- type ConfigDeviceSync
- type ConfigDeviceSyncAuth
- type ConfigDriver
- type ConfigFactum
- type ConfigIcinga
- type ConfigIcingaCert
- type ConfigLdapWriteback
- type ConfigLibrenms
- type ConfigNetbox
- type ConfigOxidized
- type ConfigPrometheus
- type ConfigRoot
- type ConfigStorage
- type ConfigWeb
- type ConfigWorker
- type ConfigWorkerCommand
- type ConfigWorkerPaths
- type Response
Constants ¶
const ( KeyLegoBin = "lego_bin" KeyLegoYaml = "lego_yaml" KeyLegoEnv = "lego_env" KeyLegoStorage = "lego_storage" KeyDNSDestFile = "dns_dest_file" KeyDNSZonesFile = "dns_zones_file" KeyDNSPrefixesFile = "dns_prefixes_file" KeyOxidizedDestFile = "oxidized_dest_file" KeyPrometheusDestFile = "prometheus_dest_file" KeyIcingaHostsFile = "icinga_hosts_file" KeyIcingaUsersFile = "icinga_users_file" KeyIcingaCertsFile = "icinga_certs_file" KeyIcingaInterfacesFile = "icinga_interfaces_file" KeyStorageRoot = "storage_root" )
worker.paths keys. Admin → Destinations stores one of these names. The filesystem path is only in the worker YAML.
const DefaultHubSocket = "/run/factum2-worker/api.sock"
DefaultHubSocket is the unix HTTP path factum2-worker listens on and co-located CLIs probe. One constant so the two sides cannot drift.
const HubRPCTimeout = 60 * time.Second
HubRPCTimeout is the per-request bound for hub RPC (ServeHTTP after the websocket dies, CLI HTTP clients). Canonical here so util does not import worker.
Variables ¶
This section is empty.
Functions ¶
func ConnectDatabase ¶
ConnectDatabase opens Postgres and does not apply schema migrations. Call this from the web server and CLIs. Schema changes belong in the dedicated `migrate` command (cmdbase.Migrate → MigrateDatabase); running migrations as a side effect of start/sync/createadmin rewrites tables while factum2-web may already be serving.
func FactumHTTP ¶ added in v1.0.2
FactumHTTP picks a client for Factum API calls. The local worker unix socket is used when it is present and dialable; otherwise HTTPS to cfg.URL. After a successful unix Dial, RPC 502s/timeouts are not retried over HTTPS - worker-net :443 may already be closed. Unix requests send no Authorization header (the socket ACL is the auth); HTTPS keeps the bearer.
func FetchRemoteConfig ¶
func FetchRemoteConfig[T any](factumConfig *ConfigFactum, path string) (*T, error)
FetchRemoteConfig GETs path from the Factum API and unmarshals the JSON into a new T. Transport is selected by FactumHTTP (unix socket when the probe succeeds, otherwise HTTPS to factumConfig.URL with "Authorization: Bearer "+factumConfig.Token - see web.Controller.checkServiceToken). A unix 502 is returned as an error; it is not retried over HTTPS. Shared by CLI tools that typically run on a different host than the primary (factum2-icinga, factum2-oxidized, factum2-dns, factum2-librenms-cli, factum2-prometheus) to fetch their database-backed settings instead of needing a local copy - each package wraps this in its own FetchRemoteConfig returning its own config type, see e.g. internal/librenms/remote_config.go.
func FormatName ¶
FormatName appends defaultDomain when name has no '.' (a short hostname). Names that are already FQDNs (or IPv4 literals) are returned unchanged. An empty defaultDomain is a no-op so callers don't get a trailing dot.
func GetOrCreateSettings ¶
GetOrCreateSettings returns the single Settings row (id=1), creating it with zero-valued fields on first use so callers always have a row to read - most settings (integration URLs/tokens like Netbox's, previously only configurable via the YAML config file) are now database-backed and editable from the admin UI instead, so both the web API and any CLI/sync code that needs them goes through here.
func HubSocketPath ¶ added in v1.0.2
func MigrateDatabase ¶
MigrateDatabase applies schema migrations then cfgmgmt.Seed. Only cmdbase.Migrate (and tests) should call this — not ConnectDatabase.
Postgres: goose SQL in internal/dbmigrate (existing AutoMigrate DBs are stamped at the baseline version). SQLite: GORM AutoMigrateAll, for unit tests only.
func OrganizationEnabled ¶ added in v1.0.3
OrganizationEnabled reports Settings.OrganizationEnabled (nil/false = off). Disabling the flag only hides the Customers/Contacts menu — it does not touch customer or contact rows.
func OxidizedEnabled ¶ added in v1.0.4
OxidizedEnabled reports Settings.OxidizedEnabled (nil/false = off). Disabling the flag only hides the Oxidized menu and GUI browser — it does not touch device backup flags or oxidized's own router.db.
func PinnedExecutable ¶ added in v1.2.0
PinnedExecutable is PinnedPath for a command: an absolute path, or a single bare name with no directory separator (looked up on PATH).
func PinnedPath ¶ added in v1.2.0
PinnedPath checks a worker-local absolute path. remote, when set, must be that same path. Destination sync does not pass the primary's value here: ResolvePinnedKey treats it as a worker.paths key and then checks only the path from this host.
func ResolvePinnedKey ¶ added in v1.3.0
func ResolvePinnedKey(paths ConfigWorkerPaths, remote, defaultKey string, optional, executable bool) (string, error)
ResolvePinnedKey maps a destination setting to a path from the worker config. remote is a worker.paths key from the primary, never a filesystem path. An empty remote selects defaultKey. The returned path always comes from paths.
optional: an empty remote and an empty pin return "", nil. A non-empty remote still requires that key's pin. executable: the pin may be a bare command name (lego_bin).
func ShortName ¶
ShortName strips the trailing ".defaultDomain" suffix from a fully qualified name - the inverse of FormatName.
func ValidateWorkerPathKey ¶ added in v1.3.0
ValidateWorkerPathKey accepts an empty value or a worker.paths key. A filesystem path is rejected.
Types ¶
type CommonConfig ¶
type CommonConfig struct {
DefaultDomain string `json:"default_domain"`
// SmtpHost/Port/User/Pass/TLSMode and EmailSender are the shared
// outbound mail relay settings (Settings.Smtp*/EmailSender, edited on
// the admin UI's Factum > Email tab) - factum2-icinga-notifications
// is the first consumer, but any tool needing to send mail can reuse
// these instead of having its own copy.
SmtpHost string `json:"smtp_host"`
SmtpPort uint16 `json:"smtp_port"`
SmtpUser string `json:"smtp_user"`
SmtpPass string `json:"smtp_pass"`
SmtpTLSMode string `json:"smtp_tls_mode"`
EmailSender string `json:"email_sender"`
}
CommonConfig holds settings shared by every remote-config-fetching CLI tool, not just one of them: DefaultDomain (Settings.DefaultDomain, edited in the admin UI's Factum tab) is needed by DNS (the $ORIGIN of the generated zone file) as well as Icinga/LibreNMS/Oxidized/Prometheus sync (matching factum device names against fully-qualified DNS names).
Every service's REST response and runtime Config type embeds this instead of each declaring its own copy of the fields. Tools that don't need any other service-specific config (currently just factum2-worker agents) can fetch this alone from web.ApiCommonConfig (GET /api/common-config).
func NewCommonConfig ¶
func NewCommonConfig(settings *models.Settings) CommonConfig
NewCommonConfig builds a CommonConfig from the Settings row. SMTP credentials are not included: only a config the caller actually uses to send mail should call WithSMTP. Every web.ApiXxxConfig handler embeds this instead of repeating the same lines.
func WithSMTP ¶ added in v1.2.0
func WithSMTP(cfg CommonConfig, settings *models.Settings) CommonConfig
WithSMTP adds the shared mail relay to cfg. factum2-icinga-notifications is the consumer; other workers must not receive the SMTP password.
type ConfigAgentRoot ¶
type ConfigAgentRoot struct {
Factum ConfigFactum `yaml:"factum"`
Worker ConfigWorker `yaml:"worker"`
Driver ConfigDriver `yaml:"driver" optional:"true"`
Storage ConfigStorage `yaml:"storage" optional:"true"`
}
Agents get most of their configuration from the Factum API - factum2-worker is the one exception, needing its own local Worker section (worker.listen/ .token/.roles/.commands - see the comment on ConfigWorker for why these must stay local rather than fetched remotely).
type ConfigDNS ¶
type ConfigDNS struct {
CommonConfig
DestFile string
IgnoreModels string
IgnorePlatforms string
}
ConfigDNS is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigIcinga: every field has a DB-backed equivalent (Settings.DnsDestFile/DnsIgnoreModels/DnsIgnorePlatforms, plus Settings.DefaultDomain via the embedded CommonConfig), fetched over REST by internal/dns.FetchRemoteConfig/RemoteClient from web.ApiDNSConfig.
type ConfigDeviceSync ¶
type ConfigDeviceSync struct {
CommonConfig
VRFInGlobal []string
DeviceStates []string
DeviceIgnore []string
// VlanGroupName is the Netbox VLAN Group every synced VLAN is created
// in (Settings.DeviceSyncVlanGroupName) - "" disables VLAN sync.
VlanGroupName string
// InventoryMaps is sync_source → netbox_type from cfgmgmt service
// types (ELINE→evpl, ELAN→vpls, L3VPN→vrf). Empty means device-sync
// falls back to ELINE→evpl only.
InventoryMaps map[string]string
// ServiceSources is the allow-list of sync sources to write
// (eline, elan, l3vpn). Nil means every implemented source. An empty
// slice means write no services, including the ELINE fallback.
ServiceSources *[]string
// Workers is how many devices one run handles at once
// (Settings.DeviceSyncWorkers). Values below 1 mean
// models.DefaultDeviceSyncWorkers.
Workers int
Auth map[string]ConfigDeviceSyncAuth
}
ConfigDeviceSync is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigNetbox/ConfigOxidized: every scalar-ish field has a DB-backed equivalent (Settings.DeviceSyncVRFInGlobal/DeviceStates/ DeviceIgnore, all newline-separated text; Auth comes from the models.DeviceSyncAuth table instead of a Settings column, since it's a list of credentials, not a single value), fetched over REST by internal/device-sync.FetchRemoteConfig from web.ApiDeviceSyncConfig. factum2-device-sync-cli runs on the primary and talks to factum2-web over REST (util.WithoutHubSocket), not the hub unix socket. The Netbox client itself isn't fetched here - internal/netbox.RemoteClient/FetchRemoteConfig already does that (GET /api/netbox-config), and device-sync reuses it rather than duplicating Netbox credentials in a second config type.
type ConfigDeviceSyncAuth ¶
ConfigDeviceSyncAuth is the username/password internal/device-sync uses to log into a device - keyed by device name in ConfigDeviceSync.Auth, with a "default" entry as the fallback for devices without their own entry.
type ConfigDriver ¶ added in v1.1.1
type ConfigDriver struct {
Platforms *[]string `boa:"configonly" yaml:"platforms" optional:"true"`
IdleTimeout string `boa:"configonly" yaml:"idle_timeout" optional:"true"`
MaxSessions int `boa:"configonly" yaml:"max_sessions" optional:"true"`
QueueDepth int `boa:"configonly" yaml:"queue_depth" optional:"true"`
AcquireTimeout string `boa:"configonly" yaml:"acquire_timeout" optional:"true"`
Keepalive string `boa:"configonly" yaml:"keepalive" optional:"true"`
SessionURL string `boa:"configonly" yaml:"session_url" optional:"true"`
SessionToken string `boa:"configonly" yaml:"session_token" optional:"true"`
Socket string `boa:"configonly" yaml:"socket" optional:"true"`
Listen string `boa:"configonly" yaml:"listen" optional:"true"`
Token string `boa:"configonly" yaml:"token" optional:"true"`
TLSCert string `boa:"configonly" yaml:"tls_cert" optional:"true"`
TLSKey string `boa:"configonly" yaml:"tls_key" optional:"true"`
TLSCA string `boa:"configonly" yaml:"tls_ca" optional:"true"`
AllowCIDRs []string `boa:"configonly" yaml:"allow_cidrs" optional:"true"`
}
type ConfigFactum ¶
type ConfigFactum struct {
// URL/Token are optional at the boa level - like ConfigWorker.Roles,
// not every subcommand of every binary that embeds ConfigFactum
// actually calls out to the primary (e.g. "factum2-worker start" never
// does, only "run" does, via internal/worker.RunRemote), so requiring
// them unconditionally would force values into a config file that
// aren't needed for that particular subcommand. Call sites that do
// need them (RunRemote, internal/factum.FactumClient) check for an
// empty URL/Token themselves and fail with a clear error instead.
URL string `boa:"configonly" yaml:"url" optional:"true"`
// Token authenticates server-to-server callers (internal/factum's HTTP
// client, used by e.g. factum2-dns and factum2-librenms-cli, the latter
// typically running on a different host than the primary) against the
// primary's Settings.FactumApiToken, sent as "Authorization: Bearer
// <token>". See web.Controller.RequireAPIAuth.
Token string `boa:"configonly" yaml:"token" optional:"true"`
// Socket is the local unix API path when this CLI is co-located with
// factum2-worker. Empty uses DefaultHubSocket unless FACTUM_WORKER_API_SOCKET
// overrides it; "none"/"0" disables the socket (CLI-only escape hatch).
// Primary-side CLIs should call WithoutHubSocket rather than relying on
// operators to set this.
Socket string `boa:"configonly" yaml:"socket" optional:"true"`
}
func WithoutHubSocket ¶ added in v1.0.6
func WithoutHubSocket(cfg ConfigFactum) ConfigFactum
HubSocketPath resolves the unix socket. yamlOverride is ConfigFactum.Socket (CLI) or ConfigWorker.APISocket (listener). FACTUM_WORKER_API_SOCKET is the single relocation / disable knob both sides honor when the yaml override is empty. Values "none" and "0" (yaml or env) mean "no socket" (CLI: force HTTPS; worker: Start error). WithoutHubSocket returns a copy of cfg that never probes the worker unix socket. Primary-side CLIs (device-sync and anything else that runs next to factum2-web) must use this: a co-located factum2-worker still listens on the socket, and FactumHTTP would otherwise send every call over hub RPC. Dest-host CLIs (dns, icinga, …) keep the default probe.
type ConfigIcinga ¶
type ConfigIcinga struct {
CommonConfig
URL string
Username string
Password string
HostsFile string
UsersFile string
CertsFile string
InterfacesFile string
// MonitorInterfaces writes passive interface services and is what
// factum2-icinga poll requires before it polls. SNMPCommunities is a
// newline-separated SNMPv2c community list. EAPIUser/EAPIPassword are
// the Arista eAPI account for EOS patch-panel status.
MonitorInterfaces bool
SNMPCommunities string
EAPIUser string
EAPIPassword string
// IgnoreDevices is a newline-separated list of device names to skip
// entirely (Settings.IcingaIgnoreDevices).
IgnoreDevices string
// DefaultNotification is Jet template source executed with
// .Device for a host that has no CfAlarmDestination
// (Settings.IcingaDefaultNotification). Literal Icinga lines with no
// {{ }} still render unchanged. The result is inserted into the host
// object via hostTemplateData.Options.
DefaultNotification string
// HostTemplate/DependencyTemplate/UserTemplate/CertTemplate are Jet
// templates source, executed by internal/icinga.FactumIcingaClient -
// see that package for the data each is executed with.
HostTemplate string
DependencyTemplate string
UserTemplate string
CertTemplate string
// Certificates is the slim list used to emit Icinga cert checks
// (name, check host, DNS names). Fetched with icinga-config so the
// Icinga worker does not need ACME account secrets.
Certificates []ConfigIcingaCert
}
ConfigIcinga is a runtime-only DTO, not part of ConfigRoot - unlike ConfigLibrenms's Sync maps, every field here already has a DB-backed equivalent (Settings.IcingaApiURL/User/Pass/HostsFile/UsersFile/ CertsFile/InterfacesFile/MonitorInterfaces/SNMPCommunities/ IgnoreDevices/DefaultNotification/HostTemplate/ DependencyTemplate/UserTemplate/CertTemplate), so factum2-icinga - which typically runs on a different host than the primary - fetches this entirely over REST (internal/icinga.FetchRemoteConfig/RemoteClient, GET /api/icinga-config, served by web.ApiIcingaConfig from the Settings row) rather than reading any of it from local YAML.
type ConfigIcingaCert ¶ added in v1.1.1
type ConfigIcingaCert struct {
Name string `json:"name"`
Host string `json:"host"`
Domains []string `json:"domains"`
}
ConfigIcingaCert is one ACME certificate as Icinga needs it: the host to connect to and every name that must be presented on that host.
type ConfigLdapWriteback ¶
type ConfigLdapWriteback struct {
BindDN string `boa:"configonly" yaml:"bind_dn" optional:"true"`
Password string `boa:"configonly" yaml:"bind_password" optional:"true"`
}
ConfigLdapWriteback is the elevated LDAP/AD identity permitted to change another user's password (web.ApiForgotPassword/ApiResetPassword, web.ApiMeUpdate) - deliberately separate from Settings.LdapBindDN/ LdapBindPassword (the read-only search/bind service account, DB-stored and returned in full by GET /api/admin/settings). Password write-back needs much stronger directory permissions than a search bind, so unlike every other LDAP setting it stays config-file-only and is never exposed through the Settings API - same reasoning as ConfigWeb.JWTSecret. Both fields are optional since most installs never enable LDAP password write-back at all (Settings.LdapAllowPasswordChange defaults to off).
type ConfigLibrenms ¶
type ConfigLibrenms struct {
CommonConfig
URL string
Key string
// PersistentDevices is a newline-separated list of LibreNMS hostnames
// or display names sync never quarantines or deletes - see
// Settings.LibrenmsPersistentDevices's doc comment.
PersistentDevices string
// DelayedDeleteEnabled/DelayedDeleteDays control the LibreNMS delete
// path - see Settings.LibrenmsDelayedDeleteEnabled's doc comment.
DelayedDeleteEnabled bool
DelayedDeleteDays int
// RolesEnabled/InterfacesDisabled are newline-separated lists of
// regexes - see Settings.LibrenmsRolesEnabled's doc comment.
RolesEnabled string
InterfacesDisabled string
// SNMPVersion/SNMPCommunities are used when creating devices in
// LibreNMS - see Settings.LibrenmsSNMPVersion/LibrenmsSNMPCommunities's
// doc comments. SNMPCommunities is newline-separated, same convention
// as RolesEnabled/InterfacesDisabled.
SNMPVersion string
SNMPCommunities string
}
ConfigLibrenms is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigIcinga/ConfigDNS/ConfigOxidized: every field has a DB-backed equivalent (Settings.LibrenmsApiURL/LibrenmsApiToken/ LibrenmsPersistentDevices/LibrenmsDelayedDeleteEnabled/ LibrenmsDelayedDeleteDays/LibrenmsRolesEnabled/LibrenmsInterfacesDisabled), fetched over REST by internal/librenms.FetchRemoteConfig/RemoteClient from web.ApiLibrenmsConfig - so factum2-librenms-cli, which typically runs on a different host than the primary, doesn't need any local librenms config of its own. LibreNMS's own MySQL credentials aren't part of this struct at all - NewFactumLibrenmsClient reads those directly from LibreNMS's .env file on disk instead, since factum2-librenms-cli assumes co-location with the LibreNMS server.
type ConfigNetbox ¶
type ConfigNetbox struct {
CommonConfig
URL string
Token string
}
ConfigNetbox is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigIcinga: every field has a DB-backed equivalent (Settings.NetboxApiURL/NetboxApiToken), fetched over REST by internal/netbox.FetchRemoteConfig/RemoteClient from web.ApiNetboxConfig - so factum2-librenms-cli (which typically runs on a different host than the primary, without direct Postgres access) doesn't need its own copy of these credentials, or a direct DB connection, to build a Netbox client.
type ConfigOxidized ¶
type ConfigOxidized struct {
CommonConfig
URL string
User string
Pass string
// DestFile is oxidized's own router.db - the file
// internal/oxidized.FactumOxidizedClient.Sync writes the filtered
// device list to (name:ip:model per line).
DestFile string
// IgnoreDevices/IgnoreManufacturers/IgnoreModels/IgnorePlatforms are
// newline-separated lists (one value per line) - a device matching any
// one of them is skipped during sync.
IgnoreDevices string
IgnoreManufacturers string
IgnoreModels string
IgnorePlatforms string
}
ConfigOxidized is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigIcinga: every field has a DB-backed equivalent (Settings.OxidizedApiURL/User/Pass/DestFile/IgnoreDevices/ IgnoreManufacturers/IgnoreModels/IgnorePlatforms), fetched over REST by internal/oxidized.FetchRemoteConfig/RemoteClient from web.ApiOxidizedConfig.
type ConfigPrometheus ¶ added in v1.0.3
type ConfigPrometheus struct {
CommonConfig
DestFile string
ReloadURL string
Module string
Auth string
IgnoreDevices string
IgnoreManufacturers string
IgnoreModels string
IgnorePlatforms string
}
ConfigPrometheus is a runtime-only DTO, not part of ConfigRoot - same pattern as ConfigOxidized: every field has a DB-backed equivalent (Settings.PrometheusDestFile/ReloadURL/Module/Auth/Ignore*), fetched over REST by internal/prometheus.FetchRemoteConfig from web.ApiPrometheusConfig. factum2-prometheus typically runs on the Prometheus/snmp_exporter host, not the primary, so it has no local prometheus YAML of its own.
type ConfigRoot ¶
type ConfigRoot struct {
DB ConfigDB `yaml:"db"`
Factum ConfigFactum `yaml:"factum"`
Web ConfigWeb `yaml:"web"`
Worker ConfigWorker `yaml:"worker"`
LdapWriteback ConfigLdapWriteback `yaml:"ldap_writeback"`
Driver ConfigDriver `yaml:"driver" optional:"true"`
Storage ConfigStorage `yaml:"storage" optional:"true"`
}
Primary configuation, enough to get it up and running. most coinfig is in database
var Config *ConfigRoot
type ConfigStorage ¶ added in v1.1.1
type ConfigStorage struct {
Socket string `boa:"configonly" yaml:"socket" optional:"true"`
}
ConfigDriver is optional YAML for the SSH CLI session pool (internal/drivers). Every field is optional so existing configs keep loading. Omitted knobs and explicit 0 / "" mean compiled defaults. platforms omitted → vrp,ciscosmb; [] or [none] (or [none, ...]) turns pooling off. ConfigStorage is optional YAML for factum2-storage start (unix API socket). Listen addresses come from Settings (GET /api/storage-config). The repository directory is worker.paths.storage_root; Settings stores that key, not the path.
type ConfigWeb ¶
type ConfigWeb struct {
Bind string
JWTSecret string
// WiregasmDir is where wiregasm.js, wiregasm.wasm.gz and
// wiregasm.data.gz live (make wiregasm). Empty searches
// /usr/share/factum2/wiregasm and web/static/wiregasm, then the
// copy embedded in a release binary.
WiregasmDir string `yaml:"wiregasm_dir" boa:"configonly" optional:"true"`
}
type ConfigWorker ¶
type ConfigWorker struct {
// Roles lists what this worker instance does. "primary" runs the
// primary loop (dispatches ad hoc commands via "factum2-worker run" and
// logs everything agents report); any other entry is the name of a
// Commands entry that this instance additionally runs as an agent for
// - so one worker process can be primary AND handle one or more
// specific agent roles (e.g. ["primary", "librenms"]) at once, instead
// of being purely one or the other. Every non-"primary" role must have
// a matching Commands entry.
//
// optional:"true" because boa's required-field check would otherwise
// treat this flat []string as required (unlike map fields, which
// default to optional) for every cmd/worker subcommand, including ones
// like "run" and "show-config" that never look at it - Worker.Start
// does its own "at least one role" check instead, only when it
// actually matters.
Roles []string `boa:"configonly" yaml:"roles" optional:"true"`
// Commands lists the predefined commands this worker is able to run as
// an agent, keyed by name - Roles selects which of these (if any) this
// particular instance actually activates. An agent only ever receives
// commands it has both defined here and activated via Roles - there is
// no separate addressing by node name.
Commands map[string]ConfigWorkerCommand `boa:"configonly" yaml:"commands"`
// Paths pins executables and output files this host will accept from
// the primary. See ConfigWorkerPaths.
Paths ConfigWorkerPaths `boa:"configonly" yaml:"paths" optional:"true"`
// Listen is the bind address (e.g. ":8443") for this agent's hub
// listener (internal/worker.runHubListener), which the primary's
// RemoteManager dials into - the reverse of this agent dialing out.
// Empty (the default) disables the listener entirely.
Listen string `boa:"configonly" yaml:"listen" optional:"true"`
// Token is the shared secret this agent expects from the primary as
// "Authorization: Bearer <Token>" on the hub connection - the primary
// side of the same value lives on the matching models.WorkerNode row,
// not in any config file.
Token string `boa:"configonly" yaml:"token" optional:"true"`
// TLSCert/TLSKey are the PEM files the hub listener serves WSS with.
// Required for factum2-worker start (hub RPC carries config secrets;
// there is no ws:// fallback). optional at boa level so show-config
// and run do not force them.
TLSCert string `boa:"configonly" yaml:"tls_cert" optional:"true"`
TLSKey string `boa:"configonly" yaml:"tls_key" optional:"true"`
// APISocket is the unix HTTP listener for hub RPC. Empty uses
// DefaultHubSocket / FACTUM_WORKER_API_SOCKET; "none"/"0" is invalid
// for factum2-worker start (fail closed). Not a route on worker.listen.
APISocket string `boa:"configonly" yaml:"api_socket" optional:"true"`
// RadiusState is the on-disk copy of the RADIUS policy, including
// directory and NAS secrets. Empty uses /var/lib/factum2/radius/cache.json.
// The worker keeps answering from this file while factum2 is down.
RadiusState string `boa:"configonly" yaml:"radius_state" optional:"true"`
}
type ConfigWorkerCommand ¶
type ConfigWorkerCommand struct {
Cmd string `boa:"configonly" yaml:"cmd"`
Args []string `boa:"configonly" yaml:"args"`
AllowArgs []string `boa:"configonly" yaml:"allow_args" optional:"true"`
}
ConfigWorkerCommand is one predefined command a worker agent is allowed to run. Agents only ever execute commands looked up by name from this map. Args are the operator's argv. AllowArgs lists extra tokens the hub may append: an exact token ("--job", "copy") or a flag that takes the next token as its value ("--path=*"). Empty AllowArgs rejects every wire argument.
type ConfigWorkerPaths ¶ added in v1.2.0
type ConfigWorkerPaths struct {
LegoBin string `boa:"configonly" yaml:"lego_bin" optional:"true"`
LegoYaml string `boa:"configonly" yaml:"lego_yaml" optional:"true"`
LegoEnv string `boa:"configonly" yaml:"lego_env" optional:"true"`
LegoStorage string `boa:"configonly" yaml:"lego_storage" optional:"true"`
DNSDestFile string `boa:"configonly" yaml:"dns_dest_file" optional:"true"`
DNSZonesFile string `boa:"configonly" yaml:"dns_zones_file" optional:"true"`
DNSPrefixesFile string `boa:"configonly" yaml:"dns_prefixes_file" optional:"true"`
OxidizedDestFile string `boa:"configonly" yaml:"oxidized_dest_file" optional:"true"`
PrometheusDestFile string `boa:"configonly" yaml:"prometheus_dest_file" optional:"true"`
IcingaHostsFile string `boa:"configonly" yaml:"icinga_hosts_file" optional:"true"`
IcingaUsersFile string `boa:"configonly" yaml:"icinga_users_file" optional:"true"`
IcingaCertsFile string `boa:"configonly" yaml:"icinga_certs_file" optional:"true"`
IcingaInterfacesFile string `boa:"configonly" yaml:"icinga_interfaces_file" optional:"true"`
StorageRoot string `boa:"configonly" yaml:"storage_root" optional:"true"`
// IcingaCommandPipe and IcingaInterfaceState are local to this worker.
// They are not worker.paths keys: a destination field must not be able
// to name the command pipe, or sync could overwrite it.
IcingaCommandPipe string `boa:"configonly" yaml:"icinga_command_pipe" optional:"true"`
IcingaInterfaceState string `boa:"configonly" yaml:"icinga_interface_state" optional:"true"`
}
ConfigWorkerPaths maps a destination key to a file or binary on this host. Admin → Destinations stores the key (for example icinga_hosts_file). The path is only here. ResolvePinnedKey refuses a filesystem path sent by the primary.