4242)
4343
4444
45- def render_shadow_yaml (
45+ def _peer_env (
4646 * ,
4747 num_nodes : int ,
48- sim_stop_time_s : int ,
49- publisher_start_s : int ,
50- connect_to : int = 2 ,
51- muxer : Literal ["yamux" , "mplex" , "quic" ] = "yamux" ,
52- discovery : Literal ["static" , "kad-dht" ] = "static" ,
53- start_sleep : int = 60 ,
54- metrics_interval_s : int = 15 ,
55- seed : int = 1 ,
56- model_unblocked_syscall_latency : bool = False ,
57- strace_logging_mode : str = "off" ,
58- lsquic_tick_floor_us : int = 0 ,
59- start_jitter_ms : int = 0 ,
60- requester_app_path : str = _REQUESTER_APP_PATH ,
48+ connect_to : int ,
49+ muxer : str ,
50+ discovery : str ,
51+ start_sleep : int ,
52+ metrics_interval_s : int ,
53+ lsquic_tick_floor_us : int ,
6154) -> dict :
62- """Build the shadow.yaml dict: N peer hosts running `./main` + a publisher host
63- running the pod-api-requester in batch mode against the peers' `/publish`
64- endpoints. The traffic shape (message count, size, pacing) lives in the
65- requester's own config (see `render_publisher_config`), mounted at
66- `{_CONFIG_MOUNT}/{_PUBLISHER_CONFIG}`.
67-
68- discovery selects mesh formation: "static" dials CONNECTTO peers by pod-N
69- hostname; "kad-dht" adds a `bootstrap-0` anchor host that peers discover
70- through (Shadow resolves it by hostname, so no k8s Service is needed)."""
71- if connect_to >= num_nodes :
72- raise ValueError (f"connect_to ({ connect_to } ) must be smaller than num_nodes ({ num_nodes } )." )
73-
74- peer_env = {
55+ """Environment for a relay (pod-*) node."""
56+ env = {
7557 "PEERS" : str (num_nodes ),
7658 "CONNECTTO" : str (connect_to ),
7759 "SHADOWENV" : "true" , # env.nim requires the literal string "true"
@@ -82,14 +64,18 @@ def render_shadow_yaml(
8264 }
8365 if lsquic_tick_floor_us > 0 :
8466 # Needs the tick-floor test-node image (stock images ignore the env var).
85- peer_env ["LSQUIC_TICK_FLOOR_US" ] = str (lsquic_tick_floor_us )
67+ env ["LSQUIC_TICK_FLOOR_US" ] = str (lsquic_tick_floor_us )
8668 if discovery == "kad-dht" :
87- peer_env ["NODE_ROLE" ] = "RoleNormal"
88- peer_env ["SERVICE" ] = "bootstrap-0"
89- # start_jitter_ms staggers per-pod process start so peers don't wake and dial at
90- # one simulated instant (lockstep wakes force simultaneous-dial collisions that
91- # never occur on real hosts).
92- hosts = {
69+ env ["NODE_ROLE" ] = "RoleNormal"
70+ env ["SERVICE" ] = "bootstrap-0"
71+ return env
72+
73+
74+ def _peer_hosts (num_nodes : int , peer_env : dict , start_jitter_ms : int ) -> dict :
75+ """The N relay hosts (pod-0..pod-(N-1)). start_jitter_ms staggers per-pod process
76+ start so peers don't wake and dial at one simulated instant (lockstep wakes force
77+ simultaneous-dial collisions that never occur on real hosts)."""
78+ return {
9379 f"pod-{ i } " : {
9480 "network_node_id" : 0 ,
9581 "processes" : [
@@ -104,35 +90,47 @@ def render_shadow_yaml(
10490 }
10591 for i in range (num_nodes )
10692 }
107- if discovery == "kad-dht" :
108- hosts ["bootstrap-0" ] = {
109- "network_node_id" : 0 ,
110- "processes" : [
111- {
112- "path" : "./main" ,
113- "start_time" : "5s" ,
114- "expected_final_state" : "running" ,
115- "environment" : {
116- "PEERS" : str (num_nodes ),
117- "SHADOWENV" : "true" ,
118- "MUXER" : muxer ,
119- "DISCOVERY" : "kad-dht" ,
120- "NODE_ROLE" : "RoleBootstrap" ,
121- # the single anchor must accept every node's bootstrap dial,
122- # so lift its cap above the network size (default is 250).
123- "MAXCONNECTIONS" : str (num_nodes + 100 ),
124- "STARTSLEEP" : str (start_sleep ),
125- "METRICS_INTERVAL_S" : str (metrics_interval_s ),
126- ** (
127- {"LSQUIC_TICK_FLOOR_US" : str (lsquic_tick_floor_us )}
128- if lsquic_tick_floor_us > 0
129- else {}
130- ),
131- },
132- }
133- ],
134- }
135- hosts ["publisher" ] = {
93+
94+
95+ def _bootstrap_host (
96+ * ,
97+ num_nodes : int ,
98+ muxer : str ,
99+ start_sleep : int ,
100+ metrics_interval_s : int ,
101+ lsquic_tick_floor_us : int ,
102+ ) -> dict :
103+ """The kad-dht anchor (bootstrap-0); peers discover through it by hostname."""
104+ env = {
105+ "PEERS" : str (num_nodes ),
106+ "SHADOWENV" : "true" ,
107+ "MUXER" : muxer ,
108+ "DISCOVERY" : "kad-dht" ,
109+ "NODE_ROLE" : "RoleBootstrap" ,
110+ # the single anchor must accept every node's bootstrap dial, so lift its cap
111+ # above the network size (default is 250).
112+ "MAXCONNECTIONS" : str (num_nodes + 100 ),
113+ "STARTSLEEP" : str (start_sleep ),
114+ "METRICS_INTERVAL_S" : str (metrics_interval_s ),
115+ }
116+ if lsquic_tick_floor_us > 0 :
117+ env ["LSQUIC_TICK_FLOOR_US" ] = str (lsquic_tick_floor_us )
118+ return {
119+ "network_node_id" : 0 ,
120+ "processes" : [
121+ {
122+ "path" : "./main" ,
123+ "start_time" : "5s" ,
124+ "expected_final_state" : "running" ,
125+ "environment" : env ,
126+ }
127+ ],
128+ }
129+
130+
131+ def _publisher_host (publisher_start_s : int , requester_app_path : str ) -> dict :
132+ """The publisher host: runs the pod-api-requester in batch mode against the peers."""
133+ return {
136134 "network_node_id" : 0 ,
137135 "processes" : [
138136 {
@@ -146,6 +144,56 @@ def render_shadow_yaml(
146144 }
147145 ],
148146 }
147+
148+
149+ def render_shadow_yaml (
150+ * ,
151+ num_nodes : int ,
152+ sim_stop_time_s : int ,
153+ publisher_start_s : int ,
154+ connect_to : int = 2 ,
155+ muxer : Literal ["yamux" , "mplex" , "quic" ] = "yamux" ,
156+ discovery : Literal ["static" , "kad-dht" ] = "static" ,
157+ start_sleep : int = 60 ,
158+ metrics_interval_s : int = 15 ,
159+ seed : int = 1 ,
160+ model_unblocked_syscall_latency : bool = False ,
161+ strace_logging_mode : str = "off" ,
162+ lsquic_tick_floor_us : int = 0 ,
163+ start_jitter_ms : int = 0 ,
164+ requester_app_path : str = _REQUESTER_APP_PATH ,
165+ ) -> dict :
166+ """Build the shadow.yaml dict: N peer hosts running `./main` + a publisher host
167+ running the pod-api-requester in batch mode against the peers' `/publish`
168+ endpoints. The traffic shape (message count, size, pacing) lives in the
169+ requester's own config (see `render_publisher_config`), mounted at
170+ `{_CONFIG_MOUNT}/{_PUBLISHER_CONFIG}`.
171+
172+ discovery selects mesh formation: "static" dials CONNECTTO peers by pod-N
173+ hostname; "kad-dht" adds a `bootstrap-0` anchor host that peers discover
174+ through (Shadow resolves it by hostname, so no k8s Service is needed)."""
175+ if connect_to >= num_nodes :
176+ raise ValueError (f"connect_to ({ connect_to } ) must be smaller than num_nodes ({ num_nodes } )." )
177+
178+ peer_env = _peer_env (
179+ num_nodes = num_nodes ,
180+ connect_to = connect_to ,
181+ muxer = muxer ,
182+ discovery = discovery ,
183+ start_sleep = start_sleep ,
184+ metrics_interval_s = metrics_interval_s ,
185+ lsquic_tick_floor_us = lsquic_tick_floor_us ,
186+ )
187+ hosts = _peer_hosts (num_nodes , peer_env , start_jitter_ms )
188+ if discovery == "kad-dht" :
189+ hosts ["bootstrap-0" ] = _bootstrap_host (
190+ num_nodes = num_nodes ,
191+ muxer = muxer ,
192+ start_sleep = start_sleep ,
193+ metrics_interval_s = metrics_interval_s ,
194+ lsquic_tick_floor_us = lsquic_tick_floor_us ,
195+ )
196+ hosts ["publisher" ] = _publisher_host (publisher_start_s , requester_app_path )
149197 # Always render the seed so the run's shadow.yaml records it (Shadow defaults to 1).
150198 config = {
151199 "general" : {
0 commit comments