Documentation
¶
Overview ¶
Package emu emulates UniFi devices (UAP/USW/UGW) against a real UniFi controller using the inform protocol.
Index ¶
- Constants
- type ClassicClient
- func (c *ClassicClient) Adopt(ctx context.Context, site, mac string) error
- func (c *ClassicClient) DeviceByMAC(ctx context.Context, site, mac string) (Device, error)
- func (c *ClassicClient) Login(ctx context.Context, user, pass string) error
- func (c *ClassicClient) WaitAdopted(ctx context.Context, site, mac string) (Device, error)
- type Device
- type DeviceSpec
- type DeviceState
- type Emu
- type ModelProfile
- type Option
- type PortSpec
- type RadioSpec
- type UOSClient
- func (c *UOSClient) Adopt(ctx context.Context, site, mac string) error
- func (c *UOSClient) DeviceByMAC(ctx context.Context, site, mac string) (Device, error)
- func (c *UOSClient) Login(ctx context.Context, user, pass string) error
- func (c *UOSClient) WaitAdopted(ctx context.Context, site, mac string) (Device, error)
Constants ¶
const DefaultKey = inform.DefaultKey
DefaultKey is the inform authkey of unadopted devices.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ClassicClient ¶
type ClassicClient struct {
// contains filtered or unexported fields
}
ClassicClient talks to a classic Network App controller API (:8443, cookie auth via /api/login). It exists so tests can drive an emulated device to adoption the way the controller UI does: login, devmgr adopt, then poll stat/device.
func NewClassicClient ¶
func NewClassicClient(baseURL string) *ClassicClient
NewClassicClient returns a client for the controller at baseURL.
func (*ClassicClient) Adopt ¶
func (c *ClassicClient) Adopt(ctx context.Context, site, mac string) error
Adopt issues the devmgr adopt command for mac in site, the same call the controller UI makes when the user clicks Adopt.
func (*ClassicClient) DeviceByMAC ¶
DeviceByMAC returns the stat/device doc for mac in site, or a "device not found" error when the controller does not list it.
func (*ClassicClient) Login ¶
func (c *ClassicClient) Login(ctx context.Context, user, pass string) error
Login authenticates against /api/login; the session cookie rides in the jar from then on. Non-200 (bad credentials) is an error.
func (*ClassicClient) WaitAdopted ¶
WaitAdopted polls stat/device every 2s until the device reports state 1 and adopted. On ctx timeout it returns the last seen device and an error naming it plus the last poll error, so a stalled adoption says where it stalled.
type Device ¶
type Device struct {
MAC string `json:"mac"`
State int `json:"state"` // 1=connected, 2=pending, 7=adopt-failed
Adopted bool `json:"adopted"`
Model string `json:"model"`
IP string `json:"ip"`
Name string `json:"name"`
}
Device is the subset of a stat/device document the adoption flow reads; both ClassicClient and UOSClient decode it. The documents carry many more fields; they are ignored.
type DeviceSpec ¶
type DeviceSpec struct {
MAC string `json:"mac" yaml:"mac"`
Type string `json:"type" yaml:"type"`
Model string `json:"model" yaml:"model"`
ModelDisplay string `json:"modeldisplay" yaml:"modeldisplay"`
Version string `json:"version" yaml:"version"`
Name string `json:"name" yaml:"name"`
IP string `json:"ip" yaml:"ip"`
Ports int `json:"ports" yaml:"ports"` // overrides the profile port layout when > 0
// SSIDs opts the AP into emitting vaps. Empty by default: this
// controller build rejects default vaps with log noise until a
// setstate provisions real WLAN config (the setstate echo path
// overlays vap_table), so devices inform with an empty vap_table.
SSIDs []string `json:"ssids" yaml:"ssids"`
}
DeviceSpec describes one emulated device. Type, ModelDisplay and Version default from the model profile when empty; Name defaults to "UBNT". An explicit Type must equal the profile's: the profile drives the payload shape, so a mismatched Type would describe an incoherent device and is an error, not an override.
The json/yaml tags are the fleet-file contract (unifi-emu -devices, SIM_DEVICES); keep the two families identical so either format names the same keys.
type DeviceState ¶
type DeviceState int
DeviceState is the adoption state of an emulated device.
const ( StatePending DeviceState = iota StateAdopting StateConnected )
func (DeviceState) String ¶
func (s DeviceState) String() string
type Emu ¶
type Emu struct {
// contains filtered or unexported fields
}
Emu is a fleet of emulated UniFi devices informing one controller.
func (*Emu) Add ¶
func (e *Emu) Add(specs ...DeviceSpec) error
Add validates specs and adds them to the fleet. MACs are normalized before keying, so the same device added twice errors however it was spelled. The first invalid spec aborts the call; earlier specs stay added. Add errors once Start has been called: a running fleet is fixed, and devices added after Start would never be launched.
func (*Emu) Start ¶
Start launches one inform goroutine per device, all tied to ctx. Start is one-shot: a second Start errors "emu: already started" even after Stop — that is intended, build a fresh fleet with New to restart. Starting an empty fleet errors rather than welding it shut: once started, Add rejects new devices.
func (*Emu) State ¶
func (e *Emu) State(mac string) (DeviceState, bool)
State reports the adoption state of one device, ok=false when mac is unknown to the fleet or unparseable.
type ModelProfile ¶
type ModelProfile struct {
Model string
ModelDisplay string
Type string // "ugw", "usw", "uap"
Version string
Ports []PortSpec // usw + ugw + uap (eth port)
Radios []RadioSpec // uap only
}
ModelProfile is the per-model shape the controller expects to see: identity strings plus the port/radio/SSID layout tables are built from.
type Option ¶
type Option func(*Emu)
Option customizes an Emu fleet.
func WithInformInterval ¶
WithInformInterval sets the inform interval every added device starts with. Controller responses can still retune it per device later.
type PortSpec ¶
type PortSpec struct {
IfName string
Name string
PortIdx int
Media string // "GE", "SFP+"
PoECaps int
IsUplink bool
}
PortSpec is one switch/gateway/ethernet port in a model's layout.
type RadioSpec ¶
type RadioSpec struct {
Name string // "wifi-ng", "wifi-na"
Radio string // "ng", "na"
Channel int
HT string // "20", "40"
MinTxPower int
MaxTxPower int
NSS int
RadioCaps int
AntennaGain int
}
RadioSpec is one wireless radio in an AP model's layout.
type UOSClient ¶
type UOSClient struct {
// contains filtered or unexported fields
}
UOSClient talks to a UniFi OS controller through the ucore proxy (:443). Login at /api/auth/login yields a session cookie plus a CSRF token in the x-updated-csrf-token response header, and every call under /proxy/network must carry that token in X-CSRF-Token or ucore answers 403. The token rotates mid-session; the transport follows the rotation (see csrfSniffer). The Network App API behind the proxy is the classic one, so the paths below mirror ClassicClient's under the /proxy/network prefix.
func NewUOSClient ¶
NewUOSClient returns a client for the UniFi OS controller at baseURL; see newSessionClient for the TLS and timeout rationale.
func (*UOSClient) Adopt ¶
Adopt issues the devmgr adopt command for mac in site through the proxy, the same call the Network App UI makes when the user clicks Adopt.
func (*UOSClient) DeviceByMAC ¶
DeviceByMAC returns the stat/device doc for mac in site, or a "device not found" error when the controller does not list it.
func (*UOSClient) Login ¶
Login authenticates against /api/auth/login. The session cookie rides in the jar; the CSRF token comes back in the x-updated-csrf-token response header. A 200 without that header is still an error: without the token every proxied call would 403, so a tokenless login is no login.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
modelgen
command
Command modelgen reduces an adopted UniFi simulation fleet to the model facts used by the emulator and generates the corresponding Go registry.
|
Command modelgen reduces an adopted UniFi simulation fleet to the model facts used by the emulator and generates the corresponding Go registry. |
|
unifi-emu
command
Command unifi-emu runs a fleet of emulated UniFi devices informing a real controller until interrupted.
|
Command unifi-emu runs a fleet of emulated UniFi devices informing a real controller until interrupted. |
|
Package inform implements the UniFi inform wire protocol: the TNBU binary packet, AES-128-CBC/GCM encryption, and zlib/snappy compression.
|
Package inform implements the UniFi inform wire protocol: the TNBU binary packet, AES-128-CBC/GCM encryption, and zlib/snappy compression. |