Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements

- Add comprehensive database migrations (001-024) for schema evolution
- Enhance API schema with expanded type definitions and resolvers
- Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth
- Implement new services: AI optimization, billing, blockchain, compliance, marketplace
- Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage)
- Update Crossplane provider with enhanced VM management capabilities
- Add comprehensive test suite for API endpoints and services
- Update frontend components with improved GraphQL subscriptions and real-time updates
- Enhance security configurations and headers (CSP, CORS, etc.)
- Update documentation and configuration files
- Add new CI/CD workflows and validation scripts
- Implement design system improvements and UI enhancements
This commit is contained in:
defiQUG
2025-12-12 18:01:35 -08:00
parent e01131efaf
commit 9daf1fd378
968 changed files with 160890 additions and 1092 deletions

View File

@@ -0,0 +1,335 @@
# TP-Link Omada Management
Comprehensive management tools and integrations for TP-Link Omada SDN (Software-Defined Networking) infrastructure.
## Overview
TP-Link Omada provides centralized management of network infrastructure including access points, switches, and gateways. This directory contains management components for integrating Omada into the Sankofa Phoenix infrastructure.
## Components
### API Client (`api/`)
Omada Controller API client library for:
- Controller authentication and session management
- Site and device management
- Access point configuration
- Network policy management
- Client device tracking
- Analytics and monitoring
### Terraform (`terraform/`)
Terraform provider/modules for:
- Omada Controller configuration
- Site provisioning
- Access point deployment
- Network policy as code
- SSID management
### Ansible (`ansible/`)
Ansible roles and playbooks for:
- Omada Controller deployment
- Access point provisioning
- Network policy configuration
- Firmware management
- Configuration backup
### Scripts (`scripts/`)
Management scripts for:
- Controller health checks
- Device discovery
- Configuration backup/restore
- Firmware updates
- Network analytics
## Omada Controller Integration
### Architecture
```
Omada Controller (Centralized)
├── Sites (Physical Locations)
│ ├── Access Points
│ ├── Switches
│ ├── Gateways
│ └── Network Policies
└── Global Settings
├── SSID Templates
├── Network Policies
└── User Groups
```
### Controller Setup
```bash
# Setup Omada Controller
./scripts/setup-controller.sh \
--controller omada.sankofa.nexus \
--admin admin \
--password secure-password
```
### Site Configuration
```bash
# Add a new site
./scripts/add-site.sh \
--site us-east-1 \
--name "US East Datacenter" \
--timezone "America/New_York"
```
## Usage
### Access Point Management
```bash
# Discover access points
./scripts/discover-aps.sh --site us-east-1
# Provision access point
./scripts/provision-ap.sh \
--site us-east-1 \
--ap "AP-01" \
--mac "aa:bb:cc:dd:ee:ff" \
--name "AP-Lobby-01"
# Configure access point
./scripts/configure-ap.sh \
--ap "AP-Lobby-01" \
--radio 2.4GHz \
--channel auto \
--power high
```
### SSID Management
```bash
# Create SSID
./scripts/create-ssid.sh \
--site us-east-1 \
--name "Sankofa-Employee" \
--security wpa3 \
--vlan 100
# Assign SSID to access point
./scripts/assign-ssid.sh \
--ap "AP-Lobby-01" \
--ssid "Sankofa-Employee" \
--radio 2.4GHz,5GHz
```
### Network Policies
```bash
# Create network policy
./scripts/create-policy.sh \
--site us-east-1 \
--name "Guest-Policy" \
--bandwidth-limit 10Mbps \
--vlan 200
# Apply policy to SSID
./scripts/apply-policy.sh \
--ssid "Sankofa-Guest" \
--policy "Guest-Policy"
```
### Ansible Deployment
```bash
# Deploy Omada configuration
cd ansible
ansible-playbook -i inventory.yml omada-deployment.yml \
-e controller=omada.sankofa.nexus \
-e site=us-east-1
```
### Terraform
```bash
# Provision Omada infrastructure
cd terraform
terraform init
terraform plan -var="controller=omada.sankofa.nexus"
terraform apply
```
## API Client Usage
### Python Example
```python
from omada_api import OmadaController
# Connect to controller
controller = OmadaController(
host="omada.sankofa.nexus",
username="admin",
password="secure-password"
)
# Get sites
sites = controller.get_sites()
# Get access points for a site
aps = controller.get_access_points(site_id="us-east-1")
# Configure access point
controller.configure_ap(
ap_id="ap-123",
name="AP-Lobby-01",
radio_config={
"2.4GHz": {"channel": "auto", "power": "high"},
"5GHz": {"channel": "auto", "power": "high"}
}
)
```
### Go Example
```go
package main
import (
"github.com/sankofa/omada-api"
)
func main() {
client := omada.NewClient("omada.sankofa.nexus", "admin", "secure-password")
sites, err := client.GetSites()
if err != nil {
log.Fatal(err)
}
aps, err := client.GetAccessPoints("us-east-1")
if err != nil {
log.Fatal(err)
}
}
```
## Configuration
### Controller Configuration
```yaml
controller:
host: omada.sankofa.nexus
port: 8043
username: admin
password: ${OMADA_PASSWORD}
verify_ssl: true
sites:
- id: us-east-1
name: US East Datacenter
timezone: America/New_York
aps:
- name: AP-Lobby-01
mac: aa:bb:cc:dd:ee:ff
location: Lobby
- name: AP-Office-01
mac: aa:bb:cc:dd:ee:ff
location: Office
```
### Network Policies
```yaml
policies:
- name: Employee-Policy
bandwidth_limit: unlimited
vlan: 100
firewall_rules:
- allow: [80, 443, 22]
- block: [all]
- name: Guest-Policy
bandwidth_limit: 10Mbps
vlan: 200
firewall_rules:
- allow: [80, 443]
- block: [all]
```
## Monitoring
Omada monitoring integrates with Prometheus:
- **omada_exporter**: Prometheus metrics exporter
- **Grafana Dashboards**: Pre-built dashboards for Omada
- **Alerts**: Alert rules for network health
See [Monitoring](../monitoring/README.md) for details.
## Security
- Controller authentication via username/password or API key
- TLS/SSL for all API communications
- Network isolation via VLANs
- Client device authentication
- Regular firmware updates
## Backup and Recovery
### Configuration Backup
```bash
# Backup Omada configuration
./scripts/backup-config.sh \
--controller omada.sankofa.nexus \
--output backup-$(date +%Y%m%d).json
```
### Configuration Restore
```bash
# Restore Omada configuration
./scripts/restore-config.sh \
--controller omada.sankofa.nexus \
--backup backup-20240101.json
```
## Firmware Management
```bash
# Check firmware versions
./scripts/check-firmware.sh --site us-east-1
# Update firmware
./scripts/update-firmware.sh \
--site us-east-1 \
--ap "AP-Lobby-01" \
--firmware firmware-v1.2.3.bin
```
## Troubleshooting
### Common Issues
**Controller connectivity:**
```bash
./scripts/test-controller.sh --controller omada.sankofa.nexus
```
**Access point offline:**
```bash
./scripts/diagnose-ap.sh --ap "AP-Lobby-01"
```
**Network performance:**
```bash
./scripts/analyze-network.sh --site us-east-1
```
## Related Documentation
- [Network Management](../network/README.md)
- [System Architecture](../../docs/system_architecture.md)
- [Infrastructure Management](../README.md)

View File

@@ -0,0 +1,309 @@
# TP-Link Omada API Client
Python and Go client libraries for interacting with the TP-Link Omada Controller API.
## Overview
The Omada API client provides a high-level interface for managing TP-Link Omada SDN infrastructure, including access points, switches, gateways, and network policies.
## Features
- Controller authentication and session management
- Site and device management
- Access point configuration
- Network policy management
- Client device tracking
- Analytics and monitoring
## Installation
### Python
```bash
pip install omada-api
```
### Go
```bash
go get github.com/sankofa/omada-api
```
## Usage
### Python
```python
from omada_api import OmadaController
# Initialize controller
controller = OmadaController(
host="omada.sankofa.nexus",
username="admin",
password="secure-password",
verify_ssl=True
)
# Authenticate
controller.login()
# Get sites
sites = controller.get_sites()
for site in sites:
print(f"Site: {site['name']} (ID: {site['id']})")
# Get access points
aps = controller.get_access_points(site_id="us-east-1")
for ap in aps:
print(f"AP: {ap['name']} - {ap['status']}")
# Configure access point
controller.configure_ap(
ap_id="ap-123",
name="AP-Lobby-01",
radio_config={
"2.4GHz": {
"channel": "auto",
"power": "high",
"bandwidth": "20/40MHz"
},
"5GHz": {
"channel": "auto",
"power": "high",
"bandwidth": "20/40/80MHz"
}
}
)
# Create SSID
controller.create_ssid(
site_id="us-east-1",
name="Sankofa-Employee",
security="wpa3",
password="secure-password",
vlan=100
)
# Logout
controller.logout()
```
### Go
```go
package main
import (
"fmt"
"log"
"github.com/sankofa/omada-api"
)
func main() {
// Initialize controller
client := omada.NewClient(
"omada.sankofa.nexus",
"admin",
"secure-password",
)
// Authenticate
if err := client.Login(); err != nil {
log.Fatal(err)
}
defer client.Logout()
// Get sites
sites, err := client.GetSites()
if err != nil {
log.Fatal(err)
}
for _, site := range sites {
fmt.Printf("Site: %s (ID: %s)\n", site.Name, site.ID)
}
// Get access points
aps, err := client.GetAccessPoints("us-east-1")
if err != nil {
log.Fatal(err)
}
for _, ap := range aps {
fmt.Printf("AP: %s - %s\n", ap.Name, ap.Status)
}
}
```
## API Reference
### Authentication
```python
# Login
controller.login()
# Check authentication status
is_authenticated = controller.is_authenticated()
# Logout
controller.logout()
```
### Sites
```python
# Get all sites
sites = controller.get_sites()
# Get site by ID
site = controller.get_site(site_id="us-east-1")
# Create site
site = controller.create_site(
name="US East Datacenter",
timezone="America/New_York"
)
# Update site
controller.update_site(
site_id="us-east-1",
name="US East Datacenter - Updated"
)
# Delete site
controller.delete_site(site_id="us-east-1")
```
### Access Points
```python
# Get all access points for a site
aps = controller.get_access_points(site_id="us-east-1")
# Get access point by ID
ap = controller.get_access_point(ap_id="ap-123")
# Configure access point
controller.configure_ap(
ap_id="ap-123",
name="AP-Lobby-01",
location="Lobby",
radio_config={
"2.4GHz": {"channel": "auto", "power": "high"},
"5GHz": {"channel": "auto", "power": "high"}
}
)
# Reboot access point
controller.reboot_ap(ap_id="ap-123")
# Update firmware
controller.update_firmware(ap_id="ap-123", firmware_url="...")
```
### SSIDs
```python
# Get all SSIDs for a site
ssids = controller.get_ssids(site_id="us-east-1")
# Create SSID
ssid = controller.create_ssid(
site_id="us-east-1",
name="Sankofa-Employee",
security="wpa3",
password="secure-password",
vlan=100,
radios=["2.4GHz", "5GHz"]
)
# Update SSID
controller.update_ssid(
ssid_id="ssid-123",
name="Sankofa-Employee-Updated"
)
# Delete SSID
controller.delete_ssid(ssid_id="ssid-123")
```
### Network Policies
```python
# Get network policies
policies = controller.get_policies(site_id="us-east-1")
# Create policy
policy = controller.create_policy(
site_id="us-east-1",
name="Guest-Policy",
bandwidth_limit=10, # Mbps
vlan=200,
firewall_rules=[
{"action": "allow", "ports": [80, 443]},
{"action": "block", "ports": "all"}
]
)
# Apply policy to SSID
controller.apply_policy(ssid_id="ssid-123", policy_id="policy-123")
```
### Clients
```python
# Get client devices
clients = controller.get_clients(site_id="us-east-1")
# Get client by MAC
client = controller.get_client(mac="aa:bb:cc:dd:ee:ff")
# Block client
controller.block_client(mac="aa:bb:cc:dd:ee:ff")
# Unblock client
controller.unblock_client(mac="aa:bb:cc:dd:ee:ff")
```
## Error Handling
```python
from omada_api import OmadaError, AuthenticationError
try:
controller.login()
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except OmadaError as e:
print(f"Omada API error: {e}")
```
## Configuration
### Environment Variables
```bash
export OMADA_HOST=omada.sankofa.nexus
export OMADA_USERNAME=admin
export OMADA_PASSWORD=secure-password
export OMADA_VERIFY_SSL=true
```
### Configuration File
```yaml
omada:
host: omada.sankofa.nexus
port: 8043
username: admin
password: ${OMADA_PASSWORD}
verify_ssl: true
timeout: 30
```
## Related Documentation
- [Omada Management](../README.md)
- [Infrastructure Management](../../README.md)

View File

@@ -0,0 +1,373 @@
#!/usr/bin/env python3
"""
TP-Link Omada Controller API Client
A Python client library for interacting with the TP-Link Omada Controller API.
"""
import requests
import json
from typing import Dict, List, Optional, Any
from urllib.parse import urljoin
class OmadaError(Exception):
"""Base exception for Omada API errors"""
pass
class AuthenticationError(OmadaError):
"""Authentication failed"""
pass
class OmadaController:
"""TP-Link Omada Controller API Client"""
def __init__(
self,
host: str,
username: str,
password: str,
port: int = 8043,
verify_ssl: bool = True,
timeout: int = 30
):
"""
Initialize Omada Controller client
Args:
host: Omada Controller hostname or IP
username: Controller username
password: Controller password
port: Controller port (default: 8043)
verify_ssl: Verify SSL certificates (default: True)
timeout: Request timeout in seconds (default: 30)
"""
self.base_url = f"https://{host}:{port}"
self.username = username
self.password = password
self.verify_ssl = verify_ssl
self.timeout = timeout
self.session = requests.Session()
self.session.verify = verify_ssl
self.token = None
self.authenticated = False
def _request(
self,
method: str,
endpoint: str,
data: Optional[Dict] = None,
params: Optional[Dict] = None
) -> Dict[str, Any]:
"""
Make API request
Args:
method: HTTP method (GET, POST, PUT, DELETE)
endpoint: API endpoint
data: Request body data
params: Query parameters
Returns:
API response as dictionary
Raises:
OmadaError: If API request fails
"""
url = urljoin(self.base_url, endpoint)
headers = {
"Content-Type": "application/json",
"Accept": "application/json"
}
if self.token:
headers["Authorization"] = f"Bearer {self.token}"
try:
response = self.session.request(
method=method,
url=url,
headers=headers,
json=data,
params=params,
timeout=self.timeout
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
raise AuthenticationError("Authentication failed") from e
raise OmadaError(f"API request failed: {e}") from e
except requests.exceptions.RequestException as e:
raise OmadaError(f"Request failed: {e}") from e
def login(self) -> bool:
"""
Authenticate with Omada Controller
Returns:
True if authentication successful
Raises:
AuthenticationError: If authentication fails
"""
endpoint = "/api/v2/login"
data = {
"username": self.username,
"password": self.password
}
try:
response = self._request("POST", endpoint, data=data)
self.token = response.get("token")
self.authenticated = True
return True
except OmadaError as e:
self.authenticated = False
raise AuthenticationError(f"Login failed: {e}") from e
def logout(self) -> None:
"""Logout from Omada Controller"""
if self.authenticated:
endpoint = "/api/v2/logout"
try:
self._request("POST", endpoint)
except OmadaError:
pass # Ignore errors on logout
finally:
self.token = None
self.authenticated = False
def is_authenticated(self) -> bool:
"""Check if authenticated"""
return self.authenticated
def get_sites(self) -> List[Dict[str, Any]]:
"""
Get all sites
Returns:
List of site dictionaries
"""
endpoint = "/api/v2/sites"
response = self._request("GET", endpoint)
return response.get("data", [])
def get_site(self, site_id: str) -> Dict[str, Any]:
"""
Get site by ID
Args:
site_id: Site ID
Returns:
Site dictionary
"""
endpoint = f"/api/v2/sites/{site_id}"
response = self._request("GET", endpoint)
return response.get("data", {})
def create_site(
self,
name: str,
timezone: str = "UTC",
description: Optional[str] = None
) -> Dict[str, Any]:
"""
Create a new site
Args:
name: Site name
timezone: Timezone (e.g., "America/New_York")
description: Site description
Returns:
Created site dictionary
"""
endpoint = "/api/v2/sites"
data = {
"name": name,
"timezone": timezone
}
if description:
data["description"] = description
response = self._request("POST", endpoint, data=data)
return response.get("data", {})
def get_access_points(self, site_id: str) -> List[Dict[str, Any]]:
"""
Get all access points for a site
Args:
site_id: Site ID
Returns:
List of access point dictionaries
"""
endpoint = f"/api/v2/sites/{site_id}/access-points"
response = self._request("GET", endpoint)
return response.get("data", [])
def get_access_point(self, ap_id: str) -> Dict[str, Any]:
"""
Get access point by ID
Args:
ap_id: Access point ID
Returns:
Access point dictionary
"""
endpoint = f"/api/v2/access-points/{ap_id}"
response = self._request("GET", endpoint)
return response.get("data", {})
def configure_ap(
self,
ap_id: str,
name: Optional[str] = None,
location: Optional[str] = None,
radio_config: Optional[Dict] = None
) -> Dict[str, Any]:
"""
Configure access point
Args:
ap_id: Access point ID
name: Access point name
location: Physical location
radio_config: Radio configuration
Returns:
Updated access point dictionary
"""
endpoint = f"/api/v2/access-points/{ap_id}"
data = {}
if name:
data["name"] = name
if location:
data["location"] = location
if radio_config:
data["radio_config"] = radio_config
response = self._request("PUT", endpoint, data=data)
return response.get("data", {})
def get_ssids(self, site_id: str) -> List[Dict[str, Any]]:
"""
Get all SSIDs for a site
Args:
site_id: Site ID
Returns:
List of SSID dictionaries
"""
endpoint = f"/api/v2/sites/{site_id}/ssids"
response = self._request("GET", endpoint)
return response.get("data", [])
def create_ssid(
self,
site_id: str,
name: str,
security: str = "wpa3",
password: Optional[str] = None,
vlan: Optional[int] = None,
radios: Optional[List[str]] = None
) -> Dict[str, Any]:
"""
Create SSID
Args:
site_id: Site ID
name: SSID name
security: Security type (open, wpa2, wpa3)
password: WPA password (required for wpa2/wpa3)
vlan: VLAN ID
radios: List of radios (["2.4GHz", "5GHz"])
Returns:
Created SSID dictionary
"""
endpoint = f"/api/v2/sites/{site_id}/ssids"
data = {
"name": name,
"security": security
}
if password:
data["password"] = password
if vlan:
data["vlan"] = vlan
if radios:
data["radios"] = radios
response = self._request("POST", endpoint, data=data)
return response.get("data", {})
def get_clients(self, site_id: str) -> List[Dict[str, Any]]:
"""
Get all client devices for a site
Args:
site_id: Site ID
Returns:
List of client dictionaries
"""
endpoint = f"/api/v2/sites/{site_id}/clients"
response = self._request("GET", endpoint)
return response.get("data", [])
def get_client(self, mac: str) -> Dict[str, Any]:
"""
Get client device by MAC address
Args:
mac: MAC address
Returns:
Client dictionary
"""
endpoint = f"/api/v2/clients/{mac}"
response = self._request("GET", endpoint)
return response.get("data", {})
# Example usage
if __name__ == "__main__":
# Initialize controller
controller = OmadaController(
host="omada.sankofa.nexus",
username="admin",
password="secure-password"
)
try:
# Authenticate
controller.login()
print("Authenticated successfully")
# Get sites
sites = controller.get_sites()
print(f"Found {len(sites)} sites")
# Get access points for first site
if sites:
site_id = sites[0]["id"]
aps = controller.get_access_points(site_id)
print(f"Found {len(aps)} access points")
# Logout
controller.logout()
print("Logged out")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except OmadaError as e:
print(f"Error: {e}")

View File

@@ -0,0 +1,74 @@
#!/bin/bash
set -euo pipefail
# Discover Access Points Script
CONTROLLER="${OMADA_CONTROLLER:-}"
ADMIN_USER="${OMADA_ADMIN:-admin}"
ADMIN_PASSWORD="${OMADA_PASSWORD:-}"
SITE_ID="${SITE_ID:-}"
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}
error() {
log "ERROR: $*"
exit 1
}
check_prerequisites() {
if [ -z "${CONTROLLER}" ]; then
error "OMADA_CONTROLLER environment variable is required"
fi
if [ -z "${ADMIN_PASSWORD}" ]; then
error "OMADA_PASSWORD environment variable is required"
fi
}
authenticate() {
log "Authenticating with Omada Controller..."
TOKEN_RESPONSE=$(curl -k -s -X POST "https://${CONTROLLER}:8043/api/v2/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASSWORD}\"}")
TOKEN=$(echo "${TOKEN_RESPONSE}" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
if [ -z "${TOKEN}" ]; then
error "Authentication failed"
fi
echo "${TOKEN}"
}
discover_aps() {
TOKEN=$1
if [ -n "${SITE_ID}" ]; then
ENDPOINT="/api/v2/sites/${SITE_ID}/access-points"
else
ENDPOINT="/api/v2/access-points"
fi
log "Discovering access points..."
RESPONSE=$(curl -k -s -X GET "https://${CONTROLLER}:8043${ENDPOINT}" \
-H "Authorization: Bearer ${TOKEN}")
echo "${RESPONSE}" | python3 -m json.tool 2>/dev/null || echo "${RESPONSE}"
}
main() {
log "Starting access point discovery..."
check_prerequisites
TOKEN=$(authenticate)
discover_aps "${TOKEN}"
log "Discovery completed!"
}
main "$@"

View File

@@ -0,0 +1,110 @@
#!/bin/bash
set -euo pipefail
# TP-Link Omada Controller Setup Script
CONTROLLER="${OMADA_CONTROLLER:-}"
ADMIN_USER="${OMADA_ADMIN:-admin}"
ADMIN_PASSWORD="${OMADA_PASSWORD:-}"
SITE_NAME="${SITE_NAME:-}"
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}
error() {
log "ERROR: $*"
exit 1
}
check_prerequisites() {
if [ -z "${CONTROLLER}" ]; then
error "OMADA_CONTROLLER environment variable is required"
fi
if [ -z "${ADMIN_PASSWORD}" ]; then
error "OMADA_PASSWORD environment variable is required"
fi
if ! command -v curl &> /dev/null; then
error "curl is required but not installed"
fi
}
test_controller_connectivity() {
log "Testing connectivity to Omada Controller at ${CONTROLLER}..."
if curl -k -s --connect-timeout 5 "https://${CONTROLLER}:8043" > /dev/null; then
log "Controller is reachable"
return 0
else
error "Cannot reach controller at ${CONTROLLER}:8043"
fi
}
verify_authentication() {
log "Verifying authentication..."
RESPONSE=$(curl -k -s -X POST "https://${CONTROLLER}:8043/api/v2/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASSWORD}\"}")
if echo "${RESPONSE}" | grep -q "token"; then
log "Authentication successful"
return 0
else
error "Authentication failed. Please check credentials."
fi
}
create_site() {
if [ -z "${SITE_NAME}" ]; then
log "SITE_NAME not provided, skipping site creation"
return 0
fi
log "Creating site: ${SITE_NAME}..."
# Get authentication token
TOKEN_RESPONSE=$(curl -k -s -X POST "https://${CONTROLLER}:8043/api/v2/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASSWORD}\"}")
TOKEN=$(echo "${TOKEN_RESPONSE}" | grep -o '"token":"[^"]*' | cut -d'"' -f4)
if [ -z "${TOKEN}" ]; then
error "Failed to get authentication token"
fi
# Create site
SITE_RESPONSE=$(curl -k -s -X POST "https://${CONTROLLER}:8043/api/v2/sites" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${TOKEN}" \
-d "{\"name\":\"${SITE_NAME}\",\"timezone\":\"UTC\"}")
if echo "${SITE_RESPONSE}" | grep -q "id"; then
SITE_ID=$(echo "${SITE_RESPONSE}" | grep -o '"id":"[^"]*' | cut -d'"' -f4)
log "Site created successfully with ID: ${SITE_ID}"
else
log "Warning: Site creation may have failed or site already exists"
fi
}
main() {
log "Starting Omada Controller setup..."
check_prerequisites
test_controller_connectivity
verify_authentication
create_site
log "Omada Controller setup completed!"
log ""
log "Next steps:"
log "1. Configure access points: ./provision-ap.sh"
log "2. Create SSIDs: ./create-ssid.sh"
log "3. Set up network policies: ./create-policy.sh"
}
main "$@"