μNet Documentation
Welcome to μNet - A modern network configuration management system for documenting topology, monitoring compliance, and automating operations.
🚀 New to μNet?
→ Quick Start Guide - Get μNet running in 10 minutes
→ What is μNet? - Learn about features and use cases
📖 User Guides
Choose your path based on how you'll use μNet:
For Network Operators
- CLI Reference - Complete command documentation
- Policy Guide - Write compliance rules and automation
- Troubleshooting - Common issues and solutions
For Developers & Integrators
- API Reference - HTTP API for automation and integration
- Architecture - System design and components
For Project Planning
- Roadmap - Current features and future plans
🎯 Common Tasks
Just getting started? → Quick Start Guide → CLI Reference
Setting up compliance monitoring? → Policy Guide → Troubleshooting
Building integrations? → API Reference → Architecture
Having issues? → Troubleshooting → CLI Reference
📋 Examples & Resources
- API Reference - Complete HTTP API documentation
- GitHub Repository - Source code and issue tracking
- Release Notes - Latest features and changes
💬 Getting Help
Found a bug or need a feature?
Open an issue on GitHub
Questions about usage?
Check Troubleshooting or browse the complete documentation
Want to contribute?
See the Architecture Guide and GitHub repository
μNet v0.1.0 - Built with ❤️ in Rust
📖 Full documentation: https://unet.bedecarroll.com
Introduction to μNet
μNet (pronounced "micro-net") is a network configuration management system that helps you document, monitor, and automate your network infrastructure.
What Problems Does μNet Solve?
📋 Network Documentation Chaos
- Problem: Network topology scattered across spreadsheets, diagrams, and tribal knowledge
- Solution: Centralized device inventory with relationships, locations, and lifecycle tracking
🔍 Configuration Drift
- Problem: Devices gradually drift from standards without detection
- Solution: Declarative policies that continuously check compliance
🔧 Manual Operations
- Problem: Repetitive configuration tasks prone to human error
- Solution: Automated actions triggered by policy rules
📊 Lack of Visibility
- Problem: Limited insight into device status and performance
- Solution: Real-time SNMP monitoring with historical tracking
Core Concepts
Devices & Topology
μNet models your network as Nodes (devices), Links (connections), and Locations (physical sites):
Campus
├── Building A
│ ├── Floor 1
│ │ └── Rack 1
│ │ ├── core-01 (Core Router)
│ │ └── dist-01 (Distribution Switch)
│ └── Floor 2
└── Building B
Policy-Driven Compliance
Define network standards as declarative rules:
# Ensure production devices are monitored
WHEN node.lifecycle == "Production"
THEN SET custom_data.monitoring_enabled TO true
# Cisco devices should use SNMPv3
WHEN node.vendor == "Cisco"
THEN ASSERT custom_data.snmp_version == "v3"
Real-Time Monitoring
μNet polls your devices via SNMP to collect:
- System information (uptime, description, contact)
- Interface status and statistics
- Performance metrics (CPU, memory, temperature)
- Custom vendor-specific data
Key Features
✅ What μNet Does Today (v0.1.0)
- Complete Device Management: Add, update, and organize network devices
- Topology Mapping: Document connections and physical locations
- Policy Engine: Write and evaluate compliance rules
- SNMP Monitoring: Real-time device status collection
- REST API: Full HTTP API for automation
- Rich CLI: Command-line interface with multiple output formats
- Data Import/Export: Bulk operations for network data
🚧 In Development
- Background SNMP Integration: Automatic device polling and database updates
- API Completeness: Full implementation of location/link endpoints
- Derived State Tracking: Historical device status and metrics
🔮 Future Planned Features
- Configuration Templates: Generate device configs from templates (NOT STARTED)
- Historical Analytics: Time-series data and trend analysis (NOT STARTED)
- Configuration Push: Deploy generated configs to devices (NOT STARTED)
- Advanced Alerting: Notifications for policy violations (NOT STARTED)
Architecture Overview
μNet consists of three main components:
┌─────────────┐ HTTP/JSON ┌─────────────┐
│ unet-cli │ ◄──────────────► │ unet-server │
│ │ │ │
│ • Commands │ │ • REST API │
│ • Local DB │ │ • SNMP Poll │
│ • Policies │ │ • Policies │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────┐
│ SQLite Database │
│ • Devices • Links • Locations • Status │
└─────────────────────────────────────────────┘
Design Principles:
- Single Binary: No external dependencies, easy deployment
- SQLite Backend: Zero-ops database for up to 10K+ devices
- API-First: Everything available via HTTP API
- Incremental Adoption: Start small, grow capabilities over time
Use Cases
Network Documentation
- Device Inventory: Comprehensive database of all network equipment
- Topology Mapping: Visual representation of network connections
- Lifecycle Tracking: Manage devices from planning to decommission
- Change Auditing: Track modifications and policy compliance
Compliance Monitoring
- Security Standards: Ensure devices meet security baselines
- Configuration Validation: Check for required settings and features
- Vendor Consistency: Enforce consistent configurations by vendor
- Lifecycle Policies: Different rules for production vs. staging
Operational Automation
- Bulk Updates: Apply changes across multiple devices
- Automated Validation: Continuous compliance checking
- Integration Workflows: Connect with existing automation tools
- Reporting: Generate compliance and inventory reports
Getting Started
Ready to try μNet?
- Quick Start Guide - Get running in 10 minutes
- CLI Reference - Learn the commands
- Policy Guide - Write your first compliance rules
Questions? Check the Troubleshooting Guide or open an issue.
Why Choose μNet?
Built for Network Engineers
- Domain-specific: Designed for network operations, not generic IT
- Practical: Solves real daily challenges network teams face
- Flexible: Adapt to your existing processes and tools
Modern Technology
- Rust Performance: Fast, memory-safe, reliable
- Simple Deployment: Single binary, SQLite database
- API-First: Easy integration with existing tools
Open Source
- MIT/Apache License: Use freely in commercial environments
- Active Development: Regular releases with new features
- Community Driven: Contributions and feedback welcome
Next: Quick Start Guide →
Quick Start Guide – Getting Started with μNet
Goal: Get μNet running and managing your first network devices in 10 minutes
Installation
Build from Source
Note: μNet is currently in active development. Pre-built releases are not yet available. You must build from source.
git clone https://github.com/bedecarroll/unet.git
cd unet
cargo build --release
cp target/release/unet-cli ./unet
cp target/release/unet-server ./unet-server
Quick Setup
1. Initialize Database
μNet will automatically create a SQLite database on first use:
./unet nodes list
# Creates unet.db in current directory
Managing Vendors
Common vendors are seeded automatically. Manage them using the CLI:
# List vendors
unet vendors list
# Add a vendor
unet vendors add CustomVendor
# Remove a vendor
unet vendors delete CustomVendor
2. Create Sample Data
Note: Pre-built example files are not yet available. You can create sample data manually:
# Create a location
./unet locations create --name "Datacenter" --type "datacenter" --description "Main datacenter"
# Create a node
./unet nodes create --name "core-01" --type "Router" --vendor "Cisco" --model "ISR4321" --location "Datacenter"
# List your data
./unet nodes list
./unet locations list
Basic Operations
Managing Nodes
# Add a new device
./unet nodes add \
--name core-sw-01 \
--domain corp.example.com \
--vendor cisco \
--model catalyst9300 \
--role access \
--lifecycle production \
--management-ip 192.168.1.10
# List all devices
./unet nodes list
# Show device details
./unet nodes show core-sw-01
# Update device
./unet nodes update core-sw-01 --lifecycle production
# Delete device
./unet nodes delete core-sw-01
Managing Locations
# Add a location
./unet locations add \
--name "Building A" \
--location-type building \
--address "123 Main Street"
# List locations
./unet locations list
# Show location details
./unet locations show "Building A"
Managing Links
# Create a point-to-point link
./unet links add \
--node-a core-sw-01 \
--interface-a GigE0/0/1 \
--node-z dist-sw-01 \
--interface-z GigE1/0/24 \
--bandwidth 1000000000
# Create an internet circuit
./unet links add \
--node-a edge-rtr-01 \
--interface-a GigE0/0/0 \
--circuit-id "ISP-CIRCUIT-12345"
# List links
./unet links list
Working with Policies
1. Create Your First Policy
Create a file called network-standards.rules:
# Ensure all production devices are monitored
WHEN node.lifecycle == "Production"
THEN SET custom_data.monitoring_enabled TO true
# Cisco devices should use SNMPv3
WHEN node.vendor == "Cisco"
THEN SET custom_data.snmp_version TO "v3"
# Core devices need redundancy
WHEN node.role == "Core"
THEN ASSERT custom_data.redundancy_configured IS true
2. Validate and Run Policies
# Check syntax
./unet policy validate network-standards.rules
# Evaluate against all nodes
./unet policy eval network-standards.rules
# Show only failures
./unet policy eval network-standards.rules --failures-only
Using the HTTP Server
1. Start the Server
# Start server on default port (8080)
./unet-server
# Or specify custom settings
./unet-server --host 0.0.0.0 --port 8080 --database-url sqlite://network.db
2. Use CLI with Remote Server
# Set server URL
export UNET_SERVER=http://localhost:8080
# Now CLI commands use the server
./unet nodes list
./unet policy eval network-standards.rules
3. Use the API Directly
# List nodes via API
curl http://localhost:8080/api/v1/nodes
# Create a node via API
curl -X POST http://localhost:8080/api/v1/nodes \
-H "Content-Type: application/json" \
-d '{
"name": "new-device",
"vendor": "Cisco",
"model": "ISR4331",
"role": "Edge",
"lifecycle": "Staging"
}'
# Evaluate policies via API
curl -X POST http://localhost:8080/api/v1/policies/evaluate
Output Formats
μNet supports multiple output formats for different use cases:
# Human-readable table (default for terminal)
./unet nodes list
# JSON for automation
./unet nodes list --output json
# YAML for readability
./unet nodes list --output yaml
# Pipe to other tools
./unet nodes list --output json | jq '.data.data[].name'
Common Workflows
Network Discovery Documentation
# 1. Document your physical sites
./unet locations add --name "HQ Campus" --location-type campus
./unet locations add --name "Main Building" --location-type building --parent-id <campus-id>
# 2. Add your network devices
./unet nodes add --name core-01 --vendor cisco --model asr9000 --role core
./unet nodes add --name dist-01 --vendor cisco --model catalyst9400 --role distribution
# 3. Document connections
./unet links add --node-a core-01 --interface-a TenGigE0/0/0/1 \
--node-z dist-01 --interface-z TenGigE1/0/1
# 4. Export for backup
./unet export --output-dir backup/
Compliance Monitoring
# 1. Create compliance policies
cat > compliance.rules << 'EOF'
WHEN node.lifecycle == "Production" THEN ASSERT custom_data.backup_configured IS true
WHEN node.role == "Core" THEN ASSERT custom_data.redundancy_level >= 2
WHEN node.vendor == "Cisco" THEN ASSERT custom_data.snmp_version == "v3"
EOF
# 2. Run compliance check
./unet policy eval compliance.rules --failures-only
# 3. Generate compliance report
./unet policy eval compliance.rules --output json > compliance-report.json
Data Migration
# Export from existing system
./unet export --output-dir migration/
# Edit exported files as needed
# ...
# Import to new environment
./unet import migration/ --dry-run # Test first
./unet import migration/ # Actually import
Configuration
Environment Variables
# Database location
export UNET_DATABASE_URL="sqlite:///path/to/unet.db"
# Server URL for remote operations
export UNET_SERVER="http://unet-server:8080"
# Default output format
export UNET_OUTPUT_FORMAT="json"
Configuration File
Create ~/.config/unet/config.toml:
[defaults]
database_url = "sqlite:///home/user/network/unet.db"
server_url = "http://unet-server:8080"
output_format = "table"
[logging]
level = "info"
Next Steps
Now that you have μNet running:
- Read the CLI Reference for complete command documentation
- Study the Policy Guide for advanced policy authoring
- Explore the API Reference for automation integration
- Review the Architecture Overview to understand the system design
Common Next Actions
- Scale Up: Import your real network topology
- Automate: Integrate with your CI/CD pipeline
- Monitor: Set up continuous policy evaluation
- Extend: Use the API to build custom integrations
Getting Help
- Troubleshooting: See Troubleshooting Guide
- CLI Reference: See complete command documentation
- Issues: Report bugs at https://github.com/bedecarroll/unet/issues
Welcome to μNet! 🎉
Troubleshooting Guide – Common Issues and Solutions
Audience: Users experiencing problems with μNet
Status: Covers current implementation (v0.1.0)
Common CLI Issues
Command Not Found
Problem: unet: command not found
Solutions:
# 1. Check if binary exists and is executable
ls -la unet
chmod +x unet
# 2. Use full path
./unet nodes list
# 3. Add to PATH
export PATH=$PATH:$(pwd)
# Or move to system path
sudo mv unet /usr/local/bin/
Database Connection Errors
Problem: Failed to connect to database or Database locked
Solutions:
# 1. Check database file permissions
ls -la unet.db
chmod 644 unet.db
# 2. Ensure directory is writable
ls -la .
# Directory should be writable by current user
# 3. Try different database location
unet --database-url sqlite:///tmp/test.db nodes list
# 4. Check for zombie processes
ps aux | grep unet
# Kill any stuck processes: kill <pid>
Validation Errors
Problem: Invalid input or Validation failed
Solutions:
# 1. Check required fields
unet nodes add --help
# 2. Verify enum values
# Vendor: Cisco, Juniper, Arista, HPE, Dell, etc.
# Role: Core, Distribution, Access, Edge, etc.
# Lifecycle: Planning, Staging, Production, etc.
# 3. Check IP address format
unet nodes add --name test --vendor cisco --model test \
--role access --lifecycle staging \
--management-ip 192.168.1.1 # Valid IP format
# 4. Validate UUID format for location-id
unet locations list # Get valid UUID
Server Issues
Server Won't Start
Problem: Server fails to start or crashes immediately
Solutions:
# 1. Check port availability
netstat -an | grep 8080
# Or try different port
unet-server --port 8081
# 2. Check database access
ls -la unet.db
# Ensure server has read/write access
# 3. Verbose logging
unet-server --log-level debug
# 4. Check disk space
df -h .
# Ensure adequate space for database
Server Connection Refused
Problem: Connection refused when accessing API
Solutions:
# 1. Verify server is running
ps aux | grep unet-server
# 2. Check server logs
unet-server --log-level info
# 3. Test local connection
curl http://localhost:8080/health
# 4. Check firewall rules
# For systemd/firewalld:
sudo firewall-cmd --add-port=8080/tcp
# 5. Bind to all interfaces if needed
unet-server --host 0.0.0.0 --port 8080
API Errors
Problem: HTTP 500 errors or unexpected API responses
Solutions:
# 1. Check server logs
unet-server --log-level debug
# 2. Validate request format
curl -X POST http://localhost:8080/api/v1/nodes \
-H "Content-Type: application/json" \
-d '{"name":"test","vendor":"Cisco","model":"test","role":"Access","lifecycle":"Staging"}'
# 3. Check database state
sqlite3 unet.db ".tables"
sqlite3 unet.db "SELECT COUNT(*) FROM nodes;"
# 4. Restart server
pkill unet-server
unet-server
Policy Issues
Policy Syntax Errors
Problem: Policy validation failed or Parse error
Solutions:
# 1. Check basic syntax
cat > test.rules << 'EOF'
WHEN node.vendor == "Cisco" THEN SET custom_data.test TO true
EOF
unet policy validate test.rules
# 2. Common syntax fixes:
# - Use quotes around strings: "Cisco" not Cisco
# - Include THEN keyword: WHEN ... THEN ...
# - Check field names: node.vendor not node.brand
# 3. Use verbose validation
unet policy validate policies/ --verbose
# 4. Test with simple policy first
echo 'WHEN true THEN SET custom_data.test TO true' > simple.rules
unet policy validate simple.rules
Policy Evaluation Failures
Problem: Policies don't trigger or produce unexpected results
Solutions:
# 1. Check if nodes exist
unet nodes list
# 2. Verify field values
unet nodes show node-name --output json | jq '.data.vendor'
# 3. Test with verbose output
unet policy eval policies/ --verbose
# 4. Test specific node
unet policy eval policies/ --node specific-node-name
# 5. Check custom_data structure
unet nodes show node-name --output json | jq '.data.custom_data'
Policy Results Not Stored
Problem: Policy evaluation runs but results aren't saved
Solutions:
# 1. Check API endpoint
curl -X POST http://localhost:8080/api/v1/policies/evaluate \
-H "Content-Type: application/json" \
-d '{"store_results": true, "policies": [...]}'
# 2. Verify database tables
sqlite3 unet.db ".schema policy_results"
# 3. Check server permissions
ls -la unet.db
# Server needs write access
Data Issues
Import Failures
Problem: Import failed or partial imports
Solutions:
# 1. Validate JSON format
cat nodes.json | jq .
# Should show pretty-printed JSON without errors
# 2. Check required fields
cat > minimal-node.json << 'EOF'
{
"name": "test-node",
"vendor": "Cisco",
"model": "test",
"role": "Access",
"lifecycle": "Staging"
}
EOF
unet import minimal-node.json
# 3. Use dry-run to check
unet import data/ --dry-run
# 4. Continue on errors
unet import data/ --continue-on-error
# 5. Import in dependency order
unet import locations.json
unet import nodes.json
unet import links.json
Export Issues
Problem: Export produces empty files or fails
Solutions:
# 1. Check data exists
unet nodes list
unet locations list
# 2. Ensure output directory exists
mkdir -p exports/
unet export --output-dir exports/
# 3. Check permissions
ls -la exports/
# Directory should be writable
# 4. Try different format
unet export --output-dir exports/ --format yaml
# 5. Export specific types
unet export --output-dir exports/ --only nodes
Performance Issues
Slow CLI Commands
Problem: Commands take a long time to execute
Solutions:
# 1. Check database size
ls -lh unet.db
# 2. Use pagination for large datasets
unet nodes list --page 1 --per-page 20
# 3. Add indexes (for large datasets)
sqlite3 unet.db "CREATE INDEX idx_nodes_vendor ON nodes(vendor);"
# 4. Manually create vendor records
unet vendors add ExampleCorp
unet vendors delete ExampleCorp
# 5. Use specific filters
unet nodes list --vendor cisco --role core
# 6. Consider using server mode
unet-server &
export UNET_SERVER=http://localhost:8080
unet nodes list # Now uses HTTP API
Memory Usage Issues
Problem: High memory usage or out-of-memory errors
Solutions:
# 1. Monitor memory usage
ps aux | grep unet | awk '{print $6}' # RSS memory in KB
# 2. Use pagination
unet nodes list --per-page 50
# 3. Limit data returned
unet nodes list --output json | jq '.data.data | length'
# 4. Process in batches
for page in {1..10}; do
unet nodes list --page $page --per-page 100 --output json
done
Network/SNMP Issues
SNMP Polling Failures
Problem: Node status shows as unreachable or no SNMP data
Solutions:
# 1. Check node has management IP
unet nodes show node-name | grep management_ip
# 2. Test SNMP connectivity manually
snmpget -v2c -c public 192.168.1.1 1.3.6.1.2.1.1.1.0
# 3. Check server logs for SNMP errors
unet-server --log-level debug | grep -i snmp
# 4. Verify SNMP configuration on device
# Ensure device has SNMP enabled with proper community/credentials
# 5. Check network connectivity
ping 192.168.1.1
telnet 192.168.1.1 161 # SNMP port
Missing Derived State
Problem: Node status or interface data is empty
Solutions:
# 1. Check if SNMP polling is enabled
curl http://localhost:8080/api/v1/nodes/node-id/status
# 2. Verify management IP is set
unet nodes update node-name --management-ip 192.168.1.1
# 3. Check SNMP credentials (when implemented)
# Currently uses default community "public"
# 4. Monitor polling in server logs
unet-server --log-level debug | grep -i "snmp\|polling"
# 5. Check device SNMP configuration
# Ensure device responds to SNMP queries
Development Issues
Build Failures
Problem: cargo build fails
Solutions:
# 1. Update Rust toolchain
rustup update
rustc --version # Should be 1.85+
# 2. Clean build cache
cargo clean
cargo build --release
# 3. Check dependencies
cargo check --workspace
# 4. Update dependencies
cargo update
# 5. Check specific feature flags
cargo build --no-default-features
Test Failures
Problem: cargo test fails
Solutions:
# 1. Run specific test
cargo test test_name
# 2. Run with output
cargo test -- --nocapture
# 3. Test specific package
cargo test -p unet-core
# 4. Clean test databases
rm -f test_*.db
# 5. Check for port conflicts
# Tests may use random ports, conflicts are rare
Configuration Issues
Environment Variables Not Working
Problem: Environment variables ignored
Solutions:
# 1. Check variable names
echo $UNET_DATABASE_URL
echo $UNET_SERVER
# 2. Export variables properly
export UNET_DATABASE_URL="sqlite:///path/to/db"
# 3. Use command line flags instead
unet --database-url sqlite:///path/to/db nodes list
# 4. Check precedence order
# CLI flags > Environment variables > Config file > Defaults
Config File Issues
Problem: Configuration file not loaded
Solutions:
# 1. Check file location
ls -la ~/.config/unet/config.toml
ls -la ./config.toml
# 2. Validate TOML syntax
cat config.toml | toml verify # If you have toml CLI tool
# 3. Use explicit config path
unet --config /path/to/config.toml nodes list
# 4. Check file permissions
chmod 644 config.toml
Log Analysis
Enable Debug Logging
# CLI
unet --verbose nodes list
# Server
unet-server --log-level debug
# Via environment
export UNET_LOG_LEVEL=debug
Common Log Patterns
# Database issues
grep -i "database\|sqlite\|sea_orm" unet.log
# SNMP issues
grep -i "snmp\|poll" unet.log
# Policy issues
grep -i "policy\|eval" unet.log
# HTTP issues
grep -i "http\|api\|request" unet.log
Getting More Help
Diagnostic Information
When reporting issues, include:
# 1. Version information
unet --version
unet-server --version
# 2. System information
uname -a
rustc --version
# 3. Database information
ls -la unet.db
sqlite3 unet.db ".schema" | head -20
# 4. Sample data
unet nodes list --output json | head -50
# 5. Error logs
unet --verbose nodes list 2>&1 | tail -50
Minimal Reproduction
Create minimal test case:
# 1. Fresh database
rm -f test.db
unet --database-url sqlite://test.db nodes list
# 2. Minimal data
echo '{"name":"test","vendor":"Cisco","model":"test","role":"Access","lifecycle":"Staging"}' > test-node.json
unet --database-url sqlite://test.db import test-node.json
# 3. Reproduce issue
unet --database-url sqlite://test.db nodes show test
Community Support
- GitHub Issues: https://github.com/bedecarroll/unet/issues
- Documentation: https://unet.bedecarroll.com
- CLI Reference: See complete command documentation
Self-Help Resources
- CLI Help:
unet --help,unet nodes --help - API Documentation: API Reference
- Policy Guide: Policy Guide
- Architecture: Architecture Overview
CLI Reference – μNet Command Line Tool
Audience: Users and operators working with μNet daily
Status: Documents implemented commands only (v0.1.0)
Overview
μNet provides a comprehensive command-line interface for network configuration management. The CLI supports local SQLite and remote (HTTP API) operation modes.
Binary Name: unet
Current Version: 0.1.0
Source: crates/unet-cli/
Quick Start
# Local SQLite mode (default)
unet nodes list
# Remote server mode
unet --server http://localhost:8080 nodes list
# Import sample data (create your own JSON files)
unet import your-locations.json
unet import your-nodes.json
unet import your-links.json
Global Options
| Option | Environment Variable | Default | Description |
|---|---|---|---|
-c, --config <FILE> | UNET_CONFIG | - | Configuration file path |
-d, --database-url <URL> | UNET_DATABASE_URL | sqlite://unet.db | Database connection URL |
-s, --server <URL> | UNET_SERVER | - | Server URL for remote operations |
-t, --token <TOKEN> | UNET_TOKEN | - | Authentication token |
-f, --output <FORMAT> | - | table | Output format: table, json, yaml |
-v, --verbose | - | - | Enable verbose logging |
Commands
Node Management
unet nodes add
Create a new network device.
unet nodes add --name router-01 --domain example.com --vendor cisco --model ISR4431 --role router --lifecycle live
Required Options:
--name <NAME>- Device hostname--domain <DOMAIN>- DNS domain--vendor <VENDOR>- Device vendor (cisco, juniper, arista, fortinet, paloalto, checkpoint, other)--model <MODEL>- Device model--role <ROLE>- Device role (router, switch, firewall, load-balancer, wireless-controller, other)--lifecycle <STATE>- Lifecycle state (planned, implementing, live, decommissioned)
Optional Options:
--management-ip <IP>- Management IP address--location-id <UUID>- Location UUID--custom-data <JSON>- Additional data as JSON string
unet nodes list
List all nodes with optional filtering.
unet nodes list
unet nodes list --vendor cisco --role router
unet nodes list --lifecycle live --page 1 --per-page 20
Options:
--vendor <VENDOR>- Filter by vendor--role <ROLE>- Filter by role--lifecycle <STATE>- Filter by lifecycle--page <NUM>- Page number (default: 1)--per-page <NUM>- Items per page (default: 50)
unet nodes show
Display detailed information about a specific node.
unet nodes show router-01
unet nodes show --include-status --show-interfaces router-01
Arguments:
<NODE_ID>- Node name or UUID
Options:
--include-status- Include node status from SNMP polling--show-interfaces- Show interface status--show-system-info- Show system information
unet nodes update
Update node properties.
unet nodes update router-01 --model ISR4451 --lifecycle live
unet nodes update router-01 --management-ip 192.168.1.1
Arguments:
<NODE_ID>- Node name or UUID
Options:
--name <NAME>- Update hostname--domain <DOMAIN>- Update domain--vendor <VENDOR>- Update vendor--model <MODEL>- Update model--role <ROLE>- Update role--lifecycle <STATE>- Update lifecycle--management-ip <IP>- Update management IP--location-id <UUID>- Update location--custom-data <JSON>- Update custom data
unet nodes delete
Remove a node from the system.
unet nodes delete router-01
unet nodes delete router-01 --yes # Skip confirmation
Arguments:
<NODE_ID>- Node name or UUID
Options:
--yes- Skip confirmation prompt
unet nodes status
Show current status information for a node.
unet nodes status router-01
unet nodes status router-01 --show-interfaces --show-system-info
Arguments:
<NODE_ID>- Node name or UUID
Options:
--show-interfaces- Include interface status--show-system-info- Include system information
unet nodes metrics
Display current metrics for a node.
unet nodes metrics router-01
Arguments:
<NODE_ID>- Node name or UUID
Note: Historical metrics are not yet implemented.
Location Management
unet locations add
Create a new location.
unet locations add --name "Building A" --location-type building --address "123 Main St"
Required Options:
--name <NAME>- Location name--location-type <TYPE>- Type: campus, building, floor, room, rack
Optional Options:
--parent-id <UUID>- Parent location UUID--address <ADDRESS>- Physical address--custom-data <JSON>- Additional data as JSON
unet locations list
List all locations.
unet locations list
unet locations list --location-type building
Options:
--location-type <TYPE>- Filter by location type--page <NUM>- Page number--per-page <NUM>- Items per page
unet locations show
Display detailed location information.
unet locations show "Building A"
Arguments:
<LOCATION_ID>- Location name or UUID
unet locations update
Update location properties.
unet locations update "Building A" --address "456 New St"
Arguments:
<LOCATION_ID>- Location name or UUID
Options:
--name <NAME>- Update name--location-type <TYPE>- Update type--parent-id <UUID>- Update parent--address <ADDRESS>- Update address--custom-data <JSON>- Update custom data
unet locations delete
Remove a location.
unet locations delete "Building A"
Arguments:
<LOCATION_ID>- Location name or UUID
Options:
--yes- Skip confirmation prompt
Link Management
unet links add
Create a connection between nodes.
# Point-to-point link
unet links add --node-a router-01 --interface-a GigE0/0/0 --node-z switch-01 --interface-z GigE1/0/1
# Internet circuit (no node-z)
unet links add --node-a router-01 --interface-a GigE0/0/1 --circuit-id "ISP-12345"
Required Options:
--node-a <NODE>- First node name/UUID--interface-a <INTERFACE>- Interface on first node
For Point-to-Point Links:
--node-z <NODE>- Second node name/UUID--interface-z <INTERFACE>- Interface on second node
For Internet Circuits:
--circuit-id <ID>- Circuit identifier
Optional Options:
--bandwidth <BPS>- Link bandwidth in bits per second--custom-data <JSON>- Additional data as JSON
unet links list
List all links.
unet links list
unet links list --node-a router-01
Options:
--node-a <NODE>- Filter by first node--node-z <NODE>- Filter by second node--page <NUM>- Page number--per-page <NUM>- Items per page
unet links show
Display detailed link information.
unet links show <LINK_UUID>
Arguments:
<LINK_ID>- Link UUID
unet links update
Update link properties.
unet links update <LINK_UUID> --bandwidth 10000000000
Arguments:
<LINK_ID>- Link UUID
Options:
--bandwidth <BPS>- Update bandwidth--custom-data <JSON>- Update custom data
unet links delete
Remove a link.
unet links delete <LINK_UUID>
Arguments:
<LINK_ID>- Link UUID
Options:
--yes- Skip confirmation prompt
Policy Management
unet policy validate
Validate policy file syntax.
unet policy validate policies/compliance.rules
unet policy validate policies/ --verbose
Arguments:
<PATH>- Policy file or directory path
Options:
--verbose- Show detailed rule information
unet policy eval
Evaluate policies against nodes.
unet policy eval policies/compliance.rules
unet policy eval policies/ --verbose --failures-only
Arguments:
<PATH>- Policy file or directory path
Options:
--verbose- Show detailed evaluation results--failures-only- Only show policy failures--node <NODE>- Evaluate against specific node
unet policy list
List available policy files.
unet policy list policies/
Arguments:
<DIRECTORY>- Policy directory path
unet policy show
Display policy file contents and parsed rules.
unet policy show policies/compliance.rules
unet policy show policies/compliance.rules --ast
Arguments:
<FILE>- Policy file path
Options:
--ast- Show parsed abstract syntax tree
Data Import/Export
unet import
Import data from JSON files.
unet import your-nodes.json
unet import your-data-directory/ --dry-run
unet import your-data-directory/ --continue-on-error
Arguments:
<PATH>- JSON file or directory path
Options:
--dry-run- Show what would be imported without making changes--continue-on-error- Continue importing even if some items fail
unet export
Export data to JSON/YAML files.
unet export --output-dir exports/
unet export --output-dir exports/ --format yaml --only nodes
Options:
--output-dir <DIR>- Output directory (required)--format <FORMAT>- Export format: json, yaml (default: json)--only <TYPE>- Export only specific type: nodes, links, locations--force- Overwrite existing files
Output Formats
Table Format (Default)
Human-readable tabular output with colors when outputting to terminal.
unet nodes list
JSON Format
Machine-readable JSON output.
unet nodes list --output json
YAML Format
Human-readable YAML output.
unet nodes list --output yaml
Configuration
Configuration File
μNet can load settings from a configuration file:
unet --config /path/to/config.toml nodes list
Environment Variables
Set environment variables to avoid repeating common options:
export UNET_DATABASE_URL="sqlite:///path/to/unet.db"
export UNET_SERVER="http://localhost:8080"
export UNET_TOKEN="your-auth-token"
Error Codes
| Exit Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Configuration error |
| 3 | Network/connection error |
| 4 | Authentication error |
| 5 | Data validation error |
Examples
Basic Network Setup
# Create locations
unet locations add --name "HQ Campus" --location-type campus --address "123 Business Park"
unet locations add --name "Main Building" --location-type building --parent-id <campus-uuid>
# Create nodes
unet nodes add --name core-01 --domain corp.example.com --vendor cisco --model ASR9000 \
--role router --lifecycle live --management-ip 10.1.1.1
unet nodes add --name dist-01 --domain corp.example.com --vendor cisco --model Catalyst9400 \
--role switch --lifecycle live --management-ip 10.1.1.2
# Create link
unet links add --node-a core-01 --interface-a TenGigE0/0/0/1 \
--node-z dist-01 --interface-z TenGigE1/0/1 --bandwidth 10000000000
# View the topology
unet nodes list
unet links list
Policy Validation
# Validate policy syntax
unet policy validate policies/security.rules
# Check compliance
unet policy eval policies/ --failures-only
# Evaluate specific node
unet policy eval policies/compliance.rules --node core-01
Data Management
# Export current configuration
unet export --output-dir backup/ --format yaml
# Import from backup
unet import backup/nodes.yaml --dry-run
unet import backup/
Limitations (Current Version)
- Template engine: Not yet implemented (planned for v0.2.0)
- SNMP polling controls: Background polling runs automatically, but CLI controls are not implemented
- Node comparison and history: Planned for future versions
- Table output formatting: Currently defaults to JSON format
- Advanced filtering: jq-style filters not yet implemented
For planned features, see the Roadmap.
Policy Guide – Network Compliance and Automation
Audience: Network engineers and operators writing policy rules
Status: Documents implemented policy engine (v0.1.0)
Overview
μNet's policy engine enables declarative network compliance checking and automated data management through a simple Domain Specific Language (DSL). Policies help ensure your network configuration meets organizational standards and automatically apply corrective actions.
Key Benefits:
- Declarative Rules: Write what you want, not how to achieve it
- Real-time Compliance: Continuous evaluation of network state
- Automated Actions: Reduce manual configuration tasks
- Audit Trail: Track policy execution and compliance status
Quick Start
Your First Policy
Create a file called basic-compliance.rules:
WHEN node.vendor == "Cisco" THEN ASSERT custom_data.snmp_configured IS true
Test it:
unet policy validate basic-compliance.rules
unet policy eval basic-compliance.rules
This policy ensures all Cisco devices have SNMP configured.
Policy Language Syntax
Basic Structure
Every policy rule follows this pattern:
WHEN <condition> THEN <action>
- WHEN: Introduces the condition that triggers the action
- Condition: Boolean expression evaluated against node data
- THEN: Separates condition from action
- Action: Operation to perform when condition is true
Example Policy Rule
WHEN node.vendor == "Cisco" AND node.lifecycle == "Production"
THEN SET custom_data.backup_enabled TO true
Conditions
Field References
Access node properties using dot notation:
| Field Path | Data Type | Example |
|---|---|---|
node.id | UUID | 550e8400-e29b-41d4-a716-446655440000 |
node.name | String | "core-switch-01" |
node.vendor | String | "Cisco", "Juniper", "Arista" |
node.model | String | "ASR9000", "EX4300" |
node.role | String | "Core", "Access", "Edge" |
node.lifecycle | String | "Production", "Staging" |
node.management_ip | String | "192.168.1.1" |
custom_data.field | Any | JSON field access |
Comparison Operators
| Operator | Description | Example |
|---|---|---|
== | Equal to | node.vendor == "Cisco" |
!= | Not equal to | node.lifecycle != "Decommissioned" |
> | Greater than | custom_data.port_count > 48 |
< | Less than | custom_data.cpu_percent < 80 |
>= | Greater than or equal | custom_data.uptime >= 86400 |
<= | Less than or equal | custom_data.memory_usage <= 90 |
CONTAINS | String contains | node.model CONTAINS "4000" |
MATCHES | Regex match | node.name MATCHES "^core-" |
Logical Operators
| Operator | Description | Example |
|---|---|---|
AND | Both conditions true | node.vendor == "Cisco" AND node.role == "Core" |
OR | Either condition true | node.lifecycle == "Production" OR node.lifecycle == "Staging" |
NOT | Negate condition | NOT (node.lifecycle == "Decommissioned") |
Parentheses for Grouping
WHEN (node.vendor == "Cisco" OR node.vendor == "Juniper")
AND node.lifecycle == "Production"
THEN ASSERT custom_data.monitoring_enabled IS true
Actions
ASSERT Action
Validate that a condition is true. Used for compliance checking.
Syntax:
ASSERT <field> IS <expected_value>
ASSERT <condition>
Examples:
# Check field value
WHEN node.vendor == "Cisco"
THEN ASSERT custom_data.snmp_enabled IS true
# Check complex condition
WHEN node.role == "Core"
THEN ASSERT custom_data.redundancy_level >= 2
# Simple assertion with message
WHEN node.lifecycle == "Production"
THEN ASSERT "Device is properly configured for production"
SET Action
Modify node data by setting field values.
Syntax:
SET <field> TO <value>
Examples:
# Set simple value
WHEN node.vendor == "Cisco"
THEN SET custom_data.backup_method TO "TFTP"
# Set complex data
WHEN node.role == "Access"
THEN SET custom_data.vlan_config TO {"default": 100, "voice": 200}
# Set based on condition
WHEN node.lifecycle == "Production"
THEN SET custom_data.monitoring_interval TO 300
Custom Data Access
Access nested JSON data in the custom_data field:
# Simple field access
custom_data.location_code
# Nested field access
custom_data.network.vlan_id
custom_data.hardware.memory_gb
custom_data.monitoring.alert_threshold
# Array access (planned feature)
custom_data.interfaces[0].name
Data Types and Values
String Values
"Cisco"
"ASR9000"
"192.168.1.1"
Numeric Values
100 # Integer
3.14 # Float
48 # Port count
80.5 # Percentage
Boolean Values
true
false
Null Values
null
Common Policy Patterns
Vendor-Specific Compliance
# Cisco devices should have specific SNMP settings
WHEN node.vendor == "Cisco"
THEN SET custom_data.snmp_version TO "v3"
# Juniper devices need different backup method
WHEN node.vendor == "Juniper"
THEN SET custom_data.backup_protocol TO "SCP"
Role-Based Configuration
# Core devices need redundancy
WHEN node.role == "Core"
THEN ASSERT custom_data.redundancy_enabled IS true
# Access switches have port security
WHEN node.role == "Access"
THEN SET custom_data.port_security_enabled TO true
# Edge devices need firewall rules
WHEN node.role == "Edge"
THEN ASSERT custom_data.firewall_configured IS true
Lifecycle Management
# Production devices must be monitored
WHEN node.lifecycle == "Production"
THEN SET custom_data.monitoring_enabled TO true
# Decommissioned devices should be isolated
WHEN node.lifecycle == "Decommissioned"
THEN SET custom_data.network_access TO false
# Staging devices need test configuration
WHEN node.lifecycle == "Staging"
THEN SET custom_data.test_mode TO true
Location-Based Policies
# Data center devices need specific settings
WHEN custom_data.location_type == "datacenter"
THEN SET custom_data.power_monitoring TO true
# Remote sites have different backup schedules
WHEN custom_data.location_type == "remote_office"
THEN SET custom_data.backup_schedule TO "weekly"
Conditional Data Management
# Set VLAN based on device role
WHEN node.role == "Access"
THEN SET custom_data.default_vlan TO 100
WHEN node.role == "Core"
THEN SET custom_data.default_vlan TO 1
# Configure monitoring intervals by importance
WHEN node.role == "Core" OR node.role == "Edge"
THEN SET custom_data.monitoring_interval TO 60
WHEN node.role == "Access"
THEN SET custom_data.monitoring_interval TO 300
Policy File Organization
Single Policy File
# File: network-compliance.rules
# Vendor compliance
WHEN node.vendor == "Cisco" THEN SET custom_data.snmp_version TO "v3"
WHEN node.vendor == "Juniper" THEN SET custom_data.backup_method TO "SCP"
# Role-based settings
WHEN node.role == "Core" THEN ASSERT custom_data.redundancy IS true
WHEN node.role == "Access" THEN SET custom_data.port_security TO true
Multiple Policy Files
policies/
├── vendor-compliance.rules # Vendor-specific rules
├── role-configuration.rules # Role-based configuration
├── lifecycle-management.rules # Lifecycle policies
└── security-baseline.rules # Security requirements
Policy File Comments
# This policy ensures core devices have redundancy
WHEN node.role == "Core"
THEN ASSERT custom_data.redundancy_level >= 2
# TODO: Add environmental monitoring for data center devices
# WHEN custom_data.location == "datacenter"
# THEN ASSERT custom_data.temperature_monitoring IS true
Working with Policies
Validating Policy Syntax
# Validate single file
unet policy validate network-compliance.rules
# Validate directory of policies
unet policy validate policies/
# Validate with detailed output
unet policy validate policies/ --verbose
Evaluating Policies
# Evaluate policies against all nodes
unet policy eval network-compliance.rules
# Evaluate against specific node
unet policy eval policies/ --node core-switch-01
# Show only failures
unet policy eval policies/ --failures-only
# Detailed evaluation output
unet policy eval policies/ --verbose
Viewing Policy Results
# List policy files and their rules
unet policy list policies/
# Show policy file contents
unet policy show network-compliance.rules
# Show parsed rules (AST)
unet policy show network-compliance.rules --ast
API Integration
Evaluate Policies via API
curl -X POST http://localhost:8080/api/v1/policies/evaluate \
-H "Content-Type: application/json" \
-d '{
"policies": [
{
"id": "cisco-compliance",
"condition": "node.vendor == \"Cisco\"",
"action": "assert(\"SNMP configured\")"
}
]
}'
Get Policy Results
curl http://localhost:8080/api/v1/policies/results?node_id=550e8400-e29b-41d4-a716-446655440000
Best Practices
Policy Design
- Start Simple: Begin with basic compliance checks before complex logic
- Use Descriptive Names: Make policy intent clear from the rule
- Group Related Rules: Organize policies by vendor, role, or function
- Test Incrementally: Validate syntax before adding to production
Rule Organization
# Good: Clear, specific rule
WHEN node.vendor == "Cisco" AND node.role == "Core"
THEN ASSERT custom_data.hsrp_configured IS true
# Avoid: Complex nested conditions
WHEN (node.vendor == "Cisco" OR node.vendor == "Juniper")
AND (node.role == "Core" OR node.role == "Distribution")
AND (custom_data.location == "datacenter" OR custom_data.location == "colo")
THEN SET custom_data.complex_setting TO true
Error Handling
- Use ASSERT for Compliance: Check requirements with clear messages
- Handle Missing Data: Consider what happens with null/undefined values
- Test Edge Cases: Verify policies work with minimal data sets
Version Control
# Store policies in Git
git add policies/
git commit -m "Add network compliance policies"
# Review policy changes
git diff policies/network-compliance.rules
Troubleshooting
Common Syntax Errors
# Error: Missing quotes around string
WHEN node.vendor == Cisco # ❌ Wrong
WHEN node.vendor == "Cisco" # ✅ Correct
# Error: Invalid field reference
WHEN node.invalid_field == "value" # ❌ Wrong
WHEN custom_data.valid_field == "value" # ✅ Correct
# Error: Missing THEN keyword
WHEN node.vendor == "Cisco" SET custom_data.x TO true # ❌ Wrong
WHEN node.vendor == "Cisco" THEN SET custom_data.x TO true # ✅ Correct
Debugging Policy Evaluation
# Check if policies parse correctly
unet policy validate policies/ --verbose
# Test against specific node
unet policy eval policies/ --node test-device-01 --verbose
# Examine policy AST
unet policy show policies/debug.rules --ast
Common Issues
- Policy Not Triggering: Check condition syntax and field names
- SET Action Failing: Verify field path and value type
- ASSERT Always Failing: Check for null/undefined values
Performance Considerations
Efficient Policy Design
- Use Specific Conditions: Avoid overly broad conditions that match many nodes
- Limit Custom Data Access: Deep JSON traversal can be slow
- Batch Similar Rules: Group related checks in single policies
Evaluation Performance
- Node Count: Policies evaluate against all matching nodes
- Rule Complexity: Complex conditions take more time to evaluate
- Custom Data Size: Large JSON objects slow down field access
Limitations (Current Version)
- Array Access: Custom data array indexing not yet supported
- Function Calls: No built-in functions (length, contains, etc.)
- Cross-Node References: Cannot reference other nodes in conditions
- Template Integration: APPLY action is infrastructure-ready but templates not implemented
Examples
Network Security Baseline
# File: security-baseline.rules
# All production devices must have SNMP v3
WHEN node.lifecycle == "Production"
THEN ASSERT custom_data.snmp_version == "v3"
# Core devices need access control
WHEN node.role == "Core"
THEN ASSERT custom_data.acl_configured IS true
# Edge devices require firewall
WHEN node.role == "Edge"
THEN ASSERT custom_data.firewall_enabled IS true
# Management interfaces should be secured
WHEN node.management_ip != null
THEN SET custom_data.mgmt_security_enabled TO true
Device Lifecycle Management
# File: lifecycle-management.rules
# New devices start in staging
WHEN custom_data.deployment_status == "new"
THEN SET node.lifecycle TO "Staging"
# Production readiness checks
WHEN node.lifecycle == "Staging" AND custom_data.testing_complete IS true
THEN SET node.lifecycle TO "Production"
# Decommissioning workflow
WHEN custom_data.scheduled_replacement != null
THEN SET custom_data.decommission_planned TO true
# Remove access for decommissioned devices
WHEN node.lifecycle == "Decommissioned"
THEN SET custom_data.network_access TO false
Vendor-Specific Configuration
# File: vendor-configuration.rules
# Cisco device standards
WHEN node.vendor == "Cisco"
THEN SET custom_data.config_backup_method TO "TFTP"
WHEN node.vendor == "Cisco" AND node.role == "Core"
THEN SET custom_data.routing_protocol TO "OSPF"
# Juniper device standards
WHEN node.vendor == "Juniper"
THEN SET custom_data.config_backup_method TO "SCP"
WHEN node.vendor == "Juniper" AND node.role == "Edge"
THEN SET custom_data.security_zones TO ["DMZ", "INTERNAL"]
# Arista device standards
WHEN node.vendor == "Arista"
THEN SET custom_data.management_protocol TO "eAPI"
For more advanced examples and integration patterns, see the API Reference and CLI Reference.
API Reference – μNet HTTP Server
Audience: Developers integrating with μNet via HTTP API
Status: Documents implemented endpoints only (v0.1.0)
Overview
μNet provides a RESTful HTTP API for all network configuration management operations. The API is built with Axum (Rust) and supports JSON request/response formats.
Base URL: http://localhost:8080 (default)
API Version: v1
Authentication: None (planned for future versions)
Standard Response Format
All API responses follow a consistent format:
Success Response
{
"data": "<response_data>",
"success": true,
"message": null
}
Error Response
{
"error": "Human-readable error message",
"code": "ERROR_CODE",
"success": false
}
HTTP Status Codes
- 200 - Success
- 400 - Bad Request (validation errors)
- 404 - Resource not found
- 409 - Conflict (constraint violations)
- 500 - Internal server error
- 503 - Service unavailable
Health Check
GET /health
System health and status check.
Response
{
"status": "healthy",
"service": "μNet",
"version": "0.1.0",
"timestamp": "2024-01-15T10:30:00Z",
"components": {
"datastore": {
"status": "healthy",
"type": "sqlite"
}
}
}
Node Management
GET /api/v1/nodes
List all nodes with filtering and pagination.
Query Parameters
page(int) - Page number (default: 1)per_page(int) - Items per page (default: 20)lifecycle(string) - Filter by lifecycle staterole(string) - Filter by device rolevendor(string) - Filter by vendorinclude_status(bool) - Include SNMP-derived status data
Example Request
GET /api/v1/nodes?vendor=cisco&role=router&page=1&per_page=10
Response
{
"data": {
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "core-01",
"domain": "example.com",
"fqdn": "core-01.example.com",
"vendor": "Cisco",
"model": "ASR9000",
"role": "Core",
"lifecycle": "Production",
"management_ip": "10.1.1.1",
"location_id": "550e8400-e29b-41d4-a716-446655440001",
"platform": null,
"version": null,
"serial_number": null,
"asset_tag": null,
"purchase_date": null,
"warranty_expires": null,
"custom_data": {},
"status": null
}
],
"total": 50,
"page": 1,
"per_page": 10,
"total_pages": 5,
"has_next": true,
"has_prev": false
},
"success": true,
"message": null
}
GET /api/v1/nodes/{id}
Get a specific node by UUID.
Path Parameters
id(UUID) - Node identifier
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "core-01",
"domain": "example.com",
"fqdn": "core-01.example.com",
"vendor": "Cisco",
"model": "ASR9000",
"role": "Core",
"lifecycle": "Production",
"management_ip": "10.1.1.1",
"location_id": "550e8400-e29b-41d4-a716-446655440001",
"custom_data": {
"rack_position": "R1-U20"
}
},
"success": true,
"message": null
}
POST /api/v1/nodes
Create a new node.
Request Body
{
"name": "new-router-01",
"domain": "example.com",
"vendor": "Cisco",
"model": "ISR4431",
"role": "Edge",
"lifecycle": "Staging",
"management_ip": "10.1.1.50",
"location_id": "550e8400-e29b-41d4-a716-446655440001",
"custom_data": {
"cost_center": "IT-001",
"rack_position": "R2-U10"
}
}
Required Fields: name, vendor, model, role, lifecycle
Optional Fields: domain, management_ip, location_id, custom_data
Vendor Values: Cisco, Juniper, Arista, HPE, Dell, Ubiquiti, MikroTik, Fortinet, PaloAlto, CheckPoint, F5, A10, Riverbed, SilverPeak, VMware, Linux, Windows, Other
Role Values: Core, Distribution, Access, Edge, Firewall, LoadBalancer, WirelessController, WirelessAP, Server, Storage, Hypervisor, Container, IoT, Camera, Phone, Printer, Other
Lifecycle Values: Planning, Staging, Production, Maintenance, Decommissioned
PUT /api/v1/nodes/{id}
Update an existing node (partial updates supported).
Path Parameters
id(UUID) - Node identifier
Request Body (all fields optional)
{
"name": "updated-router-01",
"lifecycle": "Production",
"management_ip": "10.1.1.51",
"custom_data": {
"maintenance_window": "Sunday 02:00-04:00"
}
}
DELETE /api/v1/nodes/{id}
Delete a node.
Path Parameters
id(UUID) - Node identifier
Response
{
"data": null,
"success": true,
"message": null
}
Node Derived State (SNMP Data)
GET /api/v1/nodes/{id}/status
Get current node status from SNMP polling.
Path Parameters
id(UUID) - Node identifier
Response
{
"data": {
"node_id": "550e8400-e29b-41d4-a716-446655440000",
"last_updated": "2024-01-15T10:30:00Z",
"reachable": true,
"system_info": {
"description": "Cisco IOS Software, Version 15.2(7)E6",
"object_id": "1.3.6.1.4.1.9.1.516",
"uptime_ticks": 123456789,
"contact": "admin@example.com",
"name": "core-01",
"location": "Data Center Rack 1",
"services": 72
},
"interfaces": [],
"performance": null,
"environmental": null,
"vendor_metrics": {},
"raw_snmp_data": {},
"last_snmp_success": "2024-01-15T10:29:45Z",
"last_error": null,
"consecutive_failures": 0
},
"success": true,
"message": null
}
GET /api/v1/nodes/{id}/interfaces
Get interface status for a node.
Path Parameters
id(UUID) - Node identifier
Response
{
"data": [
{
"index": 1,
"name": "GigabitEthernet1/0/1",
"interface_type": 6,
"mtu": 1500,
"speed": 1000000000,
"physical_address": "aa:bb:cc:dd:ee:ff",
"admin_status": "Up",
"oper_status": "Up",
"last_change": "2024-01-15T08:00:00Z",
"input_stats": {
"octets": 1234567890,
"unicast_packets": 9876543,
"non_unicast_packets": 1000,
"discards": 0,
"errors": 0,
"unknown_protocols": 0
},
"output_stats": {
"octets": 987654321,
"unicast_packets": 5432109,
"non_unicast_packets": 500,
"discards": 0,
"errors": 0
}
}
],
"success": true,
"message": null
}
GET /api/v1/nodes/{id}/metrics
Get performance metrics for a node.
Path Parameters
id(UUID) - Node identifier
Response
{
"data": {
"cpu_utilization": 15.5,
"memory_utilization": 45.2,
"temperature": 42.0,
"total_memory_kb": 524288,
"available_memory_kb": 287309,
"buffer_hit_ratio": 98.5,
"uptime_seconds": 1234567
},
"success": true,
"message": null
}
Policy Management
POST /api/v1/policies/evaluate
Evaluate policies against nodes.
Request Body
{
"node_ids": ["550e8400-e29b-41d4-a716-446655440000"],
"policies": [
{
"id": "cisco-compliance",
"condition": "node.vendor == 'Cisco' && node.lifecycle == 'Production'",
"action": "assert('Cisco device in production has proper config')"
}
],
"store_results": true
}
Fields:
node_ids(array, optional) - Node UUIDs to evaluate (default: all nodes)policies(array, optional) - Policy rules to evaluate (default: load from configured source)store_results(bool, optional) - Store results in database (default: true)
Response
{
"data": {
"results": {
"550e8400-e29b-41d4-a716-446655440000": [
{
"policy_id": "cisco-compliance",
"status": "Satisfied",
"message": "Cisco device in production has proper config",
"execution_time_ms": 12,
"timestamp": "2024-01-15T10:30:00Z"
}
]
},
"nodes_evaluated": 1,
"policies_evaluated": 1,
"evaluation_time_ms": 150,
"summary": {
"total_rules": 1,
"satisfied_rules": 1,
"unsatisfied_rules": 0,
"error_rules": 0,
"compliance_failures": 0
}
},
"success": true,
"message": null
}
GET /api/v1/policies/results
Get stored policy evaluation results.
Query Parameters
node_id(UUID, optional) - Filter by nodelimit(int, optional) - Maximum results (default: 100)offset(int, optional) - Results to skip (default: 0)
Response
{
"data": {
"results": [
{
"policy_id": "cisco-compliance",
"status": "Satisfied",
"message": "Cisco device in production has proper config",
"execution_time_ms": 12,
"timestamp": "2024-01-15T10:30:00Z"
}
],
"total_count": 1,
"returned_count": 1
},
"success": true,
"message": null
}
POST /api/v1/policies/validate
Validate policy rule syntax.
Request Body
[
{
"id": "valid-policy",
"condition": "node.vendor == 'Cisco'",
"action": "assert('Valid Cisco device')"
},
{
"id": "invalid-policy",
"condition": "",
"action": "invalid_action()"
}
]
Response
{
"total_policies": 2,
"valid_policies": 1,
"invalid_policies": 1,
"validation_results": [
{
"index": 0,
"valid": true,
"message": "Policy rule is valid"
},
{
"index": 1,
"valid": false,
"message": "Policy rule has syntax errors"
}
]
}
GET /api/v1/policies/status
Get policy engine status.
Response
{
"policy_engine_enabled": true,
"nodes_available": 25,
"policies_available": 10,
"last_evaluation": null,
"evaluation_frequency": "on-demand"
}
Error Handling
Common Error Codes
| Code | Description |
|---|---|
VALIDATION_ERROR | Request validation failed |
NOT_FOUND | Resource not found |
CONSTRAINT_VIOLATION | Database constraint violated |
DATASTORE_ERROR | Database operation failed |
POLICY_ERROR | Policy evaluation failed |
SNMP_ERROR | SNMP operation failed |
Example Error Response
{
"error": "Node with name 'duplicate-name' already exists",
"code": "CONSTRAINT_VIOLATION",
"success": false
}
Examples
Create a Complete Network Setup
# Create a location first
curl -X POST http://localhost:8080/api/v1/locations \
-H "Content-Type: application/json" \
-d '{
"name": "Data Center 1",
"location_type": "Building",
"address": "123 Server St"
}'
# Create nodes
curl -X POST http://localhost:8080/api/v1/nodes \
-H "Content-Type: application/json" \
-d '{
"name": "core-01",
"domain": "example.com",
"vendor": "Cisco",
"model": "ASR9000",
"role": "Core",
"lifecycle": "Production",
"management_ip": "10.1.1.1",
"location_id": "550e8400-e29b-41d4-a716-446655440001"
}'
# List nodes
curl http://localhost:8080/api/v1/nodes?vendor=Cisco
# Get node status
curl http://localhost:8080/api/v1/nodes/550e8400-e29b-41d4-a716-446655440000/status
Policy Evaluation
# Evaluate compliance policies
curl -X POST http://localhost:8080/api/v1/policies/evaluate \
-H "Content-Type: application/json" \
-d '{
"policies": [
{
"id": "production-check",
"condition": "node.lifecycle == \"Production\"",
"action": "assert(\"Device is in production\")"
}
]
}'
# Get evaluation results
curl http://localhost:8080/api/v1/policies/results?limit=50
Configuration
Server Configuration
The API server can be configured via command line, environment variables, or configuration file:
# Command line
unet-server --host 0.0.0.0 --port 8080 --database-url sqlite://production.db
# Environment variables
export UNET_HOST=0.0.0.0
export UNET_PORT=8080
export UNET_DATABASE_URL=sqlite://production.db
unet-server
# Configuration file
unet-server --config /etc/unet/server.toml
CORS
The server enables permissive CORS for development. In production, configure appropriate CORS policies.
Future Enhancements
- Authentication & Authorization - Token-based access control
- Rate Limiting - Request throttling and abuse prevention
- WebSocket Support - Real-time updates and notifications
- GraphQL API - Alternative query interface
- OpenAPI Specification - Auto-generated API documentation
For planned features, see the Roadmap.
Developer Guide
This guide provides comprehensive patterns, best practices, and decision trees for developing μNet. It complements the Architecture document with practical implementation guidance.
Quick Reference
Finding Implementation Patterns
- New entities: Copy pattern from
crates/unet-core/src/entities/nodes.rs - New API endpoints: Copy pattern from
crates/unet-server/src/handlers/nodes/crud.rs - New CLI commands: Copy pattern from
crates/unet-cli/src/commands/nodes/crud.rs - Database migrations: Copy pattern from
crates/migrations/src/m20241221_000002_create_nodes_table.rs - SNMP integration: Study patterns in
crates/unet-core/src/snmp/
Essential Search Terms
# Find similar API implementations
grep -r "async fn.*Result<Json" crates/unet-server/src/handlers/
# Find entity patterns
grep -r "DeriveEntityModel" crates/unet-core/src/entities/
# Find test patterns
grep -r "#\[tokio::test\]" crates/*/src/
# Find error handling patterns
grep -r "ApiError" crates/unet-server/src/
# Find SNMP patterns
grep -r "SnmpSession" crates/unet-core/src/snmp/
Decision Trees
Adding New Data Fields
Is this field user-configurable?
├─ Yes → Desired state (nodes, locations, links tables)
│ ├─ Required for basic functionality? → NOT NULL
│ └─ Optional enhancement? → NULL allowed
└─ No → Is it derived from SNMP/monitoring?
├─ Yes → Derived state (node_status, interface_status tables)
│ ├─ Always available from SNMP? → NOT NULL
│ └─ Device-dependent? → NULL allowed
└─ No → Consider if this belongs in custom_data JSON field
Build & Test Performance
Lib-First Binaries (sccache-friendly)
- Pattern: keep
src/main.rsas a thin shim and move logic intosrc/lib.rs. - Benefits: lib artifacts (
rlib) are reused across tests, coverage, and other bins bysccache. - Applied in this repo:
unet-cli: CLI parsing and execution inlib,maindelegates.unet-server: modules andrun()inlib,maindelegates.config-slicer: CLI parsing and execution inlib,maindelegates.
- Writing tests: prefer in-process tests calling library functions; keep minimal binary smoke tests.
sccache Usage
- Local defaults:
.cargo/config.tomlsetsRUSTC_WRAPPER=sccacheif not set. - CI: workflows install and cache
~/.cache/sccache. - Cache hints:
- Keep flags consistent between tasks to maximize cache hits.
- Prefer default features locally; use
--all-featuresonly in CI. - Avoid embedding non-deterministic build-time values unless gated.
Optional Fast Linker (Linux GNU)
- lld/mold can reduce link time. Example usage for local runs:
# Requires clang + lld
RUSTFLAGS="-C link-arg=-fuse-ld=lld" \
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang \
cargo build
# Or mold if installed
RUSTFLAGS="-C link-arg=-fuse-ld=mold" \
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang \
cargo nextest run
- Notes:
- macOS uses Apple’s linker; lld/mold steps above are Linux-specific.
- These flags are optional and not set globally to avoid portability issues.
Fast Coverage Loop
- Local:
mise run coverage-fast(tests only,--no-clean, show missing lines). - CI:
mise run ci-coverage(workspace, all features/targets as configured).
Choosing Error Handling Approach
Where does the error originate?
├─ API endpoint → Use ApiError with appropriate HTTP status
│ ├─ User input validation → 400 Bad Request
│ ├─ Resource not found → 404 Not Found
│ ├─ Database constraint → 409 Conflict
│ └─ Internal system error → 500 Internal Server Error
├─ SNMP operation → Use csnmp error types
│ ├─ Network timeout → Retry with exponential backoff
│ ├─ Authentication failure → Log and mark node unreachable
│ └─ Parse error → Log raw data and continue
└─ Database operation → Use sea_orm::DbErr
├─ Transaction conflict → Retry operation
└─ Schema mismatch → Return structured error
Database Query Optimization
What type of query?
├─ Single record by ID → Use find_by_id() - most efficient
├─ List with filters → Use find() with where clauses
│ ├─ Common filter? → Ensure index exists
│ ├─ Large result set? → Add pagination
│ └─ Complex joins? → Consider separate queries
└─ Aggregation → Use select() with group_by()
├─ Real-time display? → Cache results
└─ Background reporting? → Direct SQL may be faster
Code Patterns
Standard Entity Implementation
When creating a new entity, follow this pattern:
// crates/unet-core/src/entities/example.rs
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
/// Description of what this entity represents
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "example")]
pub struct Model {
/// Primary key - always use String for UUID
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
/// Required fields come first
pub name: String,
pub example_type: String,
/// Optional fields
pub description: Option<String>,
pub custom_data: Option<String>,
/// Timestamps - always include these
pub created_at: String,
pub updated_at: String,
}
/// Database relations
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
// Define relationships to other entities
}
impl ActiveModelBehavior for ActiveModel {}
Standard API Endpoint Implementation
// crates/unet-server/src/handlers/example/crud.rs
use axum::{extract::State, http::StatusCode, Json};
use crate::{ApiError, AppState};
/// Create a new example
pub async fn create_example(
State(app_state): State<AppState>,
Json(payload): Json<CreateExampleRequest>,
) -> Result<Json<Example>, ApiError> {
// 1. Validate input
payload.validate()?;
// 2. Check permissions/authorization if needed
// 3. Transform to domain model
let example = Example::from(payload);
// 4. Store via DataStore trait
let created = app_state.datastore.create_example(example).await
.map_err(|e| ApiError::internal_error("Failed to create example", e))?;
// 5. Return response
Ok(Json(created))
}
/// Request/response types
#[derive(Debug, Deserialize)]
pub struct CreateExampleRequest {
pub name: String,
pub example_type: String,
pub description: Option<String>,
}
impl CreateExampleRequest {
fn validate(&self) -> Result<(), ApiError> {
if self.name.is_empty() {
return Err(ApiError::bad_request("Name cannot be empty"));
}
Ok(())
}
}
Standard Test Patterns
// Follow TDD - write test first!
#[tokio::test]
async fn test_create_example_success() {
// Arrange
let datastore = setup_test_datastore().await;
let example = Example {
id: Uuid::new_v4(),
name: "test-example".to_string(),
example_type: "test".to_string(),
description: Some("Test description".to_string()),
custom_data: None,
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
};
// Act
let result = datastore.create_example(example.clone()).await;
// Assert
assert!(result.is_ok());
let created = result.unwrap();
assert_eq!(created.name, example.name);
assert_eq!(created.example_type, example.example_type);
// Cleanup
cleanup_test_data(&datastore).await;
}
#[tokio::test]
async fn test_create_example_duplicate_name() {
// Test error conditions
let datastore = setup_test_datastore().await;
// Create first example
let example1 = create_test_example(&datastore, "duplicate-name").await.unwrap();
// Try to create second with same name
let example2 = Example { name: "duplicate-name".to_string(), ..test_example() };
let result = datastore.create_example(example2).await;
assert!(result.is_err());
// Verify specific error type
cleanup_test_data(&datastore).await;
}
SNMP Integration Patterns
// crates/unet-core/src/snmp/collectors/example.rs
use crate::snmp::{SnmpSession, SnmpError};
use std::time::Duration;
pub struct ExampleCollector {
session: SnmpSession,
}
impl ExampleCollector {
pub fn new(session: SnmpSession) -> Self {
Self { session }
}
pub async fn collect_example_data(&mut self, node_id: &str) -> Result<ExampleData, SnmpError> {
// 1. Define OIDs to query
let oids = vec![
"1.3.6.1.2.1.1.1.0".to_string(), // sysDescr
"1.3.6.1.2.1.1.3.0".to_string(), // sysUpTime
];
// 2. Perform bulk query with timeout
let results = self.session
.bulk_get(oids)
.timeout(Duration::from_secs(30))
.await?;
// 3. Parse results with error handling
let mut data = ExampleData::default();
for (oid, value) in results {
match oid.as_str() {
"1.3.6.1.2.1.1.1.0" => {
data.description = value.as_string().ok();
}
"1.3.6.1.2.1.1.3.0" => {
data.uptime = value.as_counter64()
.map(Duration::from_centiseconds)
.ok();
}
_ => {
tracing::warn!("Unexpected OID in response: {}", oid);
}
}
}
Ok(data)
}
}
#[derive(Debug, Default)]
pub struct ExampleData {
pub description: Option<String>,
pub uptime: Option<Duration>,
}
Domain-Specific Patterns
Network Automation Best Practices
SNMP Polling Strategy
- Bulk operations: Always use
bulk_getfor multiple OIDs - Timeout handling: Set reasonable timeouts (30s for system info, 60s for large tables)
- Error recovery: Distinguish between temporary (network) and permanent (auth) failures
- Rate limiting: Respect device capabilities - don't overwhelm network equipment
Policy Evaluation Performance
- Cache policy ASTs: Parse policies once, evaluate many times
- Batch evaluations: Process multiple nodes/policies in single transaction
- Lazy loading: Only load data that policies actually reference
- Early termination: Stop evaluation as soon as decision is clear
State Management
- Desired State: User configurations, topology definitions, policy rules
- Derived State: SNMP data, calculated metrics, policy evaluation results
- Never mix: Keep clear separation between what users configure vs. what system discovers
Common Anti-Patterns to Avoid
Database Anti-Patterns
// DON'T: Bypass DataStore trait
let node = Node::find_by_id(node_id).one(&db).await?;
// DO: Use DataStore abstraction
let node = datastore.get_node(&node_id).await?;
// DON'T: N+1 queries
for node in nodes {
let location = datastore.get_location(&node.location_id).await?;
}
// DO: Bulk operations
let location_ids: Vec<_> = nodes.iter().map(|n| &n.location_id).collect();
let locations = datastore.get_locations_by_ids(&location_ids).await?;
SNMP Anti-Patterns
// DON'T: Blocking calls in async context
let result = std::thread::spawn(|| snmp_sync_call()).join();
// DO: Use async SNMP operations
let result = snmp_session.get(oid).await?;
// DON'T: Ignore timeouts
let result = snmp_session.get(oid).await?;
// DO: Set appropriate timeouts
let result = snmp_session.get(oid).timeout(Duration::from_secs(30)).await?;
Error Handling Anti-Patterns
// DON'T: Generic error messages
return Err(ApiError::internal_error("Something went wrong"));
// DO: Specific, actionable errors
return Err(ApiError::bad_request("Node name must be between 1 and 255 characters"));
// DON'T: Expose internal details
return Err(ApiError::internal_error(format!("Database error: {}", db_error)));
// DO: Log internal details, return user-friendly message
tracing::error!("Database constraint violation: {}", db_error);
return Err(ApiError::conflict("A node with this name already exists"));
Debugging & Troubleshooting
SNMP Issues
Connection Problems
- Check network connectivity:
ping <device_ip> - Verify SNMP credentials: Test with
snmpwalkcommand - Check firewall rules: Ensure UDP 161 is accessible
- Validate community strings: Ensure they match device configuration
Query Failures
- OID validation: Verify OIDs exist on target device
- Permission checking: Ensure community has read access to OIDs
- MIB loading: Check if custom MIBs are needed
- Timeout tuning: Increase timeouts for slow devices
Performance Issues
- Bulk query optimization: Group related OIDs together
- Polling frequency: Reduce frequency for non-critical metrics
- Device capability: Some devices can't handle high query rates
- Network latency: Account for WAN links with higher timeouts
Database Performance
Slow Queries
- Check indexes: Ensure proper indexes on filtered columns
- Query analysis: Use EXPLAIN QUERY PLAN for complex queries
- Pagination: Add LIMIT/OFFSET for large result sets
- Connection pooling: Monitor connection pool utilization
Lock Contention
- Transaction scope: Keep transactions as short as possible
- Retry logic: Implement exponential backoff for lock timeouts
- Read replicas: Use read-only queries where possible
- Batch operations: Group multiple updates into single transaction
API Performance
Slow Endpoints
- Database queries: Profile database access patterns
- Serialization: Large JSON responses can be slow
- External dependencies: SNMP calls, file I/O
- Memory allocation: Check for unnecessary clones/allocations
Memory Issues
- Large datasets: Implement streaming for large responses
- Connection leaks: Monitor database connection usage
- Background tasks: Check for memory leaks in polling tasks
- Logging overhead: Excessive debug logging can consume memory
Task Recipes
Adding a New SNMP OID
-
Research the OID
# Test with snmpwalk first snmpwalk -v2c -c public <device_ip> <new_oid> -
Add to OID definitions
// crates/unet-core/src/snmp/oids/standard.rs pub const NEW_METRIC_OID: &str = "1.3.6.1.2.1.x.x.x"; -
Update collector
// Add to relevant collector in crates/unet-core/src/snmp/collectors/ let oids = vec![ // existing OIDs... NEW_METRIC_OID.to_string(), ]; -
Add to data model
// Update derived state entity pub new_metric: Option<i64>, -
Write tests
#[tokio::test] async fn test_collect_new_metric() { // Test successful collection // Test missing OID handling // Test parsing edge cases } -
Update migration
# Create new migration file cargo run --bin migration -- generate add_new_metric_column
Adding a New Policy Rule Type
-
Define AST node
// crates/unet-core/src/policy/ast.rs pub enum Condition { // existing conditions... NewRuleType { field: String, operator: ComparisonOp, value: Value }, } -
Update parser
// crates/unet-core/src/policy/grammar.pest new_rule = { "new_rule" ~ "(" ~ field ~ operator ~ value ~ ")" } -
Implement evaluator
// crates/unet-core/src/policy/evaluator/conditions.rs Condition::NewRuleType { field, operator, value } => { let node_value = get_node_field(node, field)?; compare_values(&node_value, operator, value) } -
Add CLI support
// crates/unet-cli/src/commands/policy/ // Add new subcommand for rule type -
Write comprehensive tests
#[tokio::test] async fn test_new_rule_evaluation() { // Test various value types // Test all operators // Test edge cases and errors }
Extending the Data Model
-
Plan the change
- Desired vs derived state?
- Required vs optional field?
- Index requirements?
-
Create migration
cargo run --bin migration -- generate add_new_field_to_table -
Update entity model
// Add field to appropriate entity pub new_field: Option<String>, -
Update DataStore trait
// Add methods if needed async fn update_new_field(&self, id: &str, value: String) -> Result<()>; -
Implement in datastores
// Update the SQLite implementation -
Add API endpoints
// Update request/response types // Add validation logic // Update handlers -
Update CLI
// Add command line options // Update output formatting -
Write tests
// Unit tests for data model // Integration tests for API // End-to-end tests for CLI
Performance Guidelines
Database Optimization
Query Patterns
- Single record: Use
find_by_id()with primary key - Filtered lists: Use
find().filter()with indexed columns - Counts: Use
count()instead of loading all records - Exists checks: Use
count() > 0for existence tests
Index Strategy
- Primary keys: Automatic unique index
- Foreign keys: Add index for join performance
- Filter columns: Index frequently filtered columns
- Composite indexes: For multi-column filters
Transaction Management
- Read operations: No transaction needed for single queries
- Write operations: Use transactions for multi-table updates
- Long operations: Break into smaller transactions
- Retry logic: Handle transaction conflicts gracefully
Memory Management
Large Datasets
- Streaming: Process records in batches
- Pagination: Limit result set sizes
- Lazy loading: Load related data on demand
- Connection pooling: Reuse database connections
Background Tasks
- Resource cleanup: Properly close connections and files
- Memory monitoring: Check for gradual memory leaks
- Graceful shutdown: Handle termination signals properly
- Error recovery: Restart failed background tasks
Network Optimization
SNMP Efficiency
- Bulk operations: Query multiple OIDs together
- Connection reuse: Maintain persistent SNMP sessions
- Timeout tuning: Balance responsiveness vs. reliability
- Error handling: Distinguish temporary vs. permanent failures
API Performance
- Response size: Minimize JSON payload size
- Caching: Cache expensive computations
- Compression: Use gzip for large responses
- Connection limits: Prevent resource exhaustion
This guide provides the foundation for efficient μNet development. Always refer to existing code patterns and follow the TDD practices outlined in AGENTS.md.
Codex Startup Script
Purpose: Document the commands run when a Codex environment starts
This script installs the development and CI tooling used by μNet. It is executed automatically for Codex containers.
rustup component add clippy rustfmt llvm-tools-preview
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
cargo binstall --disable-telemetry --no-confirm cargo-tarpaulin cargo-audit typos-cli mise mdbook cargo-llvm-cov
mise trust
curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
cargo fetch
npm install markdownlint-cli2 --global --no-progress
Command Overview
rustup component add clippy rustfmt llvm-tools-preview– install Rust linting, formatting, and LLVM coverage components.curl ... cargo-binstall ...– download and install thecargo-binstallhelper.cargo binstall ...– install code coverage, security audit, formatting, and other tooling.mise trust– mark this repository'smiseconfiguration as trusted.curl ... nexte.st ...– fetch thenextestbinary used to run tests.cargo fetch– pre-download Rust dependencies.npm install markdownlint-cli2 --global --no-progress– install the Markdown linter.
Architecture Overview – μNet Network Management System
Audience: Engineers and operators working with μNet
Status: Documents current implementation (v0.1.0)
Overview
μNet is a network configuration management system built in Rust, designed around three core principles:
- Single Binary Deployment - Both CLI and server are self-contained executables
- Modular Architecture - Clear separation between data, policy, and presentation layers
- Progressive Adoption - Start small, grow capabilities over time
System Architecture
Current Implementation
┌─────────────────────────────────────────────────────────────────────────┐
│ μNet System (v0.1.0) │
│ ─────────────────────────────────────────────────────────────────────── │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ unet-cli │ HTTP │ unet-server │ │
│ │ │◄──────────┤ │ │
│ │ • Commands │ JSON │ • REST API │ │
│ │ • Output Format │ │ • Background │ │
│ │ • Local/Remote │ │ Tasks │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ unet-core Library │ │
│ │ ─────────────────────────────────────────────────────────────── │ │
│ │ • Data Models • DataStore Trait • Policy Engine │ │
│ │ • SNMP Client • Error Handling • Configuration │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Data Storage │ │
│ │ ─────────────────────────────────────────────────────────────── │ │
│ │ SQLite Database │ │
│ │ • SeaORM Entities │ │
│ │ • Migrations │ │
│ │ • ACID Transactions │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
External Network Devices
├── SNMP Polling ──────► Node Status, Interface Stats, System Info
├── Policy Evaluation ──► Compliance Checking
└── Configuration Management (Planned for v0.2.0)
Component Architecture
Core Library (unet-core)
The heart of μNet, providing all business logic as a reusable library.
Data Models
- Node: Network devices with lifecycle management
- Link: Connections between nodes (point-to-point and circuits)
- Location: Hierarchical physical locations (campus → building → rack)
- Derived State: SNMP-collected data (status, interfaces, metrics)
DataStore Abstraction
use sea_orm::DbErr;
// Example types for illustration
struct Node {
id: String,
name: String,
}
struct QueryOptions {
limit: Option<u64>,
offset: Option<u64>,
}
struct PagedResult<T> {
items: Vec<T>,
total: u64,
}
trait DataStore {
async fn get_node(&self, id: &str) -> Result<Option<Node>, DbErr>;
async fn create_node(&self, node: &Node) -> Result<(), DbErr>;
async fn list_nodes(&self, options: QueryOptions) -> Result<PagedResult<Node>, DbErr>;
// ... comprehensive CRUD operations
}
Implementations:
- SQLiteStore: Production backend using SeaORM
Policy Engine
- DSL Parser: Pest-based grammar for WHEN/THEN rules
- Evaluator: Context-based rule execution against JSON data
- Actions: Assert (compliance), Set (data modification)
SNMP Integration
- Client: Async SNMP operations with connection pooling
- Polling: Background tasks for device data collection
- OID Mapping: Standard and vendor-specific MIB support
Server Binary (unet-server)
HTTP API server built with Axum framework.
API Features
- REST Endpoints: Full CRUD operations for all data types
- Pagination: Built-in support for large datasets
- Filtering: Query nodes by vendor, role, lifecycle
- Error Handling: Consistent JSON error responses
- Derived State: SNMP data accessible via dedicated endpoints
Background Services
- SNMP Polling: Continuous device monitoring
- Policy Evaluation: Periodic compliance checking
- Health Monitoring: Component status tracking
CLI Binary (unet-cli)
Command-line interface for operators and automation.
Command Structure
unet [global-options] <command> <subcommand> [args]
Commands:
├── nodes - Device CRUD operations
├── links - Connection management
├── locations - Site management
├── policy - Compliance operations
├── import - Data import from JSON/YAML
└── export - Data export to JSON/YAML
Features
- Multiple Output Formats: Table, JSON, YAML
- Local & Remote Operation: Direct database or HTTP API
- Comprehensive Validation: Input checking and error reporting
- Pagination Support: Handle large datasets efficiently
Data Flow
1. Device Management Flow
Operator ──► CLI Command ──► DataStore ──► Database
│ │ │ │
│ │ │ │
▼ ▼ ▼ ▼
Input Validation Business Persistence
Parsing & Building Logic & Integrity
2. SNMP Monitoring Flow
Device ──► SNMP Client ──► DataStore ──► Derived State
│ │ │ │
│ │ │ │
▼ ▼ ▼ ▼
Status OID Mapping Storage API Access
Data & Parsing Update & Queries
3. Policy Evaluation Flow
Policy Files ──► Parser ──► Evaluator ──► Results
│ │ │ │
│ │ │ │
▼ ▼ ▼ ▼
Rules AST Context Compliance
Syntax Building Evaluation Reports
Technology Stack
Core Technologies
| Component | Technology | Rationale |
|---|---|---|
| Language | Rust | Memory safety, performance, async support |
| Database | SQLite + SeaORM | Zero-ops deployment, type-safe queries |
| HTTP Server | Axum | Modern async framework, high performance |
| CLI Framework | Clap v4 | Rich features, derive macros, shell completion |
| SNMP Client | csnmp | Pure Rust, async-first SNMP implementation |
| Policy Parser | Pest | PEG parser with detailed error reporting |
Data Formats
| Use Case | Format | Details |
|---|---|---|
| API Requests/Responses | JSON | Standard REST API format |
| Configuration | TOML | Human-readable, well-structured |
| Data Import/Export | JSON/YAML | Flexible bulk operations |
| Error Logging | Structured JSON | Machine-parsable logs |
Async Architecture
All I/O operations are fully asynchronous using Tokio:
- Database Operations: Non-blocking SeaORM queries
- HTTP Server: Concurrent request handling
- SNMP Polling: Parallel device monitoring
- CLI Operations: Async throughout, no blocking calls
Current Capabilities
✅ Implemented Features
Data Management
- Full CRUD Operations: Create, read, update, delete for all entities
- Hierarchical Locations: Campus → Building → Floor → Rack structure
- Lifecycle Management: Device states from planning to decommissioned
- Custom Data Support: JSON fields for extensibility
Network Monitoring
- SNMP Polling: Background collection of device status
- Interface Statistics: Port-level traffic and error counters
- System Information: Device description, uptime, contact info
- Connection Pooling: Efficient SNMP session management
Policy & Compliance
- DSL Language: WHEN/THEN rule syntax for network policies
- Rule Evaluation: Real-time compliance checking
- Bulk Operations: Evaluate policies across entire network
- Result Storage: Historical compliance tracking
API & CLI
- Comprehensive REST API: Full HTTP interface for automation
- Rich CLI: Interactive commands with multiple output formats
- Data Import/Export: Bulk operations for network topology
- Error Handling: Detailed error messages and recovery guidance
🚧 Planned Features
- Template Engine: Configuration generation (v0.2.0)
- Advanced SNMP CLI: Historical metrics, polling controls
- Configuration Push: Safe deployment to devices
- Git Integration: Version control for policies and templates
- Web UI: Browser-based management interface
Database Schema
Core Entities
-- Locations (hierarchical)
locations
├── id (UUID)
├── name (TEXT)
├── location_type (TEXT)
├── parent_id (UUID, FK)
├── address (TEXT)
└── custom_data (JSON)
-- Nodes (network devices)
nodes
├── id (UUID)
├── name (TEXT)
├── domain (TEXT)
├── fqdn (TEXT, computed)
├── vendor (TEXT)
├── model (TEXT)
├── role (TEXT)
├── lifecycle (TEXT)
├── management_ip (TEXT)
├── location_id (UUID, FK)
└── custom_data (JSON)
-- Links (connections)
links
├── id (UUID)
├── node_a_id (UUID, FK)
├── interface_a (TEXT)
├── node_z_id (UUID, FK, nullable)
├── interface_z (TEXT, nullable)
├── circuit_id (TEXT, nullable)
├── bandwidth (BIGINT)
└── custom_data (JSON)
Derived State Tables
-- SNMP-collected data
node_status
├── node_id (UUID, FK)
├── last_updated (TIMESTAMP)
├── reachable (BOOLEAN)
├── system_info (JSON)
├── raw_snmp_data (JSON)
└── last_error (TEXT)
interface_status
├── node_id (UUID, FK)
├── interface_index (INTEGER)
├── name (TEXT)
├── admin_status (TEXT)
├── oper_status (TEXT)
├── statistics (JSON)
└── last_updated (TIMESTAMP)
Security Considerations
Current State
- No Authentication: All endpoints publicly accessible
- Input Validation: Comprehensive validation of all user inputs
- SQL Injection Protection: SeaORM provides safe query building
- Error Information: Sanitized error responses, no sensitive data exposure
Planned Security Features
- Token-based Authentication: JWT or similar for API access
- Role-based Authorization: Different permission levels
- Audit Logging: Comprehensive change tracking
- TLS/HTTPS: Encrypted communication
Performance Characteristics
Current Performance
- Database: SQLite performs well for <10K devices
- API Response Times: Sub-100ms for typical operations
- SNMP Polling: Configurable intervals, parallel execution
- Memory Usage: ~50MB base, scales with dataset size
Scalability Considerations
- Horizontal Scaling: Not currently supported (SQLite limitation)
- Vertical Scaling: Optimized single-machine performance
- Caching: Minimal caching, relies on SQLite performance
- Connection Pooling: SNMP connections reused efficiently
Development Philosophy
Code Quality
- Type Safety: Rust's type system prevents many runtime errors
- Error Handling: Comprehensive error types with context
- Testing: Unit tests for business logic, integration tests for APIs
- Documentation: Inline docs and comprehensive guides
Operational Excellence
- Single Binary: No external dependencies for deployment
- Configuration: Environment variables, files, or CLI arguments
- Logging: Structured logging with multiple levels
- Metrics: Built-in health checks and status endpoints
Future Architecture Plans
Template Engine (v0.2.0)
- MiniJinja Integration: Rust-native templating
- Configuration Generation: Device-specific config templates
- Diff Engine: Compare generated vs. actual configurations
- Partial Templates: Template only specific config sections
Enhanced Storage (v0.3.0)
- PostgreSQL Support: Production-scale database backend
- Time-Series Data: Historical metrics and performance data
- Backup/Restore: Automated data protection
- Multi-tenancy: Support for multiple organizations
Advanced Features (v1.0.0)
- Configuration Push: Safe deployment to network devices
- Rollback Mechanisms: Automatic recovery from failed changes
- Change Management: Approval workflows and audit trails
- High Availability: Clustering and replication support
The architecture is designed to grow incrementally while maintaining backward compatibility and operational simplicity.
Database Schema Reference
μNet uses a SQLite database with SeaORM for data persistence. The schema is designed with a clear separation between desired state (user-configured network topology) and derived state (real-time data from SNMP polling).
Overview
The database consists of two main categories of tables:
- Desired State Tables: Store user-defined network topology and configuration
- Derived State Tables: Store real-time operational data collected via SNMP
This separation ensures that configuration remains stable while allowing operational data to be updated frequently.
Core Tables
Locations
Physical or logical locations for organizing network devices in a hierarchical structure.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
name | TEXT | NOT NULL | Human-readable location name |
type | TEXT | NOT NULL | Type of location (datacenter, building, floor, rack, etc.) |
path | TEXT | NOT NULL, UNIQUE | Hierarchical path for tree navigation |
parent_id | TEXT | FOREIGN KEY | Reference to parent location |
description | TEXT | Optional description | |
address | TEXT | Physical address or location details | |
coordinates | TEXT | GPS coordinates or position data | |
custom_data | TEXT | JSON string for custom attributes | |
created_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
updated_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp |
Indexes:
idx_location_path(unique onpath)idx_location_parent(onparent_id)
Nodes
Network devices and their static configuration attributes.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
name | TEXT | NOT NULL | Node name (typically hostname) |
fqdn | TEXT | Fully qualified domain name | |
domain | TEXT | DNS domain | |
vendor | TEXT | NOT NULL | Device vendor (see Vendor enum) |
model | TEXT | NOT NULL | Device model number |
role | TEXT | NOT NULL | Device role (see DeviceRole enum) |
lifecycle | TEXT | NOT NULL | Lifecycle stage (see Lifecycle enum) |
serial_number | TEXT | Device serial number | |
asset_tag | TEXT | Asset tag for inventory tracking | |
location_id | TEXT | FOREIGN KEY | Reference to location |
management_ip | TEXT | Primary management IP address | |
description | TEXT | Optional description | |
custom_data | TEXT | JSON string for custom attributes | |
created_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
updated_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp |
Indexes:
idx_node_name(onname)idx_node_fqdn(onfqdn)idx_node_location(onlocation_id)idx_node_role(onrole)idx_node_lifecycle(onlifecycle)
Links
Network connections between devices, including both internal links and internet circuits.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
name | TEXT | NOT NULL | Human-readable link name |
node_a_id | TEXT | NOT NULL, FOREIGN KEY | Reference to first node (required) |
interface_a | TEXT | NOT NULL | Interface name on first node |
node_b_id | TEXT | FOREIGN KEY | Reference to second node (optional for internet circuits) |
interface_b | TEXT | Interface name on second node | |
capacity | BIGINT | Link capacity in bits per second | |
utilization | REAL | Current utilization as percentage (0.0-1.0) | |
is_internet_circuit | INTEGER | NOT NULL, DEFAULT 0 | Whether this is an internet circuit (1) or internal link (0) |
circuit_id | TEXT | Provider circuit identifier | |
provider | TEXT | Service provider name | |
description | TEXT | Optional description | |
custom_data | TEXT | JSON string for custom attributes | |
created_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
updated_at | TEXT | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp |
Indexes:
idx_link_name(onname)idx_link_node_a(onnode_a_id)idx_link_node_b(onnode_b_id)idx_link_circuit_id(oncircuit_id)
Vendors
List of supported network equipment vendors.
| Column | Type | Constraints | Description |
|---|---|---|---|
name | TEXT | PRIMARY KEY, NOT NULL | Vendor name |
Seeded vendors include Cisco, Juniper, Arista, and others. Use the CLI to manage the list:
# List vendors
unet vendors list
# Add vendor
unet vendors add CustomVendor
# Remove vendor
unet vendors delete CustomVendor
Derived State Tables
Node Status
Real-time operational status and metrics for network nodes, populated by SNMP polling.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
node_id | TEXT | NOT NULL, FOREIGN KEY | Reference to node table |
last_updated | TEXT | NOT NULL | Timestamp of last status update |
reachable | BOOLEAN | NOT NULL, DEFAULT false | Whether node is reachable via SNMP |
system_info | TEXT | JSON containing system information (uptime, name, description) | |
performance | TEXT | JSON containing performance metrics (CPU, memory) | |
environmental | TEXT | JSON containing environmental data (temperature, fans) | |
vendor_metrics | TEXT | JSON containing vendor-specific metrics | |
raw_snmp_data | TEXT | JSON containing raw SNMP response data | |
last_snmp_success | TEXT | Timestamp of last successful SNMP poll | |
last_error | TEXT | Last error message encountered during polling | |
consecutive_failures | INTEGER | NOT NULL, DEFAULT 0 | Number of consecutive failed polling attempts |
Indexes:
idx_node_status_node_id(unique onnode_id)idx_node_status_last_updated(onlast_updated)
Interface Status
Per-interface operational data and statistics from SNMP interface tables.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
node_status_id | TEXT | NOT NULL, FOREIGN KEY | Reference to node_status table |
index | INTEGER | NOT NULL | Interface index from SNMP ifTable |
name | TEXT | NOT NULL | Interface name or description |
type | INTEGER | NOT NULL | Interface type code from SNMP ifType |
mtu | INTEGER | Maximum transmission unit in bytes | |
speed | BIGINT | Interface speed in bits per second | |
physical_address | TEXT | Physical MAC address of the interface | |
admin_status | TEXT | NOT NULL, DEFAULT 'unknown' | Administrative status (up/down/testing) |
oper_status | TEXT | NOT NULL, DEFAULT 'unknown' | Operational status (up/down/testing/unknown/dormant/notPresent/lowerLayerDown) |
last_change | INTEGER | Time when interface last changed state | |
input_stats | TEXT | NOT NULL | JSON containing input statistics (packets, bytes, errors) |
output_stats | TEXT | NOT NULL | JSON containing output statistics (packets, bytes, errors) |
Indexes:
idx_interface_status_node_status_id(onnode_status_id)idx_interface_status_index(unique onnode_status_id,index)
Polling Tasks
Configuration for SNMP polling tasks that collect operational data.
| Column | Type | Constraints | Description |
|---|---|---|---|
id | TEXT | PRIMARY KEY, NOT NULL | Unique identifier |
node_id | TEXT | NOT NULL, FOREIGN KEY | Reference to node table |
target | TEXT | NOT NULL | SNMP target address or hostname |
oids | TEXT | NOT NULL | JSON array of OIDs to poll |
interval_seconds | BIGINT | NOT NULL | Polling interval in seconds |
session_config | TEXT | NOT NULL | JSON containing SNMP session configuration |
priority | SMALLINT | NOT NULL, DEFAULT 128 | Task priority for scheduling |
enabled | BOOLEAN | NOT NULL, DEFAULT true | Whether task is currently enabled |
created_at | TEXT | NOT NULL | Task creation timestamp |
last_success | TEXT | Timestamp of last successful poll | |
last_error | TEXT | Last error message from polling | |
consecutive_failures | INTEGER | NOT NULL, DEFAULT 0 | Number of consecutive failed polls |
Indexes:
idx_polling_tasks_node_id(onnode_id)idx_polling_tasks_enabled(onenabled)
Enumerations
Device Role
Defines the network function of a device:
router- Network routerswitch- Network switchfirewall- Firewall deviceloadbalancer- Load balanceraccesspoint- Wireless access pointsecurityappliance- Network security appliancemonitor- Network monitoring deviceserver- Generic serverstorage- Storage deviceother- Other/unspecified device type
Lifecycle
Defines the operational state of a device:
planned- Device is planned but not yet deployedimplementing- Device is currently being implemented/deployedlive- Device is live and operationaldecommissioned- Device is being decommissioned or is decommissioned
Vendor
Supported network equipment vendors:
cisco- Cisco Systemsjuniper- Juniper Networksarista- Arista Networkspaloalto- Palo Alto Networksfortinet- Fortinethpe- HPE/Hewlett Packard Enterprisedell- Dell Technologiesextreme- Extreme Networksmikrotik- Mikrotikubiquiti- Ubiquitigeneric- Generic/unknown vendor
Schema Design Patterns
Primary Keys
All tables use text-based UUIDs as primary keys to ensure global uniqueness and enable distributed scenarios.
JSON Storage
Complex or flexible data is stored as JSON strings in columns like custom_data, system_info, and statistics fields. This allows for extensibility without schema changes.
Timestamps
All timestamps are stored as text in ISO 8601 format for consistency and readability.
Foreign Key Relationships
The schema maintains referential integrity through foreign key relationships:
- Nodes → Locations (optional)
- Links → Nodes (A-side required, B-side optional)
- Node Status → Nodes (one-to-one)
- Interface Status → Node Status (one-to-many)
- Polling Tasks → Nodes (one-to-many)
Indexing Strategy
Indexes are created on:
- Foreign key columns for efficient joins
- Frequently queried columns (names, roles, status)
- Unique constraints where needed
Usage Considerations
Data Separation
The schema enforces separation between:
- Configuration data (locations, nodes, links) - changes infrequently
- Operational data (status tables) - updated frequently via SNMP
Extensibility
Custom fields can be added via:
custom_dataJSON columns on core entities- Additional OIDs in polling tasks
- Vendor-specific metrics in status tables
Performance
- Derived state tables are optimized for frequent updates
- Indexes support common query patterns
- JSON storage provides flexibility without normalization overhead
Missing Fields?
If you need additional fields for your network automation use case, consider:
- Custom Data Fields: Use the
custom_dataJSON columns for entity-specific extensions - New Enums: Extend the vendor, role, or lifecycle enums if needed
- Additional Tables: For complex relationships not covered by existing schema
- SNMP Extensions: Add new OIDs to polling tasks for additional metrics
Open a pull request with your proposed schema changes and use cases to help expand μNet's capabilities.
μNet Roadmap
Current Status: ~60% complete. See
/STATUS.mdfor detailed development status and immediate next steps.
This document outlines the planned features and release timeline for μNet.
Current Status (v0.1.0)
μNet has CLI, API, policy engine, and SNMP infrastructure implemented. Current development focuses on completing API endpoints and background task integration. See /STATUS.md for detailed completion status.
Planned Features
Milestone 4: Template Engine
- Configuration Templates: Jinja2-compatible templating system
- Partial Configuration Management: Template-match headers for selective config management
- Intelligent Diffing: Hierarchical configuration comparison
- CLI Commands:
unet template render --node <id> --template <file>unet template diff --node <id> --template <file>unet template validate --path <dir>
Milestone 5: Advanced SNMP CLI
- SNMP Polling Controls: CLI commands to manage background polling
- Device Discovery: Automatic capability detection
- Historical Metrics: Time-series data storage and retrieval
- CLI Commands (planned):
unet nodes polling start/stop/statusunet nodes history --metrics --since 1dunet nodes compare <node1> <node2>
Milestone 6: Configuration Push
- Safe Configuration Deployment: Push generated configs to devices
- Rollback Mechanisms: Automatic recovery from failed changes
- Change Management: Audit trails and approval workflows
Future Enhancements
Enhanced CLI Experience
unet init --with-examples- Quick setup with sample dataunet locations tree- Hierarchical location display- Advanced filtering and output formatting
- Interactive mode for guided operations
Web UI
- Browser-based interface for non-CLI users
- Visual topology maps
- Policy authoring assistance
- Real-time monitoring dashboards
Enterprise Features
- Authentication & Authorization: Token-based access control
- Multi-tenancy: Support for multiple organizations
- Integration APIs: Webhooks and event streaming
- High Availability: Clustering and replication
Advanced Policy Features
- Policy Libraries: Pre-built compliance templates
- Custom Actions: Extensible action framework
- Conditional Logic: More sophisticated rule evaluation
- Policy Testing: Dry-run and simulation capabilities
Network Discovery
- Topology Auto-Discovery: LLDP/CDP-based link detection
- Device Fingerprinting: Automatic vendor/model identification
- Network Mapping: Visual topology generation
Release Sequence
- v0.2.0: Template Engine + Configuration Generation
- v0.3.0: Advanced SNMP Monitoring + CLI
- v0.4.0: Configuration Push + Rollback
- v1.0.0: Web UI
Contributing to the Roadmap
We welcome input on prioritization and feature requests:
- Feature Requests: GitHub Issues with
enhancementlabel - Architecture Discussions: GitHub Discussions
- Implementation Help: Check
good first issuelabels on planned features
Design Principles for Future Features
All new features will maintain μNet's core principles:
- Progressive Adoption: You can adopt new capabilities gradually
- Safety First: Always show what changes before applying them
- Single Binary: Minimal deployment complexity
- Multi-vendor: Work consistently across network vendors
- Git Integration: Version control for all configuration artifacts