Files
wlan-cloud-rrm/IMPLEMENTATION.md
2022-08-31 14:16:17 -04:00

7.4 KiB

Implementation

This document provides high-level implementation details for the RRM service.

Overview

Framework

Initialization

Launcher is the main class, exposing a command-line interface implemented using picocli. The launcher creates clients and then passes them to the RRM class to start all modules (details below). Typically, each module is an event loop which runs in its own thread, implementing the Java Runnable interface.

The service configuration is defined in the RRMConfig class, and can be provided either via environment variables or as a JSON-serialized file. Default values are used for any omitted fields. When using the static file option, any new/missing fields are appended automatically. All fields are documented in Javadoc.

Data Structures

The device topology, DeviceTopology, is specified as groupings of APs into disjoint "RF zones" (default topology.json). For example:

{
  "<zone-name>": ["<serialNumber1>", "<serialNumber2>"],
  "building-A": ["aaaaaaaaaa01", "aaaaaaaaaa02"]
}

Device configuration is defined in DeviceConfig and applied in a layered manner via DeviceLayeredConfig (default device_config.json), merging the following layers from least to greatest precedence:

  • Base/default AP config (DeviceConfig.createDefault())
  • Network-wide config (networkConfig)
  • Per-zone config (zoneConfig)
  • Per-AP config (apConfig)

DeviceDataManager wraps all operations for the device topology and device configuration, and enables safe concurrent access.

Logging

Logging is handled using SLF4J/Log4j and configured in src/main/resources/log4j.properties. Output is written to console as well as rotated log files.

Versioning

The artifact version is defined in pom.xml and should match the OpenAPI document version (see ApiServer annotations). During Maven builds, the version string is written to src/main/resources-filtered/version.txt, and additional metadata can also be appended via the property appendVersionString. During runtime, version information can be accessed via VersionProvider.

Clients

The clients implement connections to external services.

uCentral OpenAPI

UCentralClient implements OpenAPI HTTP client calls to other uCentral services (ex. uCentralGw, uCentralSec, owprov) using Unirest. Most request and response schemas are defined in a corresponding "models" subpackage and are serialized/deserialized as JSON using Gson.

The client supports two modes:

  • Private endpoints: When deployed in a cluster with other OpenWiFi services, private service URLs are learned from Kafka and requests are sent with API keys (i.e. X-API-KEY header).
  • Public endpoints: Mainly for development purposes, public service URLs are learned from uCentralSec and requests are sent with a Bearer token (i.e. Authorization header) obtained via login using configured credentials.

uCentral Kafka

KafkaRunner wraps the following Apache Kafka clients, handling the run loop and graceful shutdown:

  • UCentralKafkaConsumer implements the Kafka consumer for OpenWiFi topics, and passes data (ex. device state, Wi-Fi scan results, system endpoints) to other modules via listener interfaces.
  • UCentralKafkaProducer implements the Kafka producer, which is responsible for periodically pushing system events required for discoverability by other OpenWiFi services.

RRM Database

DatabaseManager handles JDBC connection details for the RRM database and exposes methods for specific database operations. It uses the MySQL Connector/J driver and HikariCP for connection pooling.

Modules

The modules implement the service's application logic.

Data Collector

DataCollector collects data from all OpenWiFi devices as follows:

  • Issues Wi-Fi scan commands periodically and handles responses
  • Registers Kafka listeners to write records into the RRM database
  • Registers config listeners to configure the stats interval in OpenWiFi devices
  • Periodically queries capabilities for OpenWiFi devices

Config Manager

ConfigManager sends config changes to OpenWiFi devices (via uCentralGw). Any desired config changes are applied via listener interfaces, including the output of RRM algorithms. Device config updates are either applied periodically (when needed) or only triggered upon events (ex. RRM algorithm execution, API calls), depending on RRM service configuration. To minimize polling frequency since device config updates are rare, this thread has a long default sleep time and is interrupted by other threads when a config update is needed.

UCentralApConfiguration wraps the raw device configuration JSON and provides various access methods.

Modeler

Modeler subscribes to raw uCentral data, then prepares it for use by an optimizer. The "model" is defined in DataModel and includes the following information for each device:

  • Recent Wi-Fi scan results
  • Statistics (or "state")
  • Configuration (or "status")
  • Capabilities

Additional data processing utilities are contained in ModelerUtils.

API Server

ApiServer is an OpenAPI HTTP server written using Spark, exposing the following endpoints:

  • / - Static resources from Swagger UI for visualizing and interacting with API endpoints
  • /openapi.{yaml,json} - OpenAPI 3.0 document generated from source code using Swagger Core
  • /api/v1/<method> - RRM API methods

The OpenWiFi SDK dictates several API endpoints which must be implemented by every service, as well as endpoints specific to RRM providers. They are both marked here under the "SDK" tag.

Depending on RRM service configuration, the API server may also enable CORS selectively or globally, and OpenWiFi auth (via Bearer tokens or internal API keys).

Provisioning Monitor

ProvMonitor syncs device topology ("venues") and configuration with the OpenWiFi Provisioning service (when enabled).

RRM Scheduler

RRMScheduler uses the Quartz Job Scheduler to schedule RRM algorithms to run per zone with different intervals and parameters. The schedules are specified in the device configuration as RRMSchedule and are applied only at the zone and network layers.

Optimizers

The optimizers implement the RRM algorithms, and are described in detail in ALGORITHMS.md.

The RRMAlgorithm class provides a common entry point for all algorithm invocations. The general logic is as follows:

  • Identify the algorithm type (AlgorithmType), implementation class ("mode"), and any algorithm arguments
  • Take the current data model snapshot from Modeler as input
  • Compute the new device configs, then save and push them via ConfigManager