Skip to content

CP/DP split (Enterprise)

When to use this

  • You operate more than a handful of gateway instances and want one place to compile and distribute config -- the controller broadcasts generations; every edge hot-reloads.
  • Fleet-wide consistency matters more than per-instance autonomy: edges keep serving through controller outages on their last received generation.

Overview

Dwara Enterprise supports a control plane / data plane split architecture: dwara-controller (the control plane) manages config distribution to a fleet of dwara-edge (data planes) via a gRPC config watch (xDS-inspired). The embedded mode (single-process) stays first-class.

This is an Enterprise feature, gated behind the ent cargo feature.

For a runnable demonstration of the CP/DP split on one Docker network, see the Enterprise quickstart demo.

Enabling

Build with the ent feature:

sh
cargo build --features ent

Architecture

In the CP/DP split:

  • The control plane (dwara-controller) watches config sources (file), compiles configs, and pushes them to edges via a gRPC stream (xDS-inspired).
  • The data plane (dwara-edge) subscribes to the stream and applies config updates without restart.
  • The embedded mode (single-process) runs the same config compilation and publishing pipeline in-process, just without the gRPC transport.

Running the controller

sh
cargo run -p dwara-cli --bin dwara-controller --features ent -- \
    --bind 127.0.0.1:50051 \
    --config-source ./dwara.yaml \
    --leader

Environment variables:

VariableDefaultPurpose
DWARA_CP_BIND127.0.0.1:50051gRPC bind address
DWARA_CP_CONFIG_SOURCE./dwara.yamlconfig source file to watch
DWARA_CP_LEADERtruewhether this controller is the leader
DWARA_CP_POLL_INTERVAL_SECS2config source poll interval
DWARA_LOGdwara=info,dwara_core=infotracing filter; the controller's own events (leader election, generation publishes, compile failures) log as JSON, same pipeline as the gateway

Running an edge

sh
cargo run -p dwara-cli --bin dwara-edge --features ent -- \
    --controller-endpoint http://127.0.0.1:50051 \
    --edge-id edge-1 \
    --config-output /etc/dwara/dwara.yaml

Environment variables:

VariableDefaultPurpose
DWARA_CP_CONTROLLER_ENDPOINThttp://127.0.0.1:50051controller gRPC endpoint
DWARA_CP_EDGE_IDedge-1edge instance ID
DWARA_CP_EDGE_VERSION0.1.0edge version string
DWARA_CP_CONFIG_OUTPUT/etc/dwara/dwara.yamllocal config output path
DWARA_LOGdwara=info,dwara_core=infotracing filter; the edge's own events (connect, receive, apply, ack, reconnect) log as JSON, same pipeline as the gateway

Edge survives CP outage

Edges cache the last received config. If the controller becomes unavailable, edges continue serving traffic with the cached config. When the controller recovers, edges reconnect and receive any config updates.

HA controller

Multiple controllers can run simultaneously; only one is active (leader election). The active controller pushes config to edges; standby controllers watch and take over if the active controller fails.

Wire protocol

The gRPC service dwara.ControlPlane has two methods:

  • StreamConfigUpdates (server-streaming): the edge sends an EdgeRegistration, the controller streams ConfigUpdate messages.
  • Ack (unary): the edge sends a ConfigAck, the controller responds with an empty AckResponse.

All wire messages are hand-written prost structs that mirror the domain types 1:1. The transport uses a custom ProstCodec (no protoc/build-script dependency).

TLS

The CP-DP transport supports both plaintext and mTLS modes.

Plaintext (default, for development and trusted-network deployments): the existing EdgeClient::connect and serve_controller methods use plaintext gRPC.

mTLS (opt-in, for deployments that need end-to-end encryption on the CP-DP transport): the controller presents its server certificate, requires client authentication, and validates peer certificates against a configured CA. The edge presents its client certificate and validates the controller's certificate against the same CA.

The TLS configuration is passed programmatically to the edge/controller builders:

CpDpTlsConfig {
    cert_pem: "/path/to/edge.crt",
    key_pem: "/path/to/edge.key",
    ca_pem: "/path/to/ca.crt",
}
  • EdgeClient::connect_tls(endpoint, tls): the edge connects to the controller over TLS, presenting its client certificate and validating the controller's certificate against the CA.
  • serve_controller_tls(server, addr, tls): the controller serves over TLS, requiring client authentication and validating peer certificates against the CA.

The TLS-enabled methods require the tonic tls feature (enabled in the workspace dependency). The existing plaintext methods remain available for compatibility.

Fleet rolling upgrades

The dwara upgrade --fleet command automates fleet-wide rolling upgrades by driving the controller's wave-by-wave rollout policy. The controller reads its fleet.upgrade config block (order, max_concurrent, halt_on_failure) and pushes the current config generation to edges in label-selector waves, waiting for acks between waves.

sh
dwara upgrade --fleet --controller http://127.0.0.1:50051

Flags:

FlagDefaultPurpose
--controllerDWARA_CP_ENDPOINT or http://127.0.0.1:50051Controller gRPC endpoint
--ack-timeout-ms0 (controller default: 30s)Per-wave ack timeout

The command prints a per-wave breakdown (targeted, acked, failed) and exits 0 on success, 1 on failure. When halt_on_failure is true in the fleet config, the controller stops after the first wave with failures.

The controller must have a fleet block in its config source for the RPC to succeed; otherwise it returns failed_precondition.

Not yet implemented

  • Production leader election (Redis/etcd distributed lock or Raft)
  • Additional config sources (etcd, Consul, K8s API) beyond file watching

Try it

The repository ships a runnable CP/DP topology under quickstart/enterprise/: one controller and a fleet of two edges/gateways on a docker network, with a documented walkthrough of fleet convergence (edit one file, watch every data plane reload) and controller-outage survival.

Runnable demo

The demos/11-enterprise/ directory in the repository documents the CP/DP split and verifies the single-node OSS baseline (test script: test-01-cp-dp-split.sh); the controller and edge binaries need the ent build shown in the quickstarts above. The category README covers prerequisites and teardown.