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}