Skip to main content

zlayer_types/api/
overlay.rs

1//! Overlay network API DTOs.
2//!
3//! Wire types for the `/api/v1/overlay/*` HTTP surface, shared between
4//! `zlayer-api` (server) and `zlayer-client` / `zlayer-manager` (clients).
5//! These are the response shapes consumed by both the daemon and SDK
6//! clients.
7//!
8//! See [`crate::overlay`] for the underlying configuration types.
9
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use std::net::IpAddr;
13use utoipa::ToSchema;
14
15use crate::overlay::OverlayMode;
16
17/// Where on a specific node a service's overlay terminates.
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
19pub struct BridgeInfo {
20    /// Linux bridge name (`br-svc-<hash>`), max 15 chars per IFNAMSIZ.
21    pub name: String,
22    /// CIDR of the service subnet assigned to this node.
23    #[schema(value_type = String, example = "10.201.0.0/24")]
24    pub subnet: ipnet::IpNet,
25    /// Gateway IP within the subnet (first usable address); the bridge's
26    /// own L3 address. Containers' default route points here.
27    #[schema(value_type = String, example = "10.201.0.1")]
28    pub gateway: IpAddr,
29    /// Node identifier (stringified to avoid leaking `NodeId` type details
30    /// across crate boundaries).
31    pub node_id: String,
32}
33
34/// Status of a service's overlay across the cluster.
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
36pub struct ServiceOverlayStatus {
37    pub service: String,
38    /// Mode the daemon resolved for this service (after `resolve`).
39    pub mode: OverlayMode,
40    /// One entry per node where this service has at least one container
41    /// attached. Keys are node IDs as stringified.
42    pub bridges_by_node: HashMap<String, BridgeInfo>,
43}
44
45/// Overlay network status response
46#[derive(Debug, Serialize, Deserialize, ToSchema)]
47pub struct OverlayStatusResponse {
48    /// Overlay interface name
49    pub interface: String,
50    /// Whether this node is the cluster leader
51    pub is_leader: bool,
52    /// Node's overlay IP address
53    pub node_ip: String,
54    /// Overlay network CIDR
55    pub cidr: String,
56    /// Overlay listen port (`WireGuard` protocol)
57    pub port: u16,
58    /// Total number of peers
59    pub total_peers: usize,
60    /// Number of healthy peers
61    pub healthy_peers: usize,
62    /// Number of unhealthy peers
63    pub unhealthy_peers: usize,
64    /// Last health check timestamp (unix epoch seconds)
65    pub last_check: u64,
66}
67
68/// Peer information
69#[derive(Debug, Serialize, Deserialize, ToSchema)]
70pub struct PeerInfo {
71    /// Peer's public key
72    pub public_key: String,
73    /// Peer's overlay IP address
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub overlay_ip: Option<String>,
76    /// Whether the peer is healthy
77    pub healthy: bool,
78    /// Seconds since last handshake
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub last_handshake_secs: Option<u64>,
81    /// Last ping latency in milliseconds
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub last_ping_ms: Option<u64>,
84    /// Number of consecutive health check failures
85    pub failure_count: u32,
86    /// Last health check timestamp (unix epoch seconds)
87    pub last_check: u64,
88}
89
90/// Peer list response
91#[derive(Debug, Serialize, Deserialize, ToSchema)]
92pub struct PeerListResponse {
93    /// Total number of peers
94    pub total: usize,
95    /// Number of healthy peers
96    pub healthy: usize,
97    /// List of peer information
98    pub peers: Vec<PeerInfo>,
99}
100
101/// IP allocation status response
102#[derive(Debug, Serialize, Deserialize, ToSchema)]
103pub struct IpAllocationResponse {
104    /// Overlay network CIDR
105    pub cidr: String,
106    /// Total available IPs in the range
107    pub total_ips: u32,
108    /// Number of allocated IPs
109    pub allocated_count: usize,
110    /// Number of available IPs
111    pub available_count: u32,
112    /// Utilization percentage (0.0 - 100.0)
113    pub utilization_percent: f64,
114    /// List of allocated IP addresses (only included if requested)
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub allocated_ips: Option<Vec<String>>,
117}
118
119/// NAT traversal status response
120#[derive(Debug, Serialize, Deserialize, ToSchema)]
121pub struct NatStatusResponse {
122    /// Whether NAT traversal is enabled in the daemon's config
123    pub enabled: bool,
124    /// Configured STUN servers (host:port)
125    pub stun_servers: Vec<String>,
126    /// Configured TURN/relay servers (host:port)
127    pub turn_servers: Vec<String>,
128    /// Address of the locally-bound built-in relay server, if running
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub relay_server_bind: Option<String>,
131    /// Locally gathered ICE candidates
132    pub candidates: Vec<NatCandidateDto>,
133    /// Per-peer NAT connectivity state
134    pub peers: Vec<NatPeerDto>,
135    /// Unix epoch seconds of the last successful STUN refresh
136    pub last_refresh: u64,
137}
138
139/// Locally gathered NAT candidate (`Host` / `ServerReflexive` / `Relay`).
140#[derive(Debug, Serialize, Deserialize, ToSchema)]
141pub struct NatCandidateDto {
142    /// `Host` / `ServerReflexive` / `Relay`
143    pub kind: String,
144    /// Transport (e.g. "udp")
145    pub transport: String,
146    /// Address (host:port)
147    pub address: String,
148    /// Priority (higher = preferred)
149    pub priority: u32,
150}
151
152/// Per-peer NAT connectivity entry.
153#[derive(Debug, Serialize, Deserialize, ToSchema)]
154pub struct NatPeerDto {
155    /// Peer node ID
156    pub node_id: String,
157    /// Direct / `HolePunched` / Relayed / Unreachable
158    pub connection_type: String,
159    /// Selected remote endpoint, if any
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub remote_endpoint: Option<String>,
162}
163
164/// DNS service status response
165#[derive(Debug, Serialize, Deserialize, ToSchema)]
166pub struct DnsStatusResponse {
167    /// Whether DNS service is enabled
168    pub enabled: bool,
169    /// DNS zone name
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub zone: Option<String>,
172    /// DNS server port
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub port: Option<u16>,
175    /// DNS server bind address
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub bind_addr: Option<String>,
178    /// Number of registered services
179    pub service_count: usize,
180    /// List of registered service names
181    pub services: Vec<String>,
182}