Documentation
¶
Index ¶
- Constants
- Variables
- func AutoMigrateAll(db *gorm.DB) error
- func CategoryFromServiceID(serviceID string) string
- func IsOpticalKind(kind string) bool
- func NetboxModeToSwitchportMode(mode string) string
- func Slugify(s string) string
- func SwitchportModeToNetboxMode(mode string) any
- type Address
- type AddressCreateDTO
- type Agreement
- type AgreementQoS
- type CLIContext
- type CertAccount
- type CertAccountDTO
- type CertChallenge
- type CertChallengeDTO
- type Certificate
- type CertificateDTO
- type CertificateDomain
- type ConfigAssignment
- type ConfigAssignmentDTO
- type ConfigCLIFeature
- type ConfigCLIFeatureDTO
- type ConfigMacro
- type ConfigMacroDTO
- type ConfigScope
- type ConfigScopeDTO
- type ConfigScopePayload
- type ConfigVariableDef
- type ConfigVariableDefDTO
- type Connection
- type ConnectionViewLayout
- type ConnectionWriteDTO
- type Contact
- type ContactDTO
- type Control
- type Customer
- type CustomerContact
- type CustomerDTO
- type Device
- type DeviceCreateDTO
- type DevicePlacement
- type DeviceSyncAuth
- type DeviceSyncAuthDTO
- type DeviceType
- type DeviceTypeDTO
- type DnsDNSSECPolicy
- type DnsDNSSECPolicyDTO
- type DnsSOATemplate
- type DnsSOATemplateDTO
- type DnsTemplate
- type DnsTemplateDTO
- type DnsTemplateNameserver
- type DnsZone
- type DnsZoneDTO
- type DnsZoneRecord
- type DnsZoneRecordDTO
- type EnumChoice
- type FactumModel
- type FieldSchema
- type FloorPlan
- type FloorPlanAnnotation
- type FloorPlanRack
- type Interface
- type InterfaceCreateDTO
- type InterfaceServiceRef
- type InterfaceTemplate
- type InterfaceTemplateDTO
- type InterfaceType
- type InterfaceTypeDTO
- type IpamNamespace
- type IpamNamespaceDTO
- type IpamNamespacePrefix
- type IpamNamespacePrefixDTO
- type IpamPrefix
- type IpamPrefixDTO
- type IpamVRF
- type IpamVRFIDTO
- type Job
- type JobSchedule
- type JobScheduleDTO
- type JobTask
- type JobTaskEvent
- type LdapRoleMapping
- type LdapRoleMappingDTO
- type LibrenmsPendingDelete
- type Link
- type LinkDTO
- type LogEntry
- type MaintenanceNotification
- type MaintenanceResource
- type MaintenanceWindow
- type Manufacturer
- type ManufacturerDTO
- type MoveScopeRequest
- type OpticalKindMap
- type OpticalKindMapDTO
- type OpticalPort
- type OpticalXConnect
- type PasswordResetToken
- type Platform
- type PlatformDTO
- type Product
- type Rack
- type Role
- type RoleDTO
- type Service
- type ServiceConnectionType
- type ServiceConnectionTypeDTO
- type ServiceDTO
- type ServiceEndpoint
- type ServiceEndpointDTO
- type ServiceHop
- type ServiceInterfacesSpec
- type ServicePath
- type ServiceType
- type ServiceTypeDTO
- type Settings
- type Site
- type SiteDTO
- type Tag
- type User
- type UserDTO
- type WorkerNode
- type WorkerNodeDTO
Constants ¶
const ( CertChallengeKindDNS01 = "dns-01" CertProviderRFC2136 = "rfc2136" )
const ( ConfigScopeKindFolder = "folder" ConfigScopeKindSite = "site" ConfigScopeKindLocation = "location" ConfigScopeKindDevice = "device" ConfigScopeKindInterface = "interface" ConfigScopeKindParameter = "parameter" ConfigScopeKindCLI = "cli" ConfigScopeKindService = "service" ConfigScopeKindServiceEndpoint = "service_endpoint" ConfigScopeKindResource = "resource" // ConfigScopeKindServiceRef is virtual: ScopeTree injects it, it is not stored. ConfigScopeKindServiceRef = "service_ref" ConfigRootName = "global" ConfigCatalogName = "_catalog" ConfigCatalogCLIName = "cli" ConfigServicesFolderName = "_services" ConfigParametersChildName = "parameters" VarTypeString = "string" VarTypeInt = "int" VarTypeBool = "bool" VarTypeEnum = "enum" VarTypeIP = "ip" VarTypePrefix = "prefix" VarTypeVLAN = "vlan" VarTypeInterfaceRef = "interface_ref" VarTypeSecret = "secret" // List is a JSON array. Type entries with constraints.items // ("ip" or {"type":"int","min":1}); min/max are length. VarTypeList = "list" // Map is a JSON object (hash/dictionary). Type keys and values with // constraints.keys and constraints.values; min/max are size. VarTypeMap = "map" PayloadKindCLI = "cli" PayloadKindNETCONF = "netconf" PayloadKindRESTCONF = "restconf" // SyncSource* is which parsed DeviceConfig collection device-sync // reads for a service type. Empty means device-sync ignores the type. SyncSourceELINE = "eline" SyncSourceELAN = "elan" SyncSourceL3VPN = "l3vpn" // NetboxType* is the NetBox object kind device-sync upserts for a // SyncSource. L2VPN sources use the L2VPN type slug; L3VPN uses VRF. NetboxTypeEVPL = "evpl" NetboxTypeVPLS = "vpls" NetboxTypeVRF = "vrf" )
const ( SchemaFieldBandwidthMbps = "bandwidth_mbps" SchemaFieldMaxMacAddresses = "max_mac_addresses" )
Well-known ServiceType.Schema field names that are also copied onto dedicated Service columns so list views and older API clients can read them without parsing Fields.
const ( FieldTypeString = VarTypeString FieldTypeInt = VarTypeInt FieldTypeBool = VarTypeBool FieldTypeEnum = VarTypeEnum FieldTypeVLAN = VarTypeVLAN FieldTypeMAC = "mac" FieldTypeSNPA = "snpa" // alias of mac; stored as mac FieldTypeIPv4 = "ipv4" FieldTypeIPv6 = "ipv6" FieldTypeIP = VarTypeIP FieldTypeIPv4Prefix = "ipv4_prefix" FieldTypeIPv6Prefix = "ipv6_prefix" FieldTypePrefix = VarTypePrefix FieldTypeServiceID = "service_id" FieldTypeList = VarTypeList )
const ( DCIMSourceFactum = "factum" DCIMSourceNetbox = "netbox" RackNumberingAscending = "ascending" RackNumberingDescending = "descending" DeviceFaceFront = "front" DeviceFaceRear = "rear" FloorAnnotationLabel = "label" FloorAnnotationAisle = "aisle" FloorAnnotationZone = "zone" )
const ( SiteSourceFactum = "factum" SiteSourceNetbox = "netbox" // SiteNetboxKind* is the NetBox object a synced row came from. // Factum-created sites leave this empty. Region/site/location IDs // occupy separate NetBox sequences, so uniqueness is (kind, id). SiteNetboxKindRegion = "region" SiteNetboxKindSite = "site" SiteNetboxKindLocation = "location" )
const ( DnsZoneTypeForward = "forward" DnsZoneTypeReverse4 = "reverse4" DnsZoneTypeReverse6 = "reverse6" )
const ( VRFSourceFactum = "factum" VRFSourceNetbox = "netbox" )
const ( OpticalKindNone = "" OpticalKindROADM = "roadm" OpticalKindWDMShelf = "wdm_shelf" OpticalKindILA = "ila" OpticalKindPassive = "passive" )
Optical chassis kinds. Transponder vs muxponder is not a device kind — it is derived from tributary xconnect cardinality on a line port.
const ( PortTXPClient = "txp_client" PortTXPLine = "txp_line" PortROADMAddDrop = "roadm_adddrop" PortROADMDegree = "roadm_degree" PortFiber = "fiber_port" )
Optical port roles.
const ( XCTributary = "tributary" XCAddDrop = "roadm_adddrop" XCExpress = "roadm_express" XCPassthrough = "passthrough" // XCSourceOpenROADM marks xconnects written by optical inventory sync. // Operator-created rows keep Source empty; sync only deletes its own. XCSourceOpenROADM = "openroadm" )
Optical xconnect kinds.
const ( HopInterface = "interface" HopDevice = "device" HopConnection = "connection" HopXConnect = "xconnect" PathNone = "none" PathComplete = "complete" PathIncomplete = "incomplete" PathStale = "stale" PathConflict = "conflict" TraceModeWDM = "wdm" TraceModeFiber = "fiber" StartCustomerPort = "customer_port" StartTXPClient = "txp_client" StartFiberPort = "fiber_port" )
Service path / hop kinds and statuses.
const ( MaintResourceConnection = "connection" MaintResourceDevice = "device" MaintResourceInterface = "interface" MaintResourceWavelength = "wavelength" MaintResourceFiber = "fiber" MaintDraft = "draft" MaintPlanned = "planned" MaintNotified = "notified" MaintInProgress = "in_progress" MaintCompleted = "completed" MaintCancelled = "cancelled" MaintNotifyPending = "pending" MaintNotifySent = "sent" MaintNotifyFailed = "failed" MaintNotifySkipped = "skipped" )
Maintenance constants.
const EndpointRoleInterface = "interface"
EndpointRoleInterface is the sentinel stored in ServiceEndpoint.Role.
const TicksPerU = 2
TicksPerU is the internal occupancy resolution: two ticks equal 1U.
Variables ¶
var AllowedOpticalKinds = map[string]bool{ OpticalKindROADM: true, OpticalKindWDMShelf: true, OpticalKindILA: true, OpticalKindPassive: true, }
AllowedOpticalKinds is the stored set (aliases are normalized first).
var AllowedOpticalPortRoles = map[string]bool{ PortTXPClient: true, PortTXPLine: true, PortROADMAddDrop: true, PortROADMDegree: true, PortFiber: true, }
AllowedOpticalPortRoles is the stored set for OpticalPort.Role / the NetBox optical_role custom field on dcim.interface.
var OpticalKindAliases = map[string]string{ "transponder": OpticalKindWDMShelf, "muxponder": OpticalKindWDMShelf, }
OpticalKindAliases maps legacy / operator-facing names onto stored kinds.
var OpticalServiceCategories = map[string]bool{ "VL": true, "VI": true, "LF": true, "LI": true, }
OpticalServiceCategories are the prefixes that participate in fiber / wavelength impact. CN/CI are excluded.
Functions ¶
func AutoMigrateAll ¶ added in v1.0.6
AutoMigrateAll creates the application schema via GORM. Used only by in-memory SQLite tests (util.MigrateDatabase's non-postgres branch). Production schema is internal/dbmigrate/sql, not this list.
func CategoryFromServiceID ¶
CategoryFromServiceID derives CN/CI/VL/VI/LF/LI from ServiceID's prefix. Returns "" for free-text / Lime IDs that don't match the shape.
func IsOpticalKind ¶
func NetboxModeToSwitchportMode ¶
NetboxModeToSwitchportMode is the inverse of SwitchportModeToNetboxMode, used when syncing Netbox's interface "mode" into factum's own Interface.SwitchportMode (internal/netbox's syncInterfaces). Netbox's "tagged-all" (an untagged VLAN plus every VLAN in the assigned group, tagged) has no equivalent in this codebase's switchport vocabulary, so it maps to "trunk" like "tagged" does - both write "switchport trunk allowed vlan ..." in this codebase's driver-write direction.
func SwitchportModeToNetboxMode ¶
SwitchportModeToNetboxMode maps a driver/factum SwitchportMode value ("access", "trunk", "dot1q-tunnel") to Netbox's interface "mode" field ("access", "tagged", "q-in-q") - used when pushing a device-read switchport config to Netbox (internal/device-sync, and the interfaces/ vlans web endpoint). "" (not a switchport) clears Netbox's mode.
Types ¶
type Address ¶
type Address struct {
FactumModel
AddressID uint `json:"address_id"`
InterfaceID uint `json:"interface_id" gorm:"index"`
NetboxID uint `json:"netbox_id"`
Address string `json:"address" gorm:"type:varchar(80)"`
// PrefixID is the most-specific allocated ipam_prefixes row that
// contains this address. Prefix length and VRF are read from that
// row rather than parsed from Address / the denormalized VRF name.
PrefixID *uint `json:"prefix_id" gorm:"index"`
// DNSName is Netbox ipam.IPAddress.dns_name, validated at Netbox sync.
DNSName string `json:"dns_name" gorm:"type:varchar(255)"`
// VRF is the name of the VRF this address belongs to, "" for
// global/default VRF - mirrors netboxtool.NBAddress.VRF. Kept in
// sync with the related prefix's VRF when PrefixID is set.
VRF string `json:"vrf" gorm:"type:varchar(255)"`
// Role is Netbox's native ipam.IPAddress.role (e.g. "anycast"), not a
// custom field - hence no Cf prefix, unlike Interface.CfRole.
Role string `json:"role" gorm:"type:varchar(255)"`
}
type AddressCreateDTO ¶ added in v1.1.0
type AddressCreateDTO struct {
InterfaceID uint `json:"interface_id"`
Address string `json:"address"`
DNSName string `json:"dns_name"`
VRF string `json:"vrf"`
Role string `json:"role"`
PrefixID *uint `json:"prefix_id"`
// Management, when set, assigns or clears this address as the device's
// primary IPv4 or IPv6 (Device.PrimaryIPv4ID / PrimaryIPv6ID). nil
// leaves the existing primary assignment unchanged (aside from
// keeping the denormalized address string in sync).
Management *bool `json:"management"`
}
AddressCreateDTO is the writable subset of Address. NetboxID is never accepted from the client — Factum-created rows stay NetboxID=0.
type Agreement ¶
type Agreement struct {
FactumModel
LastSync uint `json:"-"`
Monthly_fee int `json:"montly_fee"`
Onetime_fee int `json:"onetime_fee"`
QOS *AgreementQoS `gorm:"-" json:"qos"`
}
-------
type AgreementQoS ¶
type AgreementQoS struct {
FactumModel
LastSync uint `json:"-"`
Key string `json:"key"`
Text string `json:"text"`
}
type CLIContext ¶ added in v1.0.5
type CLIContext struct {
Pattern string `json:"pattern"`
Enter string `json:"enter"`
Exit string `json:"exit"`
Captures map[string]string `json:"captures,omitempty"`
}
CLIContext is the optional CLI mode wrapping for a kind=cli object.
type CertAccount ¶ added in v1.1.0
type CertAccount struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Email string `json:"email" gorm:"type:varchar(255)"`
Server string `json:"server" gorm:"type:varchar(512)"`
KeyType string `json:"key_type" gorm:"type:varchar(32)"`
AcceptsTermsOfService bool `json:"accepts_terms_of_service"`
EABKID string `json:"eab_kid" gorm:"column:eab_kid;type:varchar(255)"`
EABHMACKey string `json:"eab_hmac_key" gorm:"column:eab_hmac_key;type:text"`
}
CertAccount is a lego ACME account (email, server, key type).
func (CertAccount) TableName ¶ added in v1.1.0
func (CertAccount) TableName() string
type CertAccountDTO ¶ added in v1.1.0
type CertChallenge ¶ added in v1.1.0
type CertChallenge struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Kind string `json:"kind" gorm:"type:varchar(32);not null;default:'dns-01'"`
Provider string `json:"provider" gorm:"type:varchar(64);not null;default:'rfc2136'"`
DNSTimeout int `json:"dns_timeout"`
Resolvers string `json:"resolvers" gorm:"type:text"`
DisableAuthNS bool `json:"disable_authoritative_nameservers" gorm:"column:disable_authoritative_nameservers"`
DisableRecursiveNS bool `json:"disable_recursive_nameservers" gorm:"column:disable_recursive_nameservers"`
PropagationWait string `json:"propagation_wait" gorm:"type:varchar(32)"`
RFC2136Nameserver string `json:"rfc2136_nameserver" gorm:"type:varchar(255)"`
RFC2136TSIGAlgo string `json:"rfc2136_tsig_algorithm" gorm:"column:rfc2136_tsig_algorithm;type:varchar(128)"`
RFC2136TSIGKey string `json:"rfc2136_tsig_key" gorm:"type:varchar(255)"`
RFC2136TSIGSecret string `json:"rfc2136_tsig_secret" gorm:"type:text"`
RFC2136TSIGFile string `json:"rfc2136_tsig_file" gorm:"type:varchar(512)"`
RFC2136TTL int `json:"rfc2136_ttl"`
RFC2136PropTimeout string `json:"rfc2136_propagation_timeout" gorm:"column:rfc2136_propagation_timeout;type:varchar(32)"`
RFC2136PollInterval string `json:"rfc2136_polling_interval" gorm:"column:rfc2136_polling_interval;type:varchar(32)"`
// ExtraEnv is KEY=value lines appended to the challenge dotenv.
ExtraEnv string `json:"extra_env" gorm:"type:text"`
}
CertChallenge is a named DNS-01 solver, currently RFC2136 (dynamic update).
func (CertChallenge) TableName ¶ added in v1.1.0
func (CertChallenge) TableName() string
type CertChallengeDTO ¶ added in v1.1.0
type CertChallengeDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Kind string `json:"kind"`
Provider string `json:"provider"`
DNSTimeout int `json:"dns_timeout"`
Resolvers string `json:"resolvers"`
DisableAuthNS bool `json:"disable_authoritative_nameservers"`
DisableRecursiveNS bool `json:"disable_recursive_nameservers"`
PropagationWait string `json:"propagation_wait"`
RFC2136Nameserver string `json:"rfc2136_nameserver"`
RFC2136TSIGAlgo string `json:"rfc2136_tsig_algorithm"`
RFC2136TSIGKey string `json:"rfc2136_tsig_key"`
RFC2136TSIGSecret string `json:"rfc2136_tsig_secret"`
RFC2136TSIGFile string `json:"rfc2136_tsig_file"`
RFC2136TTL int `json:"rfc2136_ttl"`
RFC2136PropTimeout string `json:"rfc2136_propagation_timeout"`
RFC2136PollInterval string `json:"rfc2136_polling_interval"`
ExtraEnv string `json:"extra_env"`
}
type Certificate ¶ added in v1.1.0
type Certificate struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
AccountID uint `json:"account_id"`
Account CertAccount `json:"account,omitempty" gorm:"constraint:OnUpdate:CASCADE,OnDelete:RESTRICT;"`
ChallengeID uint `json:"challenge_id"`
Challenge CertChallenge `json:"challenge,omitempty" gorm:"constraint:OnUpdate:CASCADE,OnDelete:RESTRICT;"`
KeyType string `json:"key_type" gorm:"type:varchar(32)"`
EnableCommonName *bool `json:"enable_common_name"`
// Host is the IPv4/IPv6/hostname Icinga connects to when checking
// this certificate. Empty skips Icinga cert checks for this cert.
Host string `json:"host" gorm:"type:varchar(255)"`
Domains []CertificateDomain `json:"domains" gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
Certificate is one lego certificate: name, domains, account, challenge. KeyType and EnableCommonName nil/empty inherit Settings.CertsDefault*.
func (Certificate) TableName ¶ added in v1.1.0
func (Certificate) TableName() string
type CertificateDTO ¶ added in v1.1.0
type CertificateDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
AccountID uint `json:"account_id"`
Account string `json:"account"`
ChallengeID uint `json:"challenge_id"`
Challenge string `json:"challenge"`
KeyType string `json:"key_type"`
EnableCommonName *bool `json:"enable_common_name"`
Host string `json:"host"`
Domains []string `json:"domains"`
}
type CertificateDomain ¶ added in v1.1.0
type CertificateDomain struct {
ID uint `json:"id" gorm:"primaryKey"`
CertificateID uint `json:"certificate_id" gorm:"not null;uniqueIndex:idx_cert_domain_rank"`
Rank uint `json:"rank" gorm:"not null;uniqueIndex:idx_cert_domain_rank"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
}
func (CertificateDomain) TableName ¶ added in v1.1.0
func (CertificateDomain) TableName() string
type ConfigAssignment ¶ added in v1.0.2
type ConfigAssignment struct {
FactumModel
VariableDefID uint `json:"variable_def_id" gorm:"uniqueIndex:idx_cfg_assign_var_scope;not null"`
ScopeID uint `json:"scope_id" gorm:"uniqueIndex:idx_cfg_assign_var_scope;not null"`
Value json.RawMessage `json:"value" gorm:"serializer:json"`
}
ConfigAssignment binds a variable def to a value at one scope.
func (ConfigAssignment) TableName ¶ added in v1.0.2
func (ConfigAssignment) TableName() string
type ConfigAssignmentDTO ¶ added in v1.0.2
type ConfigAssignmentDTO struct {
ID uint `json:"id"`
VariableDefID uint `json:"variable_def_id"`
ScopeID uint `json:"scope_id"`
Value json.RawMessage `json:"value"`
}
type ConfigCLIFeature ¶ added in v1.0.5
type ConfigCLIFeature struct {
FactumModel
ScopeID uint `json:"scope_id" gorm:"uniqueIndex:idx_cfg_feat_scope_name;not null"`
Name string `json:"name" gorm:"uniqueIndex:idx_cfg_feat_scope_name;not null;type:varchar(128)"`
SortOrder int `json:"sort_order"`
AddCommands string `json:"add_commands" gorm:"type:text"`
UpdateCommands string `json:"update_commands" gorm:"type:text"`
RemoveCommands string `json:"remove_commands" gorm:"type:text"`
RemoveAtRoot bool `json:"remove_at_root"`
}
ConfigCLIFeature is one ordered command-blob set on a kind=cli scope.
func (ConfigCLIFeature) TableName ¶ added in v1.0.5
func (ConfigCLIFeature) TableName() string
type ConfigCLIFeatureDTO ¶ added in v1.0.5
type ConfigCLIFeatureDTO struct {
ID uint `json:"id"`
ScopeID uint `json:"scope_id"`
Name string `json:"name"`
SortOrder int `json:"sort_order"`
AddCommands string `json:"add_commands"`
UpdateCommands string `json:"update_commands"`
RemoveCommands string `json:"remove_commands"`
RemoveAtRoot bool `json:"remove_at_root"`
}
type ConfigMacro ¶ added in v1.0.2
type ConfigMacro struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Body string `json:"body" gorm:"type:text"`
}
ConfigMacro is a named snippet templates can {{include}}.
func (ConfigMacro) TableName ¶ added in v1.0.2
func (ConfigMacro) TableName() string
type ConfigMacroDTO ¶ added in v1.0.2
type ConfigScope ¶ added in v1.0.2
type ConfigScope struct {
FactumModel
ParentID *uint `json:"parent_id"`
Name string `json:"name" gorm:"not null;type:varchar(255)"`
Kind string `json:"kind" gorm:"not null;type:varchar(32)"`
SiteID *uint `json:"site_id" gorm:"index"`
DeviceID *uint `json:"device_id" gorm:"index"`
InterfaceID *uint `json:"interface_id" gorm:"index"`
ServiceID *uint `json:"service_id" gorm:"index"`
ServiceTypeID *uint `json:"service_type_id" gorm:"index"`
Platform string `json:"platform" gorm:"type:varchar(64)"`
PayloadKind string `json:"payload_kind" gorm:"type:varchar(32)"`
Enabled bool `json:"enabled" gorm:"not null;default:true"`
SortOrder int `json:"sort_order"`
Payload ConfigScopePayload `json:"payload" gorm:"serializer:json"`
SeedChecksum string `json:"-" gorm:"type:varchar(64)"`
}
ConfigScope is one node in an arbitrary configuration hierarchy.
func (ConfigScope) TableName ¶ added in v1.0.2
func (ConfigScope) TableName() string
type ConfigScopeDTO ¶ added in v1.0.2
type ConfigScopeDTO struct {
ID uint `json:"id"`
ParentID *uint `json:"parent_id"`
Name *string `json:"name"`
Kind *string `json:"kind"`
SiteID *uint `json:"site_id"`
DeviceID *uint `json:"device_id"`
InterfaceID *uint `json:"interface_id"`
ServiceID *uint `json:"service_id"`
ServiceTypeID *uint `json:"service_type_id"`
Platform *string `json:"platform"`
PayloadKind *string `json:"payload_kind"`
Enabled *bool `json:"enabled"`
SortOrder *int `json:"sort_order"`
Payload *ConfigScopePayload `json:"payload"`
// Attach creates a new CN/CI inventory row plus a canonical service
// node with zero endpoints. Mutually exclusive with ServiceID (attach existing).
Attach *ServiceDTO `json:"attach,omitempty"`
}
type ConfigScopePayload ¶ added in v1.0.5
type ConfigScopePayload struct {
Description string `json:"description,omitempty"`
Platforms []string `json:"platforms,omitempty"`
Context *CLIContext `json:"context,omitempty"`
Role string `json:"role,omitempty"`
Fields map[string]any `json:"fields,omitempty"`
// CIDRs is the prefix pool for kind=resource (canonical Masked strings).
CIDRs []string `json:"cidrs,omitempty"`
}
ConfigScopePayload is kind-specific data stored as JSON on ConfigScope.
type ConfigVariableDef ¶ added in v1.0.2
type ConfigVariableDef struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Type string `json:"type" gorm:"not null;type:varchar(32)"`
Description string `json:"description" gorm:"type:varchar(255)"`
DefaultValue json.RawMessage `json:"default_value" gorm:"serializer:json"`
Constraints json.RawMessage `json:"constraints" gorm:"serializer:json"`
Secret bool `json:"secret"`
Required bool `json:"required"`
Platforms json.RawMessage `json:"platforms" gorm:"serializer:json"`
}
ConfigVariableDef is a typed variable that can be assigned on any scope.
func (ConfigVariableDef) TableName ¶ added in v1.0.2
func (ConfigVariableDef) TableName() string
type ConfigVariableDefDTO ¶ added in v1.0.2
type ConfigVariableDefDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
DefaultValue json.RawMessage `json:"default_value"`
Constraints json.RawMessage `json:"constraints"`
Secret bool `json:"secret"`
Required bool `json:"required"`
Platforms json.RawMessage `json:"platforms"`
}
type Connection ¶
type Connection struct {
FactumModel
// NetboxID uniqueness is a partial index WHERE netbox_id <> 0 so many
// Factum-local cables (netbox_id=0) can coexist.
NetboxID uint `json:"netbox_id"`
DeviceAID uint `json:"device_a_id" gorm:"index"`
InterfaceAID uint `json:"interface_a_id" gorm:"index"`
DeviceBID uint `json:"device_b_id" gorm:"index"`
InterfaceBID uint `json:"interface_b_id" gorm:"index"`
Label string `json:"label" gorm:"type:varchar(255)"`
}
Connection is a direct interface-to-interface cable. NetBox-synced rows keep NetboxID set (partial unique index WHERE netbox_id <> 0) and are read-only here. Factum-created cables keep NetboxID=0 and can be created, retimed, and deleted from the Connections page.
type ConnectionViewLayout ¶ added in v1.1.1
type ConnectionViewLayout struct {
FactumModel
UserID uint `json:"user_id" gorm:"uniqueIndex:idx_connection_view_layouts_user_scope;not null"`
Scope string `json:"scope" gorm:"uniqueIndex:idx_connection_view_layouts_user_scope;type:varchar(64);not null"`
Revision int `json:"revision"`
Nodes string `json:"nodes" gorm:"type:text"`
}
ConnectionViewLayout stores per-user graph node coordinates for a scope. Nodes JSON is keyed by local device IDs. It never stores cable inventory.
func (*ConnectionViewLayout) BeforeCreate ¶ added in v1.1.1
func (l *ConnectionViewLayout) BeforeCreate(tx *gorm.DB) error
type ConnectionWriteDTO ¶ added in v1.1.1
type ConnectionWriteDTO struct {
InterfaceAID uint `json:"interface_a_id"`
InterfaceBID uint `json:"interface_b_id"`
Label string `json:"label"`
}
ConnectionWriteDTO is the body for POST/PUT /api/dcim/connections. Device IDs are taken from the chosen interfaces, not the client.
type Contact ¶
type Contact struct {
FactumModel
LastSync uint `json:"-"`
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
NotifyMaintenance bool `json:"notify_maintenance"`
Source string `json:"source"`
SourceID string `json:"source_id"`
}
func (*Contact) BeforeCreate ¶
BeforeCreate defaults a contact's Source to "factum" when nothing set it already. The Lime person-sync (internal/lime/lime.go) always sets Source to "lime" itself before saving, so this only ever fires for contacts created through the web API - ContactDTO has no Source field for a caller to set, so without this default every manually-created contact would be indistinguishable (Source == "") from one whose sync origin just hasn't been recorded yet, instead of clearly marked as user-created.
type ContactDTO ¶
type ContactDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
NotifyMaintenance bool `json:"notify_maintenance"`
}
ContactDTO is the create/update request shape for the contact API, mirroring the fields the frontend's contact form actually edits (web/frontend/src/views/contact/ContactList.vue). Source/SourceID are deliberately excluded: they're populated by the Lime person-sync (internal/lime/lime.go), not something a caller creating or editing a contact through the web UI should be able to set - excluding them from the DTO means Update leaves a synced contact's Source/SourceID untouched (the JSON merge only overwrites fields present in the body), and Create leaves them at their zero value so BeforeCreate can default Source to "factum" for a manually-created contact. Name/email/phone on a Lime row are also ignored by ApiContactUpdate; only NotifyMaintenance is applied, since the next sync would otherwise discard those edits.
type Control ¶
type Control struct {
FactumModel
}
type Customer ¶
type Customer struct {
FactumModel
LastSync uint `json:"-"`
Name string `json:"name"`
Postaladdress1 string `json:"postal_address1"`
Postaladdress2 string `json:"postal_address2"`
Postalcity string `json:"postalcity"`
Postalzipcode string `json:"postalzipcode"`
Country string `json:"country"`
OrganizationNumber string `json:"organization_number"`
Source string `json:"source"`
SourceID string `json:"source_id"`
}
func (*Customer) BeforeCreate ¶
BeforeCreate defaults a customer's Source to "factum" when nothing set it already. The Lime sync job (internal/lime/lime.go) always sets Source to "lime" itself before saving, so this only ever fires for customers created through the web API - CustomerDTO has no Source field for a caller to set, so without this default every manually-created customer would be indistinguishable (Source == "") from one whose sync origin just hasn't been recorded yet, instead of clearly marked as user-created.
type CustomerContact ¶
type CustomerContact struct {
FactumModel
CustomerID uint `json:"customer_id" gorm:"uniqueIndex:idx_customer_contacts;not null"`
ContactID uint `json:"contact_id" gorm:"uniqueIndex:idx_customer_contacts;not null;index"`
}
CustomerContact joins a contact to a customer for maintenance notify.
type CustomerDTO ¶
type CustomerDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Postaladdress1 string `json:"postal_address1"`
Postaladdress2 string `json:"postal_address2"`
Postalcity string `json:"postalcity"`
Postalzipcode string `json:"postalzipcode"`
Country string `json:"country"`
OrganizationNumber string `json:"organization_number"`
}
CustomerDTO is the create/update request shape for the customer API, mirroring the fields the frontend's customer form actually edits (web/frontend/src/views/customer/CustomerList.vue). Source/SourceID are deliberately excluded: they're populated by the Lime sync job (internal/lime/lime.go), not something a caller creating or editing a customer through the web UI should be able to set - excluding them from the DTO means Update leaves a synced customer's Source/SourceID untouched (the JSON merge only overwrites fields present in the body), and Create leaves them at their zero value so BeforeCreate can default Source to "factum" for a manually-created customer.
type Device ¶
type Device struct {
FactumModel
// Netbox's dcim.Device and virtualization.VirtualMachine tables have
// independent ID sequences, so NetboxID is only unique per VM value,
// never globally - see internal/netbox.syncDevice.
// Local (Factum-created) devices keep NetboxID=0; uniqueness is a
// partial index WHERE netbox_id <> 0 so many local rows can coexist.
VM bool `json:"vm"`
NetboxID uint `json:"netbox_id"`
Name string `json:"name" gorm:"type:varchar(255)"`
Comments string `json:"comments" gorm:"type:varchar(255)"`
Enabled bool `json:"enabled"`
Manufacturer string `json:"manufacturer" gorm:"type:varchar(255)"`
ManufacturerID uint `json:"manufacturer_id"`
ModelName string `json:"model_name" gorm:"type:varchar(255)"`
ModelID uint `json:"model_id"`
// DeviceTypeID is the Factum catalog row (models.DeviceType), not
// NetBox's device-type id (that is ModelID). 0 if unset.
DeviceTypeID uint `json:"device_type_id" gorm:"index"`
Platform string `json:"platform" gorm:"type:varchar(255)"`
PlatformID uint `json:"platform_id"`
PrimaryIPv4 string `json:"primary_ipv4" gorm:"type:varchar(255)"`
PrimaryIPv4ID uint `json:"primary_ipv4_id"`
PrimaryIPv6 string `json:"primary_ipv6" gorm:"type:varchar(255)"`
PrimaryIPv6ID uint `json:"primary_ipv6_id"`
Role string `json:"role" gorm:"type:varchar(255)"`
RoleID uint `json:"role_id"`
Site string `json:"site" gorm:"type:varchar(255)"`
SiteID uint `json:"site_id"`
Status string `json:"status" gorm:"type:varchar(255)"`
// Latitude/Longitude are the device's own GPS coordinates if Netbox has
// them, else inherited from its site - nil if neither is set. See
// internal/netbox.syncDevice.
Latitude *float64 `json:"latitude"`
Longitude *float64 `json:"longitude"`
// OpticalKind is computed on every NetBox sync (CF then role map).
// Always assigned on the upsert struct so UpdateAll cannot zero it.
OpticalKind string `json:"optical_kind" gorm:"type:varchar(32);index"`
// OpticalKindCF is the normalized NetBox custom-field value from the
// last sync ("" if missing/invalid). Persisted so mapping CRUD can
// re-resolve without calling NetBox.
OpticalKindCF string `json:"optical_kind_cf" gorm:"type:varchar(32)"`
LibrenmsID uint `json:"librenms_id"`
// Custom fields
CfAlarmTimeperiod string `json:"cf_alarm_timeperiod" gorm:"type:varchar(255)"`
CfAlarmDestination string `json:"cf_alarm_destination" gorm:"type:varchar(255)"`
CfAlarmInterfaces bool `json:"cf_alarm_interfaces"`
CfBackupOxidized bool `json:"cf_backup_oxidized"`
CfConnectionMethod string `json:"cf_connection_method" gorm:"type:varchar(255)"`
CfLocation string `json:"cf_location" gorm:"type:varchar(255)"`
CfMonitorGrafana bool `json:"cf_monitor_grafana"`
CfMonitorIcinga bool `json:"cf_monitor_icinga"`
CfMonitorLibrenms bool `json:"cf_monitor_librenms"`
CfSource string `json:"cf_source" gorm:"type:varchar(255)"`
CfSourceID uint `json:"cf_source_id"`
Interfaces []Interface `json:"interfaces"` // gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
Tags []Tag `json:"tags"`
}
type DeviceCreateDTO ¶ added in v1.1.0
type DeviceCreateDTO struct {
Name string `json:"name"`
DeviceTypeID uint `json:"device_type_id"`
PlatformID uint `json:"platform_id"`
SiteID uint `json:"site_id"`
Site string `json:"site"`
Role string `json:"role"`
Status string `json:"status"`
// PrimaryIPv4/PrimaryIPv6 on this DTO are ignored. Primary addresses
// are assigned by referencing an interface address (management IP).
PrimaryIPv4 string `json:"primary_ipv4"`
PrimaryIPv6 string `json:"primary_ipv6"`
Comments string `json:"comments"`
Enabled *bool `json:"enabled"`
CfLocation string `json:"cf_location"`
CfMonitorIcinga *bool `json:"cf_monitor_icinga"`
CfMonitorLibrenms *bool `json:"cf_monitor_librenms"`
CfMonitorGrafana *bool `json:"cf_monitor_grafana"`
CfBackupOxidized *bool `json:"cf_backup_oxidized"`
CfAlarmInterfaces *bool `json:"cf_alarm_interfaces"`
OpticalKind string `json:"optical_kind"`
}
DeviceCreateDTO is the POST/PUT /api/device body for a Factum-local device (NetboxID stays 0, CfSource is "factum"). Manufacturer/model/platform strings on Device are copied from the catalog rows at create time. Pointer bools distinguish omitted (leave existing / default) from false.
type DevicePlacement ¶ added in v1.1.1
type DevicePlacement struct {
FactumModel
DeviceID uint `json:"device_id" gorm:"uniqueIndex;not null"`
RackID uint `json:"rack_id" gorm:"index;not null"`
OffsetTicks int `json:"offset_ticks" gorm:"column:offset_ticks"`
Face string `json:"face" gorm:"type:varchar(16)"`
Source string `json:"source" gorm:"type:varchar(32)"`
Version int `json:"version"`
// Conflict is set when imported occupancy is inconsistent with other
// imported rows. Local writers treat the occupied interval conservatively.
Conflict string `json:"conflict,omitempty" gorm:"type:varchar(64)"`
}
DevicePlacement is the one authoritative rack mount for a physical device.
func (*DevicePlacement) BeforeCreate ¶ added in v1.1.1
func (p *DevicePlacement) BeforeCreate(tx *gorm.DB) error
func (DevicePlacement) IsLocal ¶ added in v1.1.1
func (p DevicePlacement) IsLocal() bool
type DeviceSyncAuth ¶
type DeviceSyncAuth struct {
FactumModel
Name string `gorm:"uniqueIndex;not null" json:"name"`
Username string `json:"username"`
Password string `json:"-"`
}
DeviceSyncAuth is one set of device-login credentials internal/device-sync uses to connect directly to a device (SSH/NETCONF/eAPI) - distinct from Netbox's own API credentials (Settings.NetboxApi*). Name is either a device name (an override for that one device) or the literal "default", used as the fallback for any device without its own row. Admin-editable list, same shape as WorkerNode (Password is json:"-" for the same reason WorkerNode.Token is - never leak it via GetAll/GetOne).
type DeviceSyncAuthDTO ¶
type DeviceType ¶ added in v1.1.0
type DeviceType struct {
FactumModel
ManufacturerID uint `json:"manufacturer_id" gorm:"index;not null"`
Model string `json:"model" gorm:"type:varchar(255);not null"`
Slug string `json:"slug" gorm:"type:varchar(255);not null"`
PlatformID uint `json:"platform_id" gorm:"index"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
// HeightTicks is physical height in half-U ticks (2 ticks = 1U).
// nil means unknown — never treat as 1U.
HeightTicks *int `json:"height_ticks"`
FullDepth *bool `json:"full_depth"`
FrontImage string `json:"front_image" gorm:"type:varchar(512)"`
RearImage string `json:"rear_image" gorm:"type:varchar(512)"`
}
DeviceType is the shared DCIM catalog (NetBox dcim.DeviceType).
func (*DeviceType) BeforeCreate ¶ added in v1.1.0
func (d *DeviceType) BeforeCreate(tx *gorm.DB) error
func (*DeviceType) BeforeDelete ¶ added in v1.1.0
func (d *DeviceType) BeforeDelete(tx *gorm.DB) error
func (*DeviceType) BeforeUpdate ¶ added in v1.1.0
func (d *DeviceType) BeforeUpdate(tx *gorm.DB) error
type DeviceTypeDTO ¶ added in v1.1.0
type DeviceTypeDTO struct {
ID uint `json:"id"`
ManufacturerID uint `json:"manufacturer_id"`
Model string `json:"model"`
Slug string `json:"slug"`
PlatformID uint `json:"platform_id"`
HeightTicks *int `json:"height_ticks"`
FullDepth *bool `json:"full_depth"`
FrontImage string `json:"front_image"`
RearImage string `json:"rear_image"`
}
type DnsDNSSECPolicy ¶ added in v1.0.6
type DnsDNSSECPolicy struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
KSKLifetime string `json:"ksk_lifetime" gorm:"type:varchar(64)"`
KSKAlgorithm string `json:"ksk_algorithm" gorm:"type:varchar(64)"`
ZSKLifetime string `json:"zsk_lifetime" gorm:"type:varchar(64)"`
ZSKAlgorithm string `json:"zsk_algorithm" gorm:"type:varchar(64)"`
PurgeKeys string `json:"purge_keys" gorm:"type:varchar(64)"`
SignaturesValidity string `json:"signatures_validity" gorm:"type:varchar(64)"`
SignaturesValidityDNSKEY string `json:"signatures_validity_dnskey" gorm:"column:signatures_validity_dnskey;type:varchar(64)"`
SignaturesRefresh string `json:"signatures_refresh" gorm:"type:varchar(64)"`
}
DnsDNSSECPolicy is a BIND dnssec-policy (name, KSK/ZSK, signature timings). dnsmgr2 currently consumes only Name (as zone_templates.dnssec_policy); the rest is stored so the GUI can round-trip a full policy.
func (DnsDNSSECPolicy) TableName ¶ added in v1.0.6
func (DnsDNSSECPolicy) TableName() string
type DnsDNSSECPolicyDTO ¶ added in v1.0.6
type DnsDNSSECPolicyDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
KSKLifetime string `json:"ksk_lifetime"`
KSKAlgorithm string `json:"ksk_algorithm"`
ZSKLifetime string `json:"zsk_lifetime"`
ZSKAlgorithm string `json:"zsk_algorithm"`
PurgeKeys string `json:"purge_keys"`
SignaturesValidity string `json:"signatures_validity"`
SignaturesValidityDNSKEY string `json:"signatures_validity_dnskey"`
SignaturesRefresh string `json:"signatures_refresh"`
}
type DnsSOATemplate ¶ added in v1.0.6
type DnsSOATemplate struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Mname string `json:"mname" gorm:"type:varchar(255)"`
Rname string `json:"rname" gorm:"type:varchar(255)"`
Refresh uint `json:"refresh"`
Retry uint `json:"retry"`
Expire uint `json:"expire"`
TTL uint `json:"ttl"` // SOA minimum
}
DnsSOATemplate is a named SOA used by DNS templates when dnsmgr2 writes zone files. Serial is not stored — dnsmgr2 assigns YYYYMMDDnn itself.
func (DnsSOATemplate) TableName ¶ added in v1.0.6
func (DnsSOATemplate) TableName() string
type DnsSOATemplateDTO ¶ added in v1.0.6
type DnsTemplate ¶ added in v1.0.6
type DnsTemplate struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
SOATemplateID uint `json:"soa_template_id"`
SOATemplate DnsSOATemplate `json:"soa_template,omitempty" gorm:"constraint:OnUpdate:CASCADE,OnDelete:RESTRICT;"`
DefaultTTL uint `json:"default_ttl"`
DNSSECPolicyID *uint `json:"dnssec_policy_id"`
DNSSECPolicy *DnsDNSSECPolicy `json:"dnssec_policy,omitempty" gorm:"constraint:OnUpdate:CASCADE,OnDelete:RESTRICT;"`
Nameservers []DnsTemplateNameserver `json:"nameservers" gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
DnsTemplate is a zone template (dns_template in dnsmgr2): SOA, default TTL, optional DNSSEC policy, and the NS list written into every zone that uses it.
func (DnsTemplate) TableName ¶ added in v1.0.6
func (DnsTemplate) TableName() string
type DnsTemplateDTO ¶ added in v1.0.6
type DnsTemplateDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
SOATemplateID uint `json:"soa_template_id"`
SOATemplate string `json:"soa_template"`
DefaultTTL uint `json:"default_ttl"`
DNSSECPolicyID *uint `json:"dnssec_policy_id"`
DNSSECPolicy string `json:"dnssec_policy"`
Nameservers []string `json:"nameservers"`
}
type DnsTemplateNameserver ¶ added in v1.0.6
type DnsTemplateNameserver struct {
ID uint `json:"id" gorm:"primaryKey"`
DnsTemplateID uint `json:"dns_template_id" gorm:"not null;uniqueIndex:idx_dns_template_ns_rank"`
Rank uint `json:"rank" gorm:"not null;uniqueIndex:idx_dns_template_ns_rank"`
Hostname string `json:"hostname" gorm:"type:varchar(255);not null"`
}
DnsTemplateNameserver is one NS hostname on a DNS template, in display order.
func (DnsTemplateNameserver) TableName ¶ added in v1.0.6
func (DnsTemplateNameserver) TableName() string
type DnsZone ¶ added in v1.0.6
type DnsZone struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Type string `json:"type" gorm:"type:varchar(16);not null;default:'forward'"`
DnsTemplateID uint `json:"dns_template_id"`
DnsTemplate DnsTemplate `json:"dns_template,omitempty" gorm:"constraint:OnUpdate:CASCADE,OnDelete:RESTRICT;"`
Comment string `json:"comment" gorm:"type:text"`
Records []DnsZoneRecord `json:"records" gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
DnsZone is one managed zone. Type is forward / reverse4 / reverse6, matching dnsmgr2. Records are extra RRs; SOA and apex NS come from DnsTemplate.
type DnsZoneDTO ¶ added in v1.0.6
type DnsZoneRecord ¶ added in v1.0.6
type DnsZoneRecord struct {
ID uint `json:"id" gorm:"primaryKey"`
DnsZoneID uint `json:"dns_zone_id" gorm:"not null;uniqueIndex:idx_dns_zone_record_rank"`
Rank uint `json:"rank" gorm:"not null;uniqueIndex:idx_dns_zone_record_rank"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
TTL *uint `json:"ttl"`
Type string `json:"type" gorm:"column:record_type;type:varchar(16);not null"`
Value string `json:"value" gorm:"type:text;not null"`
Description string `json:"description" gorm:"type:text"`
MAC string `json:"mac" gorm:"type:varchar(32)"`
}
DnsZoneRecord is one DNS resource record in a zone. Rank is the display / records-file order (0-based). TTL is seconds; nil means unspecified (use the template default). A stored 0 is treated as unspecified — DNS TTL 0 is not used. Description is an optional operator note; it is not part of the DNS RDATA. MAC is a DHCP host reservation (A/AAAA only). It is its own column, not a comment; factum2-dns writes it as a `mac` field on the JSON A/AAAA record so dnsmgr2 can emit a Kea reservation.
func (DnsZoneRecord) TableName ¶ added in v1.0.6
func (DnsZoneRecord) TableName() string
type DnsZoneRecordDTO ¶ added in v1.0.6
type EnumChoice ¶ added in v1.1.0
type FactumModel ¶
type FieldSchema ¶ added in v1.0.2
type FieldSchema struct {
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required"`
Description string `json:"description"`
// Inclusive bounds for int/vlan values and list length.
// VLAN defaults unset Min/Max to 1 and 4094 and clamps custom bounds to that range; int is unbounded.
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
Unit string `json:"unit,omitempty"`
BoolTrueLabel string `json:"bool_true_label,omitempty"`
BoolFalseLabel string `json:"bool_false_label,omitempty"`
Enum []EnumChoice `json:"enum,omitempty"`
Items *FieldSchema `json:"items,omitempty"`
// Resource names a kind=resource pool. Prefix-typed nodes only, including items.
Resource string `json:"resource,omitempty"`
// Default is used when the field is empty on a service or endpoint.
// Named fields only; list items cannot set default.
Default json.RawMessage `json:"default,omitempty"`
}
FieldSchema is one typed field on a service type or interfaces spec. Nested Items is the same shape; list items are nameless.
type FloorPlan ¶ added in v1.1.1
type FloorPlan struct {
FactumModel
SiteID uint `json:"site_id" gorm:"index;not null"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
WidthMM int `json:"width_mm" gorm:"column:width_mm"`
HeightMM int `json:"height_mm" gorm:"column:height_mm"`
GridMM int `json:"grid_mm" gorm:"column:grid_mm"`
Revision int `json:"revision"`
}
FloorPlan is a Factum drawing of a room. SiteID is a local sites.id.
type FloorPlanAnnotation ¶ added in v1.1.1
type FloorPlanAnnotation struct {
FactumModel
FloorPlanID uint `json:"floor_plan_id" gorm:"index;not null"`
Kind string `json:"kind" gorm:"type:varchar(32)"`
Text string `json:"text" gorm:"type:varchar(255)"`
XMM int `json:"x_mm" gorm:"column:x_mm"`
YMM int `json:"y_mm" gorm:"column:y_mm"`
WidthMM int `json:"width_mm" gorm:"column:width_mm"`
HeightMM int `json:"height_mm" gorm:"column:height_mm"`
Rotation int `json:"rotation"`
}
FloorPlanAnnotation is a label, aisle or zone on a floor plan.
type FloorPlanRack ¶ added in v1.1.1
type FloorPlanRack struct {
FactumModel
FloorPlanID uint `json:"floor_plan_id" gorm:"uniqueIndex:idx_floor_plan_racks_plan_rack;not null"`
RackID uint `json:"rack_id" gorm:"uniqueIndex:idx_floor_plan_racks_plan_rack;index;not null"`
XMM int `json:"x_mm" gorm:"column:x_mm"`
YMM int `json:"y_mm" gorm:"column:y_mm"`
Rotation int `json:"rotation"`
}
FloorPlanRack places a rack on a floor plan. X/Y are mm from the plan origin.
type Interface ¶
type Interface struct {
FactumModel
DeviceID uint `json:"device_id" gorm:"index"`
// NetboxID uniqueness is a partial index WHERE netbox_id <> 0 so many
// Factum-local interfaces (netbox_id=0) can coexist on one device.
NetboxID uint `json:"netbox_id"`
Name string `json:"name" gorm:"type:varchar(255)"`
Description string `json:"description" gorm:"type:varchar(255)"`
Enabled bool `json:"enabled"`
VRF string `json:"vrf" gorm:"type:varchar(255)"`
CfRole string `json:"cf_role" gorm:"type:varchar(255)"`
// Type is Netbox's interface type (e.g. "1000base-t") - mirrors
// netboxtool.NBInterface.Type.
Type string `json:"type" gorm:"type:varchar(255)"`
// CableID is the Netbox ID of the cable terminated on this interface,
// 0 if none - mirrors netboxtool.NBInterface.CableID.
CableID uint `json:"cable_id"`
// Label is Netbox's free-text interface label, distinct from Name -
// mirrors netboxtool.NBInterface.Label.
Label string `json:"label" gorm:"type:varchar(255)"`
// ParentID is the Netbox ID of this interface's parent interface, 0 if
// none - mirrors netboxtool.NBInterface.ParentID.
ParentID uint `json:"parent_id"`
// UntaggedVLAN/TaggedVLANs are VIDs (not Netbox IDs), mirroring
// netboxtool.NBInterface.UntaggedVLAN/TaggedVLANs. UntaggedVLAN is 0 if
// unset.
UntaggedVLAN int `json:"untagged_vlan"`
TaggedVLANs []int `json:"tagged_vlans" gorm:"serializer:json"`
// VLANNames maps VID -> Netbox VLAN name for this interface's untagged
// and tagged VLANs, copied from netboxtool.NBInterface.VLANNames on
// sync. Used by the VLAN matrix to label columns.
VLANNames map[int]string `json:"vlan_names,omitempty" gorm:"serializer:json"`
// SwitchportMode is "access", "trunk" or "dot1q-tunnel" (Q-in-Q), mirroring
// drivers.Interface.SwitchportMode - only meaningful on global-VLAN
// platforms (EOS, VRP, Cisco SMB), "" if not a switchport or unknown.
SwitchportMode string `json:"switchport_mode" gorm:"type:varchar(255)"`
LibrenmsID uint `json:"librenms_id"`
// runtime data
LineProtocolStatus string `gorm:"-"`
InterfaceStatus string `gorm:"-"`
Addresses []Address `json:"addresses"` // gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
Tags []Tag `json:"tags"`
// Services lists the factum services terminating on this interface,
// assembled by fetchDevices (web/handle_dcim.go) - not a DB relation
// on Interface itself. Terminations come from service_endpoints; when
// a per-VLAN subinterface exists, the service is attached to that
// subinterface row instead of the physical port.
Services []InterfaceServiceRef `json:"services,omitempty" gorm:"-"`
// Optical is assembled by fetchDevices — not a DB relation on Interface.
Optical *OpticalPort `json:"optical,omitempty" gorm:"-"`
}
type InterfaceCreateDTO ¶ added in v1.1.0
type InterfaceCreateDTO struct {
ID uint `json:"id"`
DeviceID uint `json:"device_id"`
Name string `json:"name"`
Type string `json:"type"`
Label string `json:"label"`
Description string `json:"description"`
VRF string `json:"vrf"`
Enabled *bool `json:"enabled"`
}
InterfaceCreateDTO is the POST/PUT /api/dcim/interfaces body for a Factum-local device interface (NetboxID stays 0).
type InterfaceServiceRef ¶
InterfaceServiceRef is the minimal service info needed to link to and label a service from an interface listing, without pulling in the whole Service record.
type InterfaceTemplate ¶ added in v1.1.0
type InterfaceTemplate struct {
FactumModel
DeviceTypeID uint `json:"device_type_id" gorm:"uniqueIndex:idx_interface_templates_type_name;not null"`
Name string `json:"name" gorm:"uniqueIndex:idx_interface_templates_type_name;type:varchar(255);not null"`
Type string `json:"type" gorm:"type:varchar(255)"`
Label string `json:"label" gorm:"type:varchar(255)"`
Description string `json:"description" gorm:"type:varchar(255)"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
}
InterfaceTemplate is a port defined on a DeviceType (NetBox dcim.InterfaceTemplate). Copied onto a device when that device is created locally, and shown under DCIM → Device types.
func (*InterfaceTemplate) BeforeCreate ¶ added in v1.1.0
func (t *InterfaceTemplate) BeforeCreate(tx *gorm.DB) error
type InterfaceTemplateDTO ¶ added in v1.1.0
type InterfaceType ¶ added in v1.1.1
type InterfaceType struct {
FactumModel
Value string `json:"value" gorm:"type:varchar(255);uniqueIndex;not null"`
Label string `json:"label" gorm:"type:varchar(255);not null"`
Source string `json:"source" gorm:"type:varchar(32)"`
SortOrder int `json:"sort_order"`
}
InterfaceType is a DCIM catalog row for NetBox interface.type choices (e.g. "1000base-t"). NetBox has no interface-types resource; full sync fills this from OPTIONS /api/dcim/interfaces/. Factum-local rows can be added in the GUI. Value is what interfaces and templates store.
func (*InterfaceType) BeforeCreate ¶ added in v1.1.1
func (t *InterfaceType) BeforeCreate(tx *gorm.DB) error
func (*InterfaceType) BeforeUpdate ¶ added in v1.1.1
func (t *InterfaceType) BeforeUpdate(tx *gorm.DB) error
type InterfaceTypeDTO ¶ added in v1.1.1
type IpamNamespace ¶
type IpamNamespace struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(255)"`
Description string `json:"description" gorm:"type:varchar(255)"`
}
IpamNamespace is one unique address space. Two namespaces may both hold 10.0.0.0/8. Created with a default VRF; allowed prefixes (pools) are added separately. The empty-name namespace is implicit: its prefixes and extra VRFs appear at the forest root so operators who do not use namespaces can allocate there directly.
func (IpamNamespace) TableName ¶
func (IpamNamespace) TableName() string
type IpamNamespaceDTO ¶
type IpamNamespacePrefix ¶
type IpamNamespacePrefix struct {
FactumModel
NamespaceID uint `json:"namespace_id" gorm:"uniqueIndex:idx_ipam_ns_pool;not null"`
Prefix string `json:"prefix" gorm:"uniqueIndex:idx_ipam_ns_pool;type:varchar(80);not null"`
Family int `json:"family"`
}
IpamNamespacePrefix is an allowed pool for a namespace. 0.0.0.0/0 and ::/0 mean any prefix of that family. Prefix is stored masked and canonical (10.1.2.3/24 → 10.1.2.0/24).
func (IpamNamespacePrefix) TableName ¶
func (IpamNamespacePrefix) TableName() string
type IpamNamespacePrefixDTO ¶
type IpamPrefix ¶
type IpamPrefix struct {
FactumModel
NamespaceID uint `json:"namespace_id" gorm:"uniqueIndex:idx_ipam_alloc_ns_pfx;not null"`
VRFID uint `json:"vrf_id" gorm:"index;not null"`
Prefix string `json:"prefix" gorm:"uniqueIndex:idx_ipam_alloc_ns_pfx;type:varchar(80);not null"`
Family int `json:"family"`
Description string `json:"description" gorm:"type:varchar(255)"`
// DhcpEnabled is the per-prefix "run a DHCP server here" checkbox.
DhcpEnabled bool `json:"dhcp_enabled"`
// DhcpRangeStart/End are the dynamic pool. Both empty is static-only.
// When set they must sit inside Prefix.
DhcpRangeStart string `json:"dhcp_range_start" gorm:"type:varchar(80)"`
DhcpRangeEnd string `json:"dhcp_range_end" gorm:"type:varchar(80)"`
// DhcpGateway empty means "first usable address in the prefix"
// (network + 1 for IPv4 /30 or shorter).
DhcpGateway string `json:"dhcp_gateway" gorm:"type:varchar(80)"`
// DhcpDnsServers is newline-separated. Empty means use the global
// default (Settings.DhcpDnsServers).
DhcpDnsServers string `json:"dhcp_dns_servers" gorm:"type:text"`
}
IpamPrefix is a CIDR allocated to exactly one VRF in a namespace. Parent/child relationships are computed from containment, not stored. DHCP fields are used when Settings.DhcpEnabled is on; turning that flag off only hides the UI — values stay on the row.
func (IpamPrefix) TableName ¶
func (IpamPrefix) TableName() string
type IpamPrefixDTO ¶
type IpamPrefixDTO struct {
ID uint `json:"id"`
NamespaceID uint `json:"namespace_id"`
VRFID uint `json:"vrf_id"`
Prefix string `json:"prefix"`
Description string `json:"description"`
DhcpEnabled bool `json:"dhcp_enabled"`
DhcpRangeStart string `json:"dhcp_range_start"`
DhcpRangeEnd string `json:"dhcp_range_end"`
DhcpGateway string `json:"dhcp_gateway"`
DhcpDnsServers string `json:"dhcp_dns_servers"`
}
type IpamVRF ¶
type IpamVRF struct {
FactumModel
NamespaceID uint `json:"namespace_id" gorm:"index;not null"`
Name string `json:"name" gorm:"not null;type:varchar(255)"`
Description string `json:"description" gorm:"type:varchar(255)"`
IsDefault bool `json:"is_default"`
// RD is the BGP route distinguisher (e.g. "65000:1").
RD string `json:"rd" gorm:"type:varchar(255)"`
// ImportRT / ExportRT are route-targets, comma-separated when there
// are several (NetBox import_targets / export_targets).
ImportRT string `json:"import_rt" gorm:"type:text"`
ExportRT string `json:"export_rt" gorm:"type:text"`
// Source is "netbox" when upserted from sync, "factum" when created
// in the UI. NetBox-synced rows are read-only.
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
}
IpamVRF is a routing domain inside a namespace. Address space is unique across VRFs of the same namespace (not classic overlapping-VRF semantics): once a prefix is allocated to one VRF, no other VRF may take it or anything that overlaps it. Extra VRF names are unique across all namespaces; each namespace still has its own default VRF (named "default"), which is created with the namespace and cannot be deleted.
type IpamVRFIDTO ¶
type Job ¶
type Job struct {
FactumModel
Type string `gorm:"index;not null;default:sync" json:"type"`
TriggeredBy string `json:"triggered_by"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
// ExpectedTasks is the total number of JobTasks this job will end up
// with, set once at creation. A sequential batch (StartJob's
// multi-target path) creates its JobTask rows one at a time as each
// target's turn comes up rather than all at once, so
// RemoteManager.resolveTask can't tell "done" from "no rows created
// yet" by counting unfinished rows alone - it also checks the finished
// row count against ExpectedTasks. Internal bookkeeping, not part of
// the REST API surface (json:"-"), like JobTask.TaskID.
ExpectedTasks int `json:"-"`
Tasks []JobTask `gorm:"foreignKey:JobID" json:"tasks,omitempty"`
}
Job is one triggered unit of work (e.g. one click of "Sync DNS", or one "Sync all"), made up of one or more JobTasks - one per target. Type lets future non-sync job kinds reuse this table without another schema change; "sync" is the only value produced today.
type JobSchedule ¶
type JobSchedule struct {
FactumModel
Name string `gorm:"not null" json:"name"`
Enabled bool `json:"enabled"`
Target string `gorm:"not null;index" json:"target"`
Cron string `gorm:"not null" json:"cron"`
// LastRunAt is when the scheduler last claimed a due run - it is
// stamped even if StartJob then fails (LastError), so a busy target
// doesn't get retried every tick.
LastRunAt *time.Time `json:"last_run_at,omitempty"`
NextRunAt *time.Time `gorm:"index" json:"next_run_at,omitempty"`
LastError string `json:"last_error,omitempty"`
CreatedBy string `json:"created_by"`
}
JobSchedule is one user-defined periodic trigger for a job, the in-app replacement for a crontab entry on the primary. Target is either one worker.IsValidJobTarget name (a single-target StartJob, same as clicking one tile on Job overview - sync targets plus "housekeeping"), or the sentinel "all" (SequencedSyncAllTargets + StartJob, same as "Sync all"; housekeeping is not included). Cron is a 5-field expression evaluated in Europe/Stockholm; NextRunAt is computed at create/update and advanced by the scheduler when a run is claimed so a restart only ever catch-up fires once, not once per missed tick.
type JobScheduleDTO ¶
type JobScheduleDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Enabled bool `json:"enabled"`
Target string `json:"target"`
Cron string `json:"cron"`
}
JobScheduleDTO is the writable subset of JobSchedule - LastRunAt/ NextRunAt/LastError/CreatedBy are server-owned, same reason LinkDTO omits Position from ordinary edits.
type JobTask ¶
type JobTask struct {
FactumModel
JobID uint `gorm:"index;not null" json:"job_id"`
TaskID string `gorm:"uniqueIndex;not null" json:"-"`
Target string `gorm:"index" json:"target"`
StartedAt time.Time `json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
ExitCode int `json:"exit_code"`
Err string `json:"err,omitempty"`
ErrorCount int `gorm:"not null;default:0" json:"error_count"`
WarningCount int `gorm:"not null;default:0" json:"warning_count"`
}
JobTask is one dispatched run of a single target (web.ApiSyncTrigger/ ApiSyncTriggerAll) within a Job - the direct successor of the old SyncJob row, minus TriggeredBy (now only on the parent Job). TaskID is the same ID used for wire-protocol correlation over the hub transport (internal/worker/hub.go's StartCommand/RunAndWait), not a separate ID space - it's an internal transport detail, not part of the REST API surface (json:"-"), which addresses tasks by their ordinary numeric ID like every other resource. FinishedAt is set by the same code path that already detects command completion (internal/worker.LogMsg's StreamExit line) - see RemoteManager.resolveTask. ErrorCount/WarningCount are denormalized, incremented alongside each JobTaskEvent insert (RemoteManager's EnvelopeEvent handler) so the job list can show counts without a live COUNT(*) over events on every poll.
type JobTaskEvent ¶
type JobTaskEvent struct {
FactumModel
JobTaskID *uint `gorm:"index" json:"job_task_id,omitempty"`
TaskID string `gorm:"index;not null" json:"-"`
Target string `json:"target"`
Level string `json:"level"`
Message string `json:"message"`
At time.Time `json:"at"`
}
JobTaskEvent is one info/warning/error line reported by a sync tool via internal/jobevent.Reporter, relayed over the hub transport's "event" envelope and persisted by internal/worker.RemoteManager. JobTaskID is nullable - a --job-flagged command run outside a tracked job (e.g. ad hoc "factum2-worker run") still produces rows here with no owning JobTask, they're just never queried since nothing links to them from the UI.
type LdapRoleMapping ¶
type LdapRoleMapping struct {
FactumModel
GroupDN string `gorm:"uniqueIndex;not null" json:"group_dn"`
RoleID uint `gorm:"not null" json:"role_id"`
}
LdapRoleMapping maps one LDAP/AD group DN to one Factum Role. Re-evaluated on every successful LDAP-backed login (see web/auth.go's syncLDAPRoles), so role changes in the directory propagate automatically without local admin action.
type LdapRoleMappingDTO ¶
type LibrenmsPendingDelete ¶
type LibrenmsPendingDelete struct {
FactumModel
DeviceID int `gorm:"uniqueIndex;not null;column:device_id" json:"device_id"`
Hostname string `json:"hostname"`
Display string `json:"display"`
Reason string `json:"reason"`
ScheduledAt time.Time `json:"scheduled_at"`
ForceDelete bool `json:"force_delete"`
}
LibrenmsPendingDelete is one LibreNMS device that sync has quarantined rather than deleted outright. DeviceID is LibreNMS's device_id (not a factum device id) - the row can outlive the factum device, which is the usual reason it was queued. Display is the original LibreNMS display name without the "(scheduled for deletion …)" suffix sync stamps while the device is quarantined.
type Link ¶
type Link struct {
FactumModel
Group string `gorm:"index;not null" json:"group"`
Name string `gorm:"not null" json:"name"`
URL string `gorm:"not null" json:"url"`
OpenInNewTab bool `json:"open_in_new_tab"`
// Icon is an optional "data:<mime>;base64,..." URI, uploaded client-side
// and stored inline rather than as a file on disk - a release build's
// static assets are compiled into the binary (web/fs_release.go) and
// read-only at runtime, so there's nowhere to write an uploaded file to.
Icon string `gorm:"type:text" json:"icon,omitempty"`
Position int `json:"position"`
}
Link is one admin-managed shortcut shown on the dashboard (Admin -> Settings -> Dashboard), grouped under Group (a free-text section heading) and ordered within the whole list by Position - see web/handle_links.go's ApiLinkCreate/ApiLinksReorder for how the two are maintained. Readable by every logged-in user (GET /api/links), editable by admins only (/api/admin/links).
type LinkDTO ¶
type LinkDTO struct {
ID uint `json:"id"`
Group string `json:"group"`
Name string `json:"name"`
URL string `json:"url"`
OpenInNewTab bool `json:"open_in_new_tab"`
Icon string `json:"icon,omitempty"`
// Position is omitempty so the generic Update handler's DTO<->model
// round trip (web/handle_crud.go) leaves the stored value alone when a
// regular edit omits it - only ApiLinkCreate (append) and
// ApiLinksReorder (drag-and-drop) ever set it, same convention as
// WorkerNodeDTO.Token/DeviceSyncAuthDTO.Password leaving those fields
// unchanged when blank.
Position int `json:"position,omitempty"`
}
type MaintenanceNotification ¶
type MaintenanceNotification struct {
FactumModel
WindowID uint `json:"window_id" gorm:"index;not null"`
CustomerID uint `json:"customer_id" gorm:"index;not null"`
ServiceIDs []uint `json:"service_ids" gorm:"serializer:json"`
ContactID *uint `json:"contact_id"`
Email string `json:"email"`
SentAt *time.Time `json:"sent_at"`
Status string `json:"status" gorm:"type:varchar(16)"`
Error string `json:"error" gorm:"type:text"`
}
MaintenanceNotification is one recipient row for a window.
type MaintenanceResource ¶ added in v1.0.5
type MaintenanceResource struct {
FactumModel
WindowID uint `json:"window_id" gorm:"uniqueIndex:idx_maint_resources;not null;index"`
ResourceType string `json:"resource_type" gorm:"uniqueIndex:idx_maint_resources;type:varchar(16);not null"`
ResourceID uint `json:"resource_id" gorm:"uniqueIndex:idx_maint_resources;not null"`
}
MaintenanceResource is one device, fiber, wavelength, or interface attached to a window. Impact is the union across all rows for that window.
type MaintenanceWindow ¶
type MaintenanceWindow struct {
FactumModel
Title string `json:"title" gorm:"type:varchar(255);not null"`
Description string `json:"description" gorm:"type:text"`
ResourceType string `json:"resource_type" gorm:"type:varchar(16);not null;index"`
ResourceID uint `json:"resource_id" gorm:"index;not null"`
StartsAt time.Time `json:"starts_at" gorm:"index;not null"`
EndsAt time.Time `json:"ends_at"`
Status string `json:"status" gorm:"type:varchar(16);not null;index"`
CreatedBy uint `json:"created_by"`
Resources []MaintenanceResource `json:"resources,omitempty" gorm:"foreignKey:WindowID"`
}
MaintenanceWindow is a scheduled outage on one or more devices, fibers (cables or LF/LI services), wavelengths (VL/VI), or interfaces. ResourceType/ResourceID denormalize the first attached resource so list queries and pre-join rows keep working; Resources is the full set.
type Manufacturer ¶ added in v1.1.0
type Manufacturer struct {
FactumModel
Name string `json:"name" gorm:"type:varchar(255);uniqueIndex;not null"`
Slug string `json:"slug" gorm:"type:varchar(255);uniqueIndex;not null"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
}
Manufacturer is the shared DCIM catalog (NetBox dcim.Manufacturer). Source is "netbox" when upserted from sync, "factum" when created in the UI.
func (*Manufacturer) BeforeCreate ¶ added in v1.1.0
func (m *Manufacturer) BeforeCreate(tx *gorm.DB) error
func (*Manufacturer) BeforeUpdate ¶ added in v1.1.0
func (m *Manufacturer) BeforeUpdate(tx *gorm.DB) error
type ManufacturerDTO ¶ added in v1.1.0
type MoveScopeRequest ¶ added in v1.0.5
type MoveScopeRequest struct {
ParentID uint `json:"parent_id"`
SortOrder *int `json:"sort_order"`
}
MoveScopeRequest is POST /api/config/scopes/:id/move. SortOrder nil = last sibling.
type OpticalKindMap ¶
type OpticalKindMap struct {
FactumModel
NetboxRoleName string `json:"netbox_role_name" gorm:"uniqueIndex;type:varchar(255);not null"`
OpticalKind string `json:"optical_kind" gorm:"type:varchar(32);not null"`
}
OpticalKindMap maps a NetBox device role display name (lowercased) to a Factum optical kind. Admin-editable.
type OpticalKindMapDTO ¶
type OpticalPort ¶
type OpticalPort struct {
FactumModel
InterfaceID uint `json:"interface_id" gorm:"uniqueIndex;not null"`
Role string `json:"role" gorm:"type:varchar(32);not null;index"`
FreqHz uint64 `json:"freq_hz"`
ITUChannel *int `json:"itu_channel"`
Notes string `json:"notes" gorm:"type:varchar(255)"`
}
OpticalPort is Factum-owned optical metadata for a NetBox-synced interface. Separate table so syncInterfaces UpdateAll cannot wipe it.
type OpticalXConnect ¶
type OpticalXConnect struct {
FactumModel
DeviceID uint `json:"device_id" gorm:"index;not null"`
Kind string `json:"kind" gorm:"type:varchar(32);not null;index"`
InterfaceAID uint `json:"interface_a_id" gorm:"index;not null"`
InterfaceBID uint `json:"interface_b_id" gorm:"index;not null"`
FreqHz uint64 `json:"freq_hz"`
Source string `json:"source" gorm:"type:varchar(32);index"`
}
OpticalXConnect is one intra-device optical adjacency.
type PasswordResetToken ¶
type PasswordResetToken struct {
FactumModel
UserID uint `gorm:"index;not null" json:"-"`
TokenHash string `gorm:"uniqueIndex;not null" json:"-"`
CodeHash string `gorm:"not null" json:"-"`
ExpiresAt time.Time `json:"-"`
// Attempts counts failed code redemption tries against this row - the
// code is only 8 digits (looked up by email, not by hash), so this
// caps brute-forcing it before ExpiresAt would otherwise.
Attempts int `json:"-"`
ConsumedAt *time.Time `json:"-"`
}
PasswordResetToken backs the forgot-password flow (web.ApiForgotPassword/ ApiResetPassword). One row per outstanding request: TokenHash matches the long random token embedded in the emailed link, CodeHash matches the short human-typeable code shown alongside it - both derive from the same crypto/rand-generated secrets, so a fast deterministic hash is fine for both (unlike a user-chosen password, there's no dictionary smaller than the keyspace to attack). Either one redeems the request; redeeming consumes it.
type Platform ¶ added in v1.1.0
type Platform struct {
FactumModel
Name string `json:"name" gorm:"type:varchar(255);uniqueIndex;not null"`
Slug string `json:"slug" gorm:"type:varchar(255);uniqueIndex;not null"`
ManufacturerID uint `json:"manufacturer_id"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
}
Platform is the shared DCIM catalog (NetBox dcim.Platform). Slug is what drivers match on (eos, sros, vrp, …).
type PlatformDTO ¶ added in v1.1.0
type Product ¶
type Product struct {
FactumModel
LastSync uint `json:"-"`
Name string `json:"name"`
}
type Rack ¶ added in v1.1.1
type Rack struct {
FactumModel
SiteID uint `json:"site_id" gorm:"index;not null"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
HeightU int `json:"height_u" gorm:"column:height_u;not null"`
WidthMM int `json:"width_mm" gorm:"column:width_mm"`
DepthMM int `json:"depth_mm" gorm:"column:depth_mm"`
StartUnit int `json:"start_unit"`
Numbering string `json:"numbering" gorm:"type:varchar(32)"`
Version int `json:"version"`
}
Rack is a physical equipment rack. SiteID is a local sites.id.
func (Rack) HeightTicks ¶ added in v1.1.1
type Role ¶
type Role struct {
FactumModel
Name string `gorm:"uniqueIndex;not null" json:"name"`
Description string `json:"description"`
Users []*User `gorm:"many2many:user_roles;" json:"-"`
}
Role defines user roles (e.g., admin, user)
type Service ¶
type Service struct {
FactumModel
LastSync uint `json:"-"`
Name string `json:"name"`
CustomerID uint `json:"company"`
Comment string `json:"comment"`
ServiceID string `json:"service_id"` // <category><5-digit>, e.g. CI00001 - the 2-letter prefix is the category (CI, VI, LI, ...), so it isn't stored separately
ServiceType string `json:"service_type"` // ELINE, ELAN, L3VPN, POLARIX - CI/CN only, else ""
BandwidthMbps int `json:"bandwidth_mbps"` // from type schema field bandwidth_mbps, else 0
MaxMacAddresses int `json:"max_mac_addresses"` // from type schema field max_mac_addresses (ELAN), else 0
DeliveryPoint1 string `json:"deliverypoint1"`
DeliveryPoint2 string `json:"deliverypoint2"`
Product string `json:"product"`
Service string `json:"service"`
AgreementStatus string `json:"agreement_status"` // Lime agreement_status.text (e.g. "Active"); empty for factum-created rows
// ConnectionTypeID is the chosen service_connection_types row, if any.
ConnectionTypeID *uint `json:"connection_type_id"`
// PseudowireID is derived from ServiceID (pseudowireIDFromServiceID,
// web/handler_service_eline.go) and stored as the Netbox L2VPN's
// identifier.
PseudowireID int `json:"pseudowire_id"`
L2VPNNetboxID uint `json:"l2vpn_netbox_id"`
// Fields holds instance-level values for a service type's schema.
Fields json.RawMessage `json:"fields" gorm:"serializer:json"`
Source string `json:"source"`
SourceID string `json:"source_id"`
}
func (*Service) BeforeCreate ¶
BeforeCreate defaults a service's Source to "factum" when nothing set it already. The Lime sync job (internal/lime/lime.go) always sets Source to "lime" itself before saving, so this only ever fires for services created through the web API - ServiceDTO has no Source field for a caller to set, so without this default every manually-created service would be indistinguishable (Source == "") from one whose sync origin just hasn't been recorded yet, instead of clearly marked as user-created.
type ServiceConnectionType ¶ added in v1.1.0
type ServiceConnectionType struct {
FactumModel
ServiceTypeID uint `json:"service_type_id" gorm:"uniqueIndex:idx_svc_ct_type_name;not null"`
Name string `json:"name" gorm:"uniqueIndex:idx_svc_ct_type_name;not null;type:varchar(64)"`
SortOrder int `json:"sort_order"`
Image []byte `json:"-" gorm:"type:bytea"`
ContentType string `json:"content_type" gorm:"type:varchar(64)"`
// HasImage is filled by list/get loaders from a length check; not a column.
HasImage bool `json:"-" gorm:"-"`
}
ServiceConnectionType is a named connection choice on a definition.
func (ServiceConnectionType) TableName ¶ added in v1.1.0
func (ServiceConnectionType) TableName() string
type ServiceConnectionTypeDTO ¶ added in v1.1.0
type ServiceDTO ¶
type ServiceDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
CustomerID uint `json:"company"`
Comment string `json:"comment"`
ServiceID string `json:"service_id"`
Category string `json:"category"`
ServiceType string `json:"service_type"`
BandwidthMbps int `json:"bandwidth_mbps"`
MaxMacAddresses int `json:"max_mac_addresses"`
DeliveryPoint1 string `json:"deliverypoint1"`
DeliveryPoint2 string `json:"deliverypoint2"`
Product string `json:"product"`
Service string `json:"service"`
Fields json.RawMessage `json:"fields"`
ConnectionTypeID *uint `json:"connection_type_id"`
}
ServiceDTO is the create/update request shape for the service API, mirroring the fields the frontend's service form actually edits (web/frontend/src/views/service/ServiceList.vue, web/frontend/src/views/service/ServiceCreateWizard.vue) - it shows "source" and "agreement_status" as disabled/display-only fields, so, like ContactDTO, Source/SourceID/AgreementStatus are excluded here rather than merely disabled client-side: the sync-managed values survive an Update untouched, and a manually-created service gets the zero value instead of a caller being able to fake a Lime origin or agreement status.
On create (ApiServiceCreate), ServiceID is optional: a blank value has the backend auto-assign the next <category><5-digit> number for Category, rather than the wizard reserving one up front.
type ServiceEndpoint ¶ added in v1.0.2
type ServiceEndpoint struct {
FactumModel
ServiceID uint `json:"service_id" gorm:"index;not null"`
Role string `json:"role" gorm:"type:varchar(64);not null"`
DeviceID uint `json:"device_id" gorm:"index;not null"`
InterfaceID uint `json:"interface_id" gorm:"index;not null"`
Fields json.RawMessage `json:"fields" gorm:"serializer:json"`
// Applied* is the last successful push snapshot for this binding.
AppliedDeviceID uint `json:"-"`
AppliedIface string `json:"-"`
AppliedPlatform string `json:"-"`
AppliedFields json.RawMessage `json:"-" gorm:"serializer:json"`
}
ServiceEndpoint is a service termination. Role is always "interface".
func (ServiceEndpoint) TableName ¶ added in v1.0.2
func (ServiceEndpoint) TableName() string
type ServiceEndpointDTO ¶ added in v1.0.2
type ServiceHop ¶
type ServiceHop struct {
FactumModel
ServiceID uint `json:"service_id" gorm:"index;not null"`
Seq int `json:"seq" gorm:"not null"`
Kind string `json:"kind" gorm:"type:varchar(16);not null;index"`
InterfaceID *uint `json:"interface_id" gorm:"index"`
ConnectionID *uint `json:"connection_id" gorm:"index"`
XConnectID *uint `json:"xconnect_id" gorm:"index"`
DeviceID *uint `json:"device_id" gorm:"index"`
FreqHz uint64 `json:"freq_hz"`
Label string `json:"label" gorm:"type:varchar(255)"`
}
ServiceHop is one row of a materialized path. Exactly one Kind / FK.
type ServiceInterfacesSpec ¶ added in v1.1.0
type ServiceInterfacesSpec struct {
Min int `json:"min"`
Max int `json:"max"`
Unique bool `json:"unique"`
Fields []FieldSchema `json:"fields"`
}
ServiceInterfacesSpec is the homogeneous UNI spec for a service type. Max == 0 means unlimited.
type ServicePath ¶
type ServicePath struct {
FactumModel
ServiceID uint `json:"service_id" gorm:"uniqueIndex;not null"`
Mode string `json:"mode" gorm:"type:varchar(16);not null"`
Status string `json:"status" gorm:"type:varchar(16);not null;index"`
EndpointAInterfaceID uint `json:"endpoint_a_interface_id" gorm:"index;not null"`
EndpointZInterfaceID uint `json:"endpoint_z_interface_id" gorm:"index;not null"`
StartKindA string `json:"start_kind_a" gorm:"type:varchar(32)"`
StartKindZ string `json:"start_kind_z" gorm:"type:varchar(32)"`
FreqHz uint64 `json:"freq_hz"`
LastTracedAt *time.Time `json:"last_traced_at"`
LastTraceError string `json:"last_trace_error" gorm:"type:text"`
Hops []ServiceHop `json:"hops,omitempty" gorm:"foreignKey:ServiceID;references:ServiceID"`
}
ServicePath is the attached optical/fiber path for one VL/VI/LF/LI service.
type ServiceType ¶ added in v1.0.2
type ServiceType struct {
FactumModel
Name string `json:"name" gorm:"uniqueIndex;not null;type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(255)"`
Schema []FieldSchema `json:"schema" gorm:"serializer:json"`
Interfaces ServiceInterfacesSpec `json:"interfaces" gorm:"serializer:json"`
Builtin bool `json:"builtin"`
// SyncSource names the on-device collection device-sync reads
// (eline / elan / l3vpn). Empty means the type is GUI-only.
SyncSource string `json:"sync_source" gorm:"type:varchar(32)"`
// NetboxType is the NetBox object to upsert for SyncSource
// (evpl / vpls / vrf).
NetboxType string `json:"netbox_type" gorm:"type:varchar(32)"`
ConnectionTypes []ServiceConnectionType `json:"connection_types" gorm:"foreignKey:ServiceTypeID"`
}
ServiceType is a vendor-agnostic service class (ELINE, ELAN, …).
func (ServiceType) TableName ¶ added in v1.0.2
func (ServiceType) TableName() string
type ServiceTypeDTO ¶ added in v1.0.2
type ServiceTypeDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Schema []FieldSchema `json:"schema"`
Interfaces ServiceInterfacesSpec `json:"interfaces"`
SyncSource string `json:"sync_source"`
NetboxType string `json:"netbox_type"`
ConnectionTypes []ServiceConnectionTypeDTO `json:"connection_types"`
}
type Settings ¶
type Settings struct {
FactumModel
// features activated
BecsEnabled *bool `gorm:"column:becs_enabled" form:"becs_enabled" json:"becs_enabled"`
DnsEnabled *bool `gorm:"column:dns_enabled" form:"dns_enabled" json:"dns_enabled"`
IcingaEnabled *bool `gorm:"column:icinga_enabled" form:"icinga_enabled" json:"icinga_enabled"`
// OpticalEnabled gates WDM / ROADM / wavelength-path UI and APIs.
// Off (nil/false) is the default. Same *bool shape as the other flags.
OpticalEnabled *bool `gorm:"column:optical_enabled" form:"optical_enabled" json:"optical_enabled"`
// IpamEnabled gates the standalone IPAM UI and /api/ipam/* routes.
// Off (nil/false) is the default. Turning it off only hides the
// feature — namespaces, VRFs and prefixes stay in the database.
IpamEnabled *bool `gorm:"column:ipam_enabled" form:"ipam_enabled" json:"ipam_enabled"`
// OrganizationEnabled gates the Organization menu (Customers, Contacts,
// Sites) in the web GUI. Off (nil/false) is the default. Turning it off
// only hides the menu — customer, contact and site rows stay in the
// database, and services may still reference them.
OrganizationEnabled *bool `gorm:"column:organization_enabled" form:"organization_enabled" json:"organization_enabled"`
// DnsZonesEnabled gates the DNS zone editor UI and /api/dns/* zone
// routes (SOA templates, DNS templates, DNSSEC policies, zones).
// Off (nil/false) is the default. Distinct from DnsEnabled, which is
// the Destinations toggle for device-record sync. Turning this off
// only hides the UI — rows stay in the database.
DnsZonesEnabled *bool `gorm:"column:dns_zones_enabled" form:"dns_zones_enabled" json:"dns_zones_enabled"`
// DhcpEnabled gates DHCP server management: per-prefix DHCP in IPAM
// and the MAC column on DNS zone records. Off (nil/false) is the
// default. Turning it off only hides the UI — prefix DHCP fields and
// record MACs stay in the database. factum2-dns writes Kea prefixes
// into the dnsmgr2 prefix include when this is on.
DhcpEnabled *bool `gorm:"column:dhcp_enabled" form:"dhcp_enabled" json:"dhcp_enabled"`
LibrenmsEnabled *bool `gorm:"column:librenms_enabled" form:"librenms_enabled" json:"librenms_enabled"`
LimeEnabled *bool `gorm:"column:lime_enabled" form:"lime_enabled" json:"lime_enabled"`
NetboxEnabled *bool `gorm:"column:netbox_enabled" form:"netbox_enabled" json:"netbox_enabled"`
OxidizedEnabled *bool `gorm:"column:oxidized_enabled" form:"oxidized_enabled" json:"oxidized_enabled"`
PrometheusEnabled *bool `gorm:"column:prometheus_enabled" form:"prometheus_enabled" json:"prometheus_enabled"`
DeviceSyncEnabled *bool `gorm:"column:device_sync_enabled" form:"device_sync_enabled" json:"device_sync_enabled"`
// CertsEnabled gates the Certificates GUI, /api/certs/*, and the
// dest "certs" sync (factum2-certs writes .lego.yaml/.env and runs lego).
CertsEnabled *bool `gorm:"column:certs_enabled" form:"certs_enabled" json:"certs_enabled"`
// StorageEnabled gates the Software GUI and /api/software/*. Off
// (nil/false) is the default. Turning it off only hides the UI — files
// on the storage host are not deleted.
StorageEnabled *bool `gorm:"column:storage_enabled" form:"storage_enabled" json:"storage_enabled"`
// StorageRoot is the repository directory on the storage host
// (factum2-storage start). Empty is /var/lib/factum2/storage.
StorageRoot string `gorm:"column:storage_root" form:"storage_root" json:"storage_root"`
// StorageHTTPListen is the device-facing HTTP bind (e.g. ":8088").
// Empty disables the HTTP server.
StorageHTTPListen string `gorm:"column:storage_http_listen" form:"storage_http_listen" json:"storage_http_listen"`
// StorageHTTPURL is the origin devices use in copy http://… commands
// (e.g. http://10.0.0.5:8088). Not the listen address.
StorageHTTPURL string `gorm:"column:storage_http_url" form:"storage_http_url" json:"storage_http_url"`
StorageTFTPListen string `gorm:"column:storage_tftp_listen" form:"storage_tftp_listen" json:"storage_tftp_listen"`
StorageTFTPHost string `gorm:"column:storage_tftp_host" form:"storage_tftp_host" json:"storage_tftp_host"`
StorageSFTPListen string `gorm:"column:storage_sftp_listen" form:"storage_sftp_listen" json:"storage_sftp_listen"`
StorageSFTPHost string `gorm:"column:storage_sftp_host" form:"storage_sftp_host" json:"storage_sftp_host"`
StorageSFTPUser string `gorm:"column:storage_sftp_user" form:"storage_sftp_user" json:"storage_sftp_user"`
StorageSFTPPassword string `gorm:"column:storage_sftp_password" form:"storage_sftp_password" json:"storage_sftp_password"`
// factum
FactumApiToken string `gorm:"column:factum_api_token" form:"factum_api_token" json:"factum_api_token"`
// BrandLogo is an optional image shown to the right of the Factum
// wordmark (data URL or http(s) URL). Empty hides it.
BrandLogo string `gorm:"column:brand_logo;type:text" form:"brand_logo" json:"brand_logo"`
// BrandText is optional label shown next to BrandLogo.
BrandText string `gorm:"column:brand_text" form:"brand_text" json:"brand_text"`
// PublicBaseURL is the externally-reachable origin (e.g.
// "https://factum.example.com") used to build absolute links in
// outgoing email, currently just the password-reset link
// (web.ApiForgotPassword). If left blank, the reset handler falls back
// to deriving an origin from the incoming request instead - fine for
// simple setups, but a deployment behind a reverse proxy should set
// this explicitly rather than trusting Host/X-Forwarded-* headers for
// something that ends up in an email.
PublicBaseURL string `gorm:"column:public_base_url" form:"public_base_url" json:"public_base_url"`
// DefaultDomain is shared by every downstream sync target
// (DNS/Icinga/LibreNMS/Oxidized/Prometheus), not just DNS - it's the
// $ORIGIN of the generated DNS zone file, and also used to match factum
// device names against fully-qualified DNS names during Icinga/LibreNMS/
// Oxidized/Prometheus sync. It lives here rather than in local YAML
// config so each CLI tool can fetch it over REST (via util.CommonConfig)
// like the rest of its settings, since they typically run on a different
// host than the primary.
DefaultDomain string `gorm:"column:default_domain" form:"default_domain" json:"default_domain"`
// JobHistoryKeep is how many newest finished Jobs (and their
// JobTask/JobTaskEvent rows) the housekeeping target keeps. Values < 1
// are treated as 50 by housekeeping.Trim (the same cap GET /api/jobs
// lists), so an unset column cannot wipe history on the first run.
// Unfinished jobs are never deleted. The task does not run on its
// own - schedule or trigger "housekeeping" like any other job target.
JobHistoryKeep int `gorm:"column:job_history_keep" form:"job_history_keep" json:"job_history_keep"`
// BECS
BecsEapiURL string `gorm:"column:becs_eapi_url" form:"becs_eapi_url" json:"becs_eapi_url"`
BecsEapiUser string `gorm:"column:becs_eapi_user" form:"becs_eapi_user" json:"becs_eapi_user"`
BecsEapiPass string `gorm:"column:becs_eapi_pass" form:"becs_eapi_pass" json:"becs_eapi_pass"`
BecsEapiOID uint `gorm:"column:becs_eapi_oid" form:"becs_eapi_oid" json:"becs_eapi_oid"`
// DNS
DnsDestFile string `gorm:"column:dns_dest_file" form:"dns_dest_file" json:"dns_dest_file"`
// IgnoreModels/IgnorePlatforms are newline-separated lists (one model or
// platform name per line), edited as a multiline box in the admin UI -
// internal/dns.filterDevices skips a device matching either.
DnsIgnoreModels string `gorm:"column:dns_ignore_models;type:text" form:"dns_ignore_models" json:"dns_ignore_models"`
DnsIgnorePlatforms string `gorm:"column:dns_ignore_platforms;type:text" form:"dns_ignore_platforms" json:"dns_ignore_platforms"`
// DnsZonesFile is the path factum2-dns writes the dnsmgr2 zone-include
// YAML to when DnsZonesEnabled is on. Empty skips writing (the
// operator lists zones in the main dnsmgr2.yaml).
DnsZonesFile string `gorm:"column:dns_zones_file" form:"dns_zones_file" json:"dns_zones_file"`
// Unused by current factum2-dns (the administrator-managed
// dnsmgr2.yaml holds BIND paths and the sqlite serial DB). Kept so
// existing Settings rows continue to load.
DnsConfigFile string `gorm:"column:dns_config_file" form:"dns_config_file" json:"dns_config_file"`
DnsDbFile string `gorm:"column:dns_db_file" form:"dns_db_file" json:"dns_db_file"`
DnsHostTemplate string `gorm:"column:dns_host_template" form:"dns_host_template" json:"dns_host_template"`
DnsBindType string `gorm:"column:dns_bind_type" form:"dns_bind_type" json:"dns_bind_type"`
DnsBindConfigDir string `gorm:"column:dns_bind_config_dir" form:"dns_bind_config_dir" json:"dns_bind_config_dir"`
DnsBindIncludeFile string `gorm:"column:dns_bind_include_file" form:"dns_bind_include_file" json:"dns_bind_include_file"`
DnsBindZonesDir string `gorm:"column:dns_bind_zones_dir" form:"dns_bind_zones_dir" json:"dns_bind_zones_dir"`
DnsBindZonesFile string `gorm:"column:dns_bind_zones_file" form:"dns_bind_zones_file" json:"dns_bind_zones_file"`
DnsBindTmpDir string `gorm:"column:dns_bind_tmp_dir" form:"dns_bind_tmp_dir" json:"dns_bind_tmp_dir"`
DnsBindCmdReloadAll string `gorm:"column:dns_bind_cmd_reload_all" form:"dns_bind_cmd_reload_all" json:"dns_bind_cmd_reload_all"`
DnsBindCmdReloadZone string `gorm:"column:dns_bind_cmd_reload_zone" form:"dns_bind_cmd_reload_zone" json:"dns_bind_cmd_reload_zone"`
DnsBindCmdRestart string `gorm:"column:dns_bind_cmd_restart" form:"dns_bind_cmd_restart" json:"dns_bind_cmd_restart"`
// DhcpDnsServers is the default DNS server list offered to DHCP
// clients (newline-separated). A prefix may override this. Edited on
// the Factum tab next to the DHCP feature switch.
DhcpDnsServers string `gorm:"column:dhcp_dns_servers;type:text" form:"dhcp_dns_servers" json:"dhcp_dns_servers"`
// DhcpPrefixesFile is the path factum2-dns writes the dnsmgr2
// prefix-include YAML to when DhcpEnabled is on. Empty skips writing.
DhcpPrefixesFile string `gorm:"column:dhcp_prefixes_file" form:"dhcp_prefixes_file" json:"dhcp_prefixes_file"`
// Kea host-template fields. Paths belong in the administrator-managed
// dnsmgr2.yaml; these Settings columns remain for existing rows.
DhcpHostTemplate string `gorm:"column:dhcp_host_template" form:"dhcp_host_template" json:"dhcp_host_template"`
DhcpKeaType string `gorm:"column:dhcp_kea_type" form:"dhcp_kea_type" json:"dhcp_kea_type"`
DhcpKea4ConfigDir string `gorm:"column:dhcp_kea4_config_dir" form:"dhcp_kea4_config_dir" json:"dhcp_kea4_config_dir"`
DhcpKea4IncludeFile string `gorm:"column:dhcp_kea4_include_file" form:"dhcp_kea4_include_file" json:"dhcp_kea4_include_file"`
DhcpKea4TmpDir string `gorm:"column:dhcp_kea4_tmp_dir" form:"dhcp_kea4_tmp_dir" json:"dhcp_kea4_tmp_dir"`
DhcpKea4CmdRestart string `gorm:"column:dhcp_kea4_cmd_restart" form:"dhcp_kea4_cmd_restart" json:"dhcp_kea4_cmd_restart"`
DhcpKea6ConfigDir string `gorm:"column:dhcp_kea6_config_dir" form:"dhcp_kea6_config_dir" json:"dhcp_kea6_config_dir"`
DhcpKea6IncludeFile string `gorm:"column:dhcp_kea6_include_file" form:"dhcp_kea6_include_file" json:"dhcp_kea6_include_file"`
DhcpKea6TmpDir string `gorm:"column:dhcp_kea6_tmp_dir" form:"dhcp_kea6_tmp_dir" json:"dhcp_kea6_tmp_dir"`
DhcpKea6CmdRestart string `gorm:"column:dhcp_kea6_cmd_restart" form:"dhcp_kea6_cmd_restart" json:"dhcp_kea6_cmd_restart"`
// Certificates / lego (https://github.com/go-acme/lego). Paths are
// written by factum2-certs on sync. Empty yaml/env paths skip writing.
CertsLegoYaml string `gorm:"column:certs_lego_yaml" form:"certs_lego_yaml" json:"certs_lego_yaml"`
CertsEnvFile string `gorm:"column:certs_env_file" form:"certs_env_file" json:"certs_env_file"`
CertsLegoBin string `gorm:"column:certs_lego_bin" form:"certs_lego_bin" json:"certs_lego_bin"`
CertsLegoStorage string `gorm:"column:certs_lego_storage" form:"certs_lego_storage" json:"certs_lego_storage"`
CertsDefaultKeyType string `gorm:"column:certs_default_key_type" form:"certs_default_key_type" json:"certs_default_key_type"`
CertsDefaultEnableCommonName *bool `` /* 126-byte string literal not displayed */
// Email / SMTP - a general-purpose outbound mail relay, not tied to
// Icinga specifically (factum2-icinga-notifications is the first
// consumer, via util.CommonConfig, but any tool that needs to send
// mail can fetch the same settings). Edited on the admin UI's
// Factum > Email tab.
SmtpHost string `gorm:"column:smtp_host" form:"smtp_host" json:"smtp_host"`
SmtpPort uint16 `gorm:"column:smtp_port" form:"smtp_port" json:"smtp_port"`
SmtpUser string `gorm:"column:smtp_user" form:"smtp_user" json:"smtp_user"`
SmtpPass string `gorm:"column:smtp_pass" form:"smtp_pass" json:"smtp_pass"`
// SmtpTLSMode is "none" | "starttls" | "tls", same convention as LdapTLSMode.
SmtpTLSMode string `gorm:"column:smtp_tls_mode" form:"smtp_tls_mode" json:"smtp_tls_mode"`
// EmailSender is the default From address for outgoing notification email.
EmailSender string `gorm:"column:email_sender" form:"email_sender" json:"email_sender"`
// Icinga
IcingaApiURL string `gorm:"column:icinga_api_url" form:"icinga_api_url" json:"icinga_api_url"`
IcingaApiUser string `gorm:"column:icinga_api_user" form:"icinga_api_user" json:"icinga_api_user"`
IcingaApiPass string `gorm:"column:icinga_api_pass" form:"icinga_api_pass" json:"icinga_api_pass"`
IcingaHostsFile string `gorm:"column:icinga_hosts_file" form:"icinga_hosts_file" json:"icinga_hosts_file"`
IcingaUsersFile string `gorm:"column:icinga_users_file" form:"icinga_users_file" json:"icinga_users_file"`
// IcingaCertsFile is the Icinga 2 conf written by factum2-icinga for
// HTTPS certificate checks (one Service per certificate name).
IcingaCertsFile string `gorm:"column:icinga_certs_file" form:"icinga_certs_file" json:"icinga_certs_file"`
// IcingaIgnoreDevices is a newline-separated list of device names (one
// per line) that factum2-icinga's Update() skips entirely.
IcingaIgnoreDevices string `gorm:"column:icinga_ignore_devices;type:text" form:"icinga_ignore_devices" json:"icinga_ignore_devices"`
// IcingaDefaultNotification is a Jet template executed with .Device
// for a host that has no cf_alarm_destination, e.g.
// ` vars.pe_notify_default = true`. Literal Icinga with no {{ }} is
// fine. The rendered lines are inserted into the host object (see
// internal/icinga/factum2-icinga.go).
IcingaDefaultNotification string `gorm:"column:icinga_default_notification;type:text" form:"icinga_default_notification" json:"icinga_default_notification"`
// IcingaHostTemplate/IcingaDependencyTemplate/IcingaUserTemplate are
// Jet templates (see internal/icinga/factum2-icinga.go for the data
// each is executed with).
IcingaHostTemplate string `gorm:"column:icinga_host_template;type:text" form:"icinga_host_template" json:"icinga_host_template"`
IcingaDependencyTemplate string `gorm:"column:icinga_dependency_template;type:text" form:"icinga_dependency_template" json:"icinga_dependency_template"`
IcingaUserTemplate string `gorm:"column:icinga_user_template;type:text" form:"icinga_user_template" json:"icinga_user_template"`
// IcingaCertTemplate is a Jet template executed once per Icinga sync
// with .Checks (Host, Domain, CertName). Typically an Icinga
// `template Service` plus one `object Service` per check.
IcingaCertTemplate string `gorm:"column:icinga_cert_template;type:text" form:"icinga_cert_template" json:"icinga_cert_template"`
// Librenms
LibrenmsApiURL string `gorm:"column:librenms_api_url" form:"librenms_api_url" json:"librenms_api_url"`
LibrenmsApiToken string `gorm:"column:librenms_api_token" form:"librenms_api_token" json:"librenms_api_token"`
// LibrenmsPersistentDevices is a newline-separated list, edited as a
// multiline box in the admin UI, same convention as the Ignore* fields
// above. FactumLibrenmsClient.Sync never quarantines or deletes a
// LibreNMS device whose hostname or display name matches a line here.
LibrenmsPersistentDevices string `gorm:"column:librenms_persistent_devices;type:text" form:"librenms_persistent_devices" json:"librenms_persistent_devices"`
// LibrenmsDelayedDeleteEnabled gates the LibreNMS delete path. Off
// (nil/false, the default) means sync never removes a device. On means
// a delete candidate is quarantined (polling and alerts off, display
// name stamped with the scheduled date) and actually deleted on a later
// sync once ScheduledAt has passed, or sooner if the user sets
// LibrenmsPendingDelete.ForceDelete. Same *bool shape as the other flags.
LibrenmsDelayedDeleteEnabled *bool `gorm:"column:librenms_delayed_delete_enabled" form:"librenms_delayed_delete_enabled" json:"librenms_delayed_delete_enabled"`
// LibrenmsDelayedDeleteDays is how long a quarantined device stays in
// LibreNMS before the next sync deletes it. Values < 1 are treated as
// 30 by sync (the documented default), so an unset column cannot
// accidentally delete on the following run.
LibrenmsDelayedDeleteDays int `gorm:"column:librenms_delayed_delete_days" form:"librenms_delayed_delete_days" json:"librenms_delayed_delete_days"`
// LibrenmsRolesEnabled/InterfacesDisabled are newline-separated lists of
// regexes (one per line) - FactumLibrenmsClient.syncInterfaces compiles
// each line and matches it against an interface's factum role
// (RolesEnabled) or name (InterfacesDisabled) to force alerting on/off
// respectively, overriding the device's CfAlarmInterfaces default.
LibrenmsRolesEnabled string `gorm:"column:librenms_roles_enabled;type:text" form:"librenms_roles_enabled" json:"librenms_roles_enabled"`
LibrenmsInterfacesDisabled string `gorm:"column:librenms_interfaces_disabled;type:text" form:"librenms_interfaces_disabled" json:"librenms_interfaces_disabled"`
// LibrenmsSNMPVersion is the SNMP version (e.g. "v1", "v2c", "v3") used
// when creating devices in LibreNMS.
LibrenmsSNMPVersion string `gorm:"column:librenms_snmp_version" form:"librenms_snmp_version" json:"librenms_snmp_version"`
// LibrenmsSNMPCommunities is a newline-separated list of SNMP
// communities (one per line, tried in order), same convention as the
// Ignore* fields above - FactumLibrenmsClient.Sync tries each in turn
// when creating a device in LibreNMS, force-adding with the first one
// if none succeed.
LibrenmsSNMPCommunities string `gorm:"column:librenms_snmp_communities;type:text" form:"librenms_snmp_communities" json:"librenms_snmp_communities"`
// Lime
LimeApiURL string `gorm:"column:lime_api_url" form:"lime_api_url" json:"lime_api_url"`
LimeApiToken string `gorm:"column:lime_api_token" form:"lime_api_token" json:"lime_api_token"`
// Netbox
NetboxApiURL string `gorm:"column:netbox_api_url" form:"netbox_api_url" json:"netbox_api_url"`
NetboxApiToken string `gorm:"column:netbox_api_token" form:"netbox_api_token" json:"netbox_api_token"`
// NetboxWebhookSecret is the shared secret Netbox signs its webhook
// request bodies with (HMAC-SHA512, "X-Hook-Signature" header) - see
// web.ApiNetboxWebhook. Configured the same way on the Netbox side, as
// the webhook's "secret" field.
NetboxWebhookSecret string `gorm:"column:netbox_webhook_secret" form:"netbox_webhook_secret" json:"netbox_webhook_secret"`
// NetboxSyncCustomersEnabled, when set, makes FactumSyncNetbox also
// push factum customers to Netbox as tenants (custom fields
// source/source_id identify which customer a tenant came from).
NetboxSyncCustomersEnabled *bool `gorm:"column:netbox_sync_customers_enabled" form:"netbox_sync_customers_enabled" json:"netbox_sync_customers_enabled"`
// NetboxSyncContactsEnabled, when set, makes FactumSyncNetbox also
// push factum contacts to Netbox as contacts (same source/source_id
// custom fields as tenants). CustomerContact links become contact
// assignments on the matching tenant when that tenant exists.
NetboxSyncContactsEnabled *bool `gorm:"column:netbox_sync_contacts_enabled" form:"netbox_sync_contacts_enabled" json:"netbox_sync_contacts_enabled"`
// Oxidized
OxidizedApiURL string `gorm:"column:oxidized_api_url" form:"oxidized_api_url" json:"oxidized_api_url"`
OxidizedApiUser string `gorm:"column:oxidized_api_user" form:"oxidized_api_user" json:"oxidized_api_user"`
OxidizedApiPass string `gorm:"column:oxidized_api_pass" form:"oxidized_api_pass" json:"oxidized_api_pass"`
// OxidizedDestFile is oxidized's own router.db - internal/oxidized
// writes the filtered device list here (name:ip:model per line).
// Oxidized's CSV source must map name: 0, ip: 1, model: 2.
OxidizedDestFile string `gorm:"column:oxidized_dest_file" form:"oxidized_dest_file" json:"oxidized_dest_file"`
// OxidizedIgnoreDevices/Manufacturers/Models/Platforms are
// newline-separated lists, edited as multiline boxes in the admin UI -
// a device matching any one of them is skipped by
// FactumOxidizedClient.Sync.
OxidizedIgnoreDevices string `gorm:"column:oxidized_ignore_devices;type:text" form:"oxidized_ignore_devices" json:"oxidized_ignore_devices"`
OxidizedIgnoreManufacturers string `` /* 127-byte string literal not displayed */
OxidizedIgnoreModels string `gorm:"column:oxidized_ignore_models;type:text" form:"oxidized_ignore_models" json:"oxidized_ignore_models"`
OxidizedIgnorePlatforms string `gorm:"column:oxidized_ignore_platforms;type:text" form:"oxidized_ignore_platforms" json:"oxidized_ignore_platforms"`
// Prometheus + snmp_exporter. factum2-prometheus writes a Prometheus
// file_sd JSON of SNMP targets (Settings.PrometheusDestFile) from
// devices flagged CfMonitorGrafana, then POSTs PrometheusReloadURL
// if the file changed and a URL is set. Module/Auth are snmp_exporter
// names (snmp.yml), not community strings.
PrometheusDestFile string `gorm:"column:prometheus_dest_file" form:"prometheus_dest_file" json:"prometheus_dest_file"`
// PrometheusReloadURL is the full URL POSTed after a file change
// (typically http://127.0.0.1:9090/-/reload, which needs Prometheus
// --web.enable-lifecycle). Empty skips the reload - file_sd still
// re-reads the dest file on its own refresh interval.
PrometheusReloadURL string `gorm:"column:prometheus_reload_url" form:"prometheus_reload_url" json:"prometheus_reload_url"`
// PrometheusModule is the snmp_exporter module name stamped on every
// target (e.g. "if_mib"). Empty is treated as "if_mib" at write time.
PrometheusModule string `gorm:"column:prometheus_module" form:"prometheus_module" json:"prometheus_module"`
// PrometheusAuth is the snmp_exporter auth name stamped on every
// target (an auths: key in snmp.yml, e.g. "public_v2"). Empty is
// treated as "public_v2" at write time.
PrometheusAuth string `gorm:"column:prometheus_auth" form:"prometheus_auth" json:"prometheus_auth"`
// PrometheusIgnoreDevices/Manufacturers/Models/Platforms are
// newline-separated lists, same convention as Oxidized's Ignore* -
// a device matching any one of them is skipped by
// FactumPrometheusClient.Sync.
PrometheusIgnoreDevices string `gorm:"column:prometheus_ignore_devices;type:text" form:"prometheus_ignore_devices" json:"prometheus_ignore_devices"`
PrometheusIgnoreManufacturers string `` /* 133-byte string literal not displayed */
PrometheusIgnoreModels string `gorm:"column:prometheus_ignore_models;type:text" form:"prometheus_ignore_models" json:"prometheus_ignore_models"`
PrometheusIgnorePlatforms string `gorm:"column:prometheus_ignore_platforms;type:text" form:"prometheus_ignore_platforms" json:"prometheus_ignore_platforms"`
// Device Sync (internal/device-sync) - VRFInGlobal/DeviceStates/
// DeviceIgnore are newline-separated lists, edited as multiline boxes in
// the admin UI, same convention as Oxidized's Ignore* fields above.
// Per-device login credentials aren't here - see DeviceSyncAuth.
//
// DeviceSyncVRFInGlobal lists VRF names whose addresses are allocated in
// the global routing table on these devices (to avoid duplicate-address
// rejections in Netbox) - device-sync compares/creates addresses in
// those VRFs as if they had no VRF at all.
DeviceSyncVRFInGlobal string `gorm:"column:device_sync_vrf_in_global;type:text" form:"device_sync_vrf_in_global" json:"device_sync_vrf_in_global"`
// DeviceSyncDeviceStates lists the Netbox device status values (e.g.
// "Active") eligible for sync - a device in any other state is skipped.
DeviceSyncDeviceStates string `gorm:"column:device_sync_device_states;type:text" form:"device_sync_device_states" json:"device_sync_device_states"`
// DeviceSyncDeviceIgnore lists device names to always skip.
DeviceSyncDeviceIgnore string `gorm:"column:device_sync_device_ignore;type:text" form:"device_sync_device_ignore" json:"device_sync_device_ignore"`
// DeviceSyncVlanGroupName is the Netbox VLAN Group (global, not scoped
// to a site) that every VLAN discovered across all synced devices is
// created in, along with each interface's untagged/tagged VLAN
// assignment. Empty disables VLAN/interface-VLAN sync entirely.
DeviceSyncVlanGroupName string `` /* 129-byte string literal not displayed */
// LDAP / Active Directory authentication + authorization. Connection
// fields are edited from the admin "Authentication" page,
// LdapDefaultRoleID from the "Authorization" page - both just load/save
// this same Settings singleton, like every other integration here.
LdapEnabled *bool `gorm:"column:ldap_enabled" form:"ldap_enabled" json:"ldap_enabled"`
// LdapServerType is "ad" | "generic" (OpenLDAP-compatible). Drives
// server-specific behavior that differs between the two (e.g. how a
// password change is performed) rather than being purely cosmetic.
LdapServerType string `gorm:"column:ldap_server_type" form:"ldap_server_type" json:"ldap_server_type"`
LdapHost string `gorm:"column:ldap_host" form:"ldap_host" json:"ldap_host"`
LdapPort uint16 `gorm:"column:ldap_port" form:"ldap_port" json:"ldap_port"`
// LdapHost2/LdapPort2 are an optional second LDAP/AD server for
// redundancy. Directory operations try LdapHost first and fall back to
// LdapHost2 if it is unreachable. LdapPort2 of 0 means "same as
// LdapPort". TLS, bind DN, base DN and filters are shared - both
// servers are assumed to be replicas of the same directory.
LdapHost2 string `gorm:"column:ldap_host2" form:"ldap_host2" json:"ldap_host2"`
LdapPort2 uint16 `gorm:"column:ldap_port2" form:"ldap_port2" json:"ldap_port2"`
// LdapTLSMode is "none" | "starttls" | "ldaps".
LdapTLSMode string `gorm:"column:ldap_tls_mode" form:"ldap_tls_mode" json:"ldap_tls_mode"`
LdapSkipTLSVerify *bool `gorm:"column:ldap_skip_tls_verify" form:"ldap_skip_tls_verify" json:"ldap_skip_tls_verify"`
// LdapBindDN/LdapBindPassword are the search identity used for the
// search+bind flow (see internal/ldapauth.Authenticate) - stored in
// plaintext like every other integration credential in this struct.
// Both may be blank for an anonymous bind, which requires the
// directory to allow anonymous search under LdapBaseDN.
LdapBindDN string `gorm:"column:ldap_bind_dn" form:"ldap_bind_dn" json:"ldap_bind_dn"`
LdapBindPassword string `gorm:"column:ldap_bind_password" form:"ldap_bind_password" json:"ldap_bind_password"`
LdapBaseDN string `gorm:"column:ldap_base_dn" form:"ldap_base_dn" json:"ldap_base_dn"`
// LdapUserFilter is a fmt.Sprintf template with one %s for the escaped
// username, e.g. "(sAMAccountName=%s)" for AD or "(uid=%s)" for
// OpenLDAP.
LdapUserFilter string `gorm:"column:ldap_user_filter" form:"ldap_user_filter" json:"ldap_user_filter"`
// LdapAttrUsername is the attribute holding the login-username value
// (matched against LdapUserFilter's %s) - "sAMAccountName" for AD,
// "uid" for OpenLDAP by default. Only used by the forgot-password
// flow's LDAP-by-email lookup to auto-provision a not-yet-provisioned
// LDAP user's local row; ordinary login already knows the username
// from what was typed into the form.
LdapAttrUsername string `gorm:"column:ldap_attr_username" form:"ldap_attr_username" json:"ldap_attr_username"`
LdapAttrEmail string `gorm:"column:ldap_attr_email" form:"ldap_attr_email" json:"ldap_attr_email"`
LdapAttrDisplayName string `gorm:"column:ldap_attr_display_name" form:"ldap_attr_display_name" json:"ldap_attr_display_name"`
// LdapAttrMobile is the attribute holding the user's phone/mobile
// number, e.g. "mobile" for both AD and OpenLDAP.
LdapAttrMobile string `gorm:"column:ldap_attr_mobile" form:"ldap_attr_mobile" json:"ldap_attr_mobile"`
// LdapAttrGroups is the attribute holding group DNs on the user entry,
// e.g. "memberOf" for both AD and OpenLDAP (with the memberOf overlay).
LdapAttrGroups string `gorm:"column:ldap_attr_groups" form:"ldap_attr_groups" json:"ldap_attr_groups"`
// LdapDefaultRoleID is the fallback Role granted to an LDAP-authenticated
// user whose group DNs match no LdapRoleMapping row. Nil = no fallback.
LdapDefaultRoleID *uint `gorm:"column:ldap_default_role_id" form:"ldap_default_role_id" json:"ldap_default_role_id"`
// LdapAllowPasswordChange opts into writing a password reset back to the
// directory for LDAP-backed users (self-service "Change password" on
// the User Settings page, and the forgot-password flow) instead of
// refusing it outright. The elevated credentials that actually perform
// the directory write are NOT here - they're config-file-only
// (util.ConfigRoot.LdapWriteback), deliberately never exposed through
// this Settings row or its admin API, since they're far more powerful
// than the read-only LdapBindDN/LdapBindPassword service account above.
LdapAllowPasswordChange *bool `gorm:"column:ldap_allow_password_change" form:"ldap_allow_password_change" json:"ldap_allow_password_change"`
}
Settings is stored in database as a single row (id=1)
type Site ¶
type Site struct {
FactumModel
ParentID *uint `json:"parent_id" gorm:"index"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
Slug string `json:"slug" gorm:"type:varchar(255)"`
Source string `json:"source" gorm:"type:varchar(32)"`
NetboxKind string `json:"netbox_kind" gorm:"type:varchar(32)"`
NetboxID uint `json:"netbox_id"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
Site is one node in the Organization sites tree. NetBox regions, sites and locations all map onto this table (parented the same way they nest in NetBox); operators can also create sites here (source=factum). GPS is optional — the network map only plots rows that have coordinates.
func (Site) HasCoordinates ¶ added in v1.1.0
type SiteDTO ¶ added in v1.1.0
type SiteDTO struct {
ID uint `json:"id"`
ParentID *uint `json:"parent_id"`
Name string `json:"name"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
SiteDTO is the create/update body for /api/sites. Source/NetboxKind/ NetboxID are sync-managed and excluded so a caller cannot fake a NetBox origin or rewrite the import key.
type Tag ¶
type Tag struct {
FactumModel
DeviceID *uint `json:"device_id"`
InterfaceID *uint `json:"interface_id"`
NetboxID uint `json:"netbox_id"`
Name string `json:"name" gorm:"type:varchar(255)"`
}
Tag is shared by device-tags and interface-tags: exactly one of DeviceID/InterfaceID is set, the other is nil (SQL NULL). They are pointers rather than plain uint so the unused side is stored as NULL, not 0 -- the fk_devices_tags/fk_interfaces_tags constraints reject a literal 0 since no device/interface has id 0.
type User ¶
type User struct {
FactumModel
Username string `gorm:"uniqueIndex;not null" json:"username"`
PasswordHash string `gorm:"not null" json:"-"`
Name string `gorm:"not null" json:"name"`
Email string `json:"email"`
Mobile string `json:"mobile"`
Roles []*Role `gorm:"many2many:user_roles;;constraint:OnDelete:CASCADE;" json:"-"`
}
User represents an application user
type UserDTO ¶
type UserDTO struct {
ID uint `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
Email string `json:"email"`
Mobile string `json:"mobile"`
Roles []string `json:"roles"`
RoleIDs []uint `json:"role_ids"`
// Password is only used as input on create, and as an optional reset on update.
// It is never populated on output (the model's PasswordHash is json:"-").
Password string `json:"password,omitempty"`
}
type WorkerNode ¶
type WorkerNode struct {
FactumModel
Name string `gorm:"uniqueIndex;not null" json:"name"`
Address string `json:"address"` // host:port, dialed as wss://<Address><worker.HubPath>
Token string `json:"-"` // shared secret sent as "Authorization: Bearer <Token>"; never serialized
Enabled bool `json:"enabled"`
// TLSSkipVerify disables hub certificate verification for this node.
// The channel is still encrypted, but a MITM with any cert is accepted;
// prefer TLSCA. Intended for lab/self-signed certs whose SAN does not
// match Address.
TLSSkipVerify bool `json:"tls_skip_verify" gorm:"column:tls_skip_verify"`
// TLSCA is optional PEM used as the TLS trust root when verifying this
// node's hub certificate. Empty uses the system CA pool. Typically the
// worker's self-signed hub.crt, or an internal CA. Not a secret.
TLSCA string `json:"tls_ca" gorm:"column:tls_ca;type:text"`
}
WorkerNode is a remote factum2-worker host the primary dials out to over a WSS connection (internal/worker.RemoteManager) - the reverse of a worker dialing in, so the firewall hole is a single narrow rule on the worker host (source = primary) rather than any inbound rule on the primary. Admin-editable list, not local YAML, since it's just "who to dial", not a security boundary tied to the primary host the way an agent's own worker.commands allowlist is.
type WorkerNodeDTO ¶
type WorkerNodeDTO struct {
ID uint `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
// Token is omitempty so the frontend can leave it blank on Update to
// keep the existing value - handle_crud.go's Update loads the row
// before merging the DTO's JSON on top, so an absent key never
// overwrites the stored token (same pattern as UserDTO.Password).
Token string `json:"token,omitempty"`
Enabled bool `json:"enabled"`
TLSSkipVerify bool `json:"tls_skip_verify"`
TLSCA string `json:"tls_ca"`
}