diff --git a/CLAUDE.md b/CLAUDE.md index 36c91cc..081f9f6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,9 +15,6 @@ go build ./cmd/... go test ./... # Run tests for a specific package -go test ./pkg/toughswitch/... - -# Run a single test go test ./pkg/toughswitch/... -run TestClient_AddDel # Tidy module dependencies @@ -26,17 +23,17 @@ go mod tidy ## Architecture -This repository provides Go client libraries for interacting with Ubiquiti network devices via reverse-engineered REST APIs. +This repository provides Go client libraries for interacting with Ubiquiti network devices via reverse-engineered REST APIs, plus a CLI tool. ### Package Structure - `pkg/toughswitch/` - Client for ToughSwitch devices (e.g., TS-8-PRO) - `pkg/edgeos/` - Client for EdgeOS devices (EdgeRouter, EdgeSwitch) -- `cmd/` - Optional CLI tool using cobra (work in progress) +- `cmd/` - CLI tool using cobra -### Client Design Pattern +### Library Client Design Pattern -Both packages follow the same multi-device client pattern: +Both `pkg/toughswitch` and `pkg/edgeos` follow the same multi-device client pattern: 1. **Client** - Top-level struct holding a map of `deviceClient` instances keyed by host 2. **deviceClient** - Per-device HTTP client with authentication state (token for ToughSwitch, cookies for EdgeOS) @@ -45,16 +42,28 @@ Both packages follow the same multi-device client pattern: Key characteristics: - Thread-safe: Uses `sync.RWMutex` for device map access and `sync.Mutex` for per-device operations - Auto-login: Automatically authenticates on 401 responses and retries the request +- Explicit login: `Login(ctx, host)` can be called to pre-authenticate - Concurrent multi-device: `GetAll*` methods use `sync.WaitGroup.Go()` for parallel queries -### API Pattern - -Each package exposes: +API pattern for each package: - `MustNew(ctx, []Config)` - Constructor that accepts multiple device configs +- `Login(ctx, host)` - Explicit authentication (also happens automatically on 401) - `Add(cfg)` / `Del(host)` - Dynamic device management - `Get(ctx, host)` - Single device query - `GetAll(ctx)` - Parallel query across all devices, returns `map[string]*Resource` +### CLI Architecture (`cmd/`) + +The CLI uses cobra with a prerun chain pattern: + +- `cmd/cmd/root.go` - Root command with `PersistentPreRunE` hook +- `cmd/cmd/prerun.go` - Prerun functions executed in order: `validateConfigFile` → `prepareConfig` → `prepareLogger` → `setEnvironment` → `prepareClients` +- `cmd/cmd/client.go` - Shared `fetchDevice()` helper that retrieves clients from context +- `cmd/internal/util/context.go` - Context helpers for config, logger, and clients +- `cmd/internal/config/config.go` - Config loading from YAML/JSON files with env overlay + +Context flow: Prerun creates clients based on config and stores them in context. Commands retrieve clients via `util.ToughSwitchClientFromContext(ctx)` / `util.EdgeOSClientFromContext(ctx)`. + ### Authentication - **ToughSwitch**: Token-based via `x-auth-token` header from `/api/v1.0/user/login` diff --git a/README.md b/README.md index 8d830eb..58771ba 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ubiquiti-clients -Go client libraries for interacting with Ubiquiti network devices via their REST APIs. +Go client libraries for interacting with Ubiquiti network devices via their REST APIs, plus a CLI tool. **⚠️ Disclaimer: These libraries are based on reverse-engineered API calls. They are not official Ubiquiti products and are subject to change if the device firmware changes.** @@ -13,7 +13,7 @@ ToughSwitch POE Pro (TS-8-PRO)) via their internal REST API. #### Features -- **Authentication**: Handles login and session token management automatically. +- **Authentication**: Handles login and session token management automatically (or explicitly via `Login`). - **Multi-Device Support**: Manage multiple devices with a single client instance. - **Data Retrieval**: - **System Information**: Hostname, uptime, firmware version, etc. @@ -29,7 +29,7 @@ A client library for interacting with Ubiquiti EdgeOS devices (EdgeRouter, EdgeS #### Features -- **Authentication**: Handles login and session management automatically. +- **Authentication**: Handles login and session management automatically (or explicitly via `Login`). - **Multi-Device Support**: Manage multiple devices with a single client instance. - **Data Retrieval**: - **System Configuration**: Hostname, domain name, and other system settings. @@ -37,17 +37,70 @@ A client library for interacting with Ubiquiti EdgeOS devices (EdgeRouter, EdgeS - **VLAN Configuration**: VLAN assignments, PVID, and tagged VLANs. - **Device Information**: Model, ports, PoE capabilities, and features. -## Installation +## CLI Tool + +A command-line tool is included for quick device queries. + +### Installation + +```bash +go install gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/cmd@latest +``` + +### Configuration + +Create a config file (YAML or JSON): + +```yaml +logLevel: info +logFormat: console + +clients: + - name: switch1 + type: toughswitch + host: 192.168.1.1 + user: ubnt + pass: password + insecure: true + timeout: 10s + + - name: router1 + type: edgeos + host: 192.168.1.2 + user: ubnt + pass: password + insecure: true + timeout: 10s +``` + +Environment variables can also be used (and take priority over config file): +- `LOG_LEVEL`, `LOG_FORMAT` for top-level settings +- `CLIENT_0_NAME`, `CLIENT_0_HOST`, `CLIENT_0_TYPE`, etc. for client array + +### Usage + +```bash +# Get info from a single device +cmd --config config.yaml get device switch1 + +# Get info from all configured devices +cmd --config config.yaml get devices + +# With flags +cmd --config config.yaml get device switch1 --pretty --color +``` + +## Library Installation ```bash # For ToughSwitch -go get gitea.libretechconsulting.com/rmcguire/toughswitch-client/pkg/toughswitch +go get gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/toughswitch # For EdgeOS -go get gitea.libretechconsulting.com/rmcguire/toughswitch-client/pkg/edgeos +go get gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/edgeos ``` -## Usage +## Library Usage ### ToughSwitch Basic Example @@ -60,7 +113,7 @@ import ( "log" "time" - "gitea.libretechconsulting.com/rmcguire/toughswitch-client/pkg/toughswitch" + "gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/toughswitch" ) func main() { @@ -80,6 +133,11 @@ func main() { // Initialize the client client := toughswitch.MustNew(ctx, configs) + // Optionally pre-authenticate (otherwise happens automatically on first request) + if err := client.Login(ctx, "192.168.1.1"); err != nil { + log.Fatalf("Failed to login: %v", err) + } + // Fetch system information deviceHost := "192.168.1.1" system, err := client.GetSystem(ctx, deviceHost) @@ -116,7 +174,7 @@ import ( "log" "time" - "gitea.libretechconsulting.com/rmcguire/toughswitch-client/pkg/edgeos" + "gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/edgeos" ) func main() { @@ -136,6 +194,11 @@ func main() { // Initialize the client client := edgeos.MustNew(ctx, configs) + // Optionally pre-authenticate (otherwise happens automatically on first request) + if err := client.Login(ctx, "192.168.1.1"); err != nil { + log.Fatalf("Failed to login: %v", err) + } + // Fetch device information deviceHost := "192.168.1.1" authInfo, err := client.GetAuthInfo(ctx, deviceHost) @@ -240,6 +303,7 @@ for host, cfg := range allConfigs { | Method | Description | |--------|-------------| +| `Login` | Explicit authentication (also happens automatically on 401) | | `GetSystem` | General system configuration and status | | `GetInterfaces` | Interface configuration and status | | `GetVLANs` | VLAN and Trunk configuration | @@ -248,18 +312,19 @@ for host, cfg := range allConfigs { | `GetNeighbors` | Discovered UBNT neighbors | | `GetDevice` | Hardware and capabilities info | -All methods have corresponding `GetAll*` variants for multi-device operations. +All `Get*` methods have corresponding `GetAll*` variants for multi-device operations. ### EdgeOS | Method | Description | |--------|-------------| +| `Login` | Explicit authentication (also happens automatically on 401) | | `GetConfig` | Complete device configuration | | `GetAuthInfo` | Device authentication and feature information | | `GetInterfaces` | Interface configuration (ethernet and switch) | | `GetSystem` | System configuration (hostname, domain) | -All methods have corresponding `GetAll*` variants for multi-device operations. +All `Get*` methods have corresponding `GetAll*` variants for multi-device operations. ## License