Skip to content

Commit 8009e44

Browse files
committed
scenarios: use initContainer
1 parent 748112a commit 8009e44

File tree

10 files changed

+87
-24
lines changed

10 files changed

+87
-24
lines changed

resources/charts/commander/templates/pod.yaml

+18-7
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,30 @@ metadata:
88
mission: commander
99
spec:
1010
restartPolicy: {{ .Values.restartPolicy }}
11+
initContainers:
12+
- name: init
13+
image: busybox
14+
command: ["/bin/sh", "-c"]
15+
args:
16+
- |
17+
while [ ! -f /shared/archive.pyz ]; do
18+
echo "Waiting for /shared/archive.pyz to exist..."
19+
sleep 2
20+
done
21+
volumeMounts:
22+
- name: shared-volume
23+
mountPath: /shared
1124
containers:
1225
- name: {{ .Chart.Name }}
1326
image: python:3.12-slim
1427
imagePullPolicy: IfNotPresent
1528
command: ["/bin/sh", "-c"]
1629
args:
1730
- |
18-
python3 /archive.pyz {{ .Values.args }}
31+
python3 /shared/archive.pyz {{ .Values.args }}
1932
volumeMounts:
20-
- name: warnet
21-
mountPath: /warnet.json
22-
subPath: warnet.json
33+
- name: shared-volume
34+
mountPath: /shared
2335
volumes:
24-
- name: warnet
25-
configMap:
26-
name: {{ include "commander.fullname" . }}-warnet
36+
- name: shared-volume
37+
emptyDir: {}

resources/scenarios/commander.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import signal
99
import sys
1010
import tempfile
11-
from pathlib import Path
1211
from typing import Dict
1312

1413
from test_framework.authproxy import AuthServiceProxy
@@ -21,7 +20,7 @@
2120
from test_framework.test_node import TestNode
2221
from test_framework.util import PortSeed, get_rpc_proxy
2322

24-
WARNET_FILE = Path("/warnet.json")
23+
WARNET_FILE = "/shared/warnet.json"
2524

2625
try:
2726
with open(WARNET_FILE) as file:

src/warnet/control.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import base64
21
import io
32
import json
43
import os
@@ -23,6 +22,8 @@
2322
get_mission,
2423
get_pods,
2524
snapshot_bitcoin_datadir,
25+
wait_for_init,
26+
write_file_to_container,
2627
)
2728
from .process import run_command, stream_command
2829

@@ -193,7 +194,7 @@ def run(scenario_file: str, additional_args: tuple[str]):
193194
]
194195

195196
# Encode tank data for warnet.json
196-
warnet_data = base64.b64encode(json.dumps(tanks).encode()).decode()
197+
warnet_data = json.dumps(tanks).encode()
197198

198199
# Create in-memory buffer to store python archive instead of writing to disk
199200
archive_buffer = io.BytesIO()
@@ -217,8 +218,9 @@ def filter(path):
217218

218219
# Encode the binary data as Base64
219220
archive_buffer.seek(0)
220-
archive_data = base64.b64encode(archive_buffer.read()).decode()
221+
archive_data = archive_buffer.read()
221222

223+
# Start the commander pod with python and init containers
222224
try:
223225
# Construct Helm command
224226
helm_command = [
@@ -229,8 +231,6 @@ def filter(path):
229231
namespace,
230232
"--set",
231233
f"fullnameOverride={name}",
232-
"--set",
233-
f"warnet={warnet_data}",
234234
]
235235

236236
# Add additional arguments
@@ -243,16 +243,23 @@ def filter(path):
243243
result = subprocess.run(helm_command, check=True, capture_output=True, text=True)
244244

245245
if result.returncode == 0:
246-
print(f"Successfully started scenario: {scenario_name}")
246+
print(f"Successfully deployed scenario commander: {scenario_name}")
247247
print(f"Commander pod name: {name}")
248248
else:
249-
print(f"Failed to start scenario: {scenario_name}")
249+
print(f"Failed to deploy scenario commander: {scenario_name}")
250250
print(f"Error: {result.stderr}")
251251

252252
except subprocess.CalledProcessError as e:
253-
print(f"Failed to start scenario: {scenario_name}")
253+
print(f"Failed to deploy scenario commander: {scenario_name}")
254254
print(f"Error: {e.stderr}")
255255

256+
# upload scenario files and network data to the init container
257+
wait_for_init(name)
258+
if write_file_to_container(
259+
name, "init", "/shared/warnet.json", warnet_data
260+
) and write_file_to_container(name, "init", "/shared/archive.pyz", archive_data):
261+
print(f"Successfully uploaded scenario data to commander: {scenario_name}")
262+
256263

257264
@click.command()
258265
@click.argument("pod_name", type=str, default="")

src/warnet/k8s.py

+43
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,24 @@ def wait_for_pod_ready(name, namespace, timeout=300):
262262
return False
263263

264264

265+
def wait_for_init(pod_name, timeout=300):
266+
sclient = get_static_client()
267+
namespace = get_default_namespace()
268+
w = watch.Watch()
269+
for event in w.stream(
270+
sclient.list_namespaced_pod, namespace=namespace, timeout_seconds=timeout
271+
):
272+
pod = event["object"]
273+
if pod.metadata.name == pod_name:
274+
for init_container_status in pod.status.init_container_statuses:
275+
if init_container_status.state.running:
276+
print(f"initContainer in pod {pod_name} is ready")
277+
w.stop()
278+
return True
279+
print(f"Timeout waiting for initContainer in {pod_name} to be ready.")
280+
return False
281+
282+
265283
def wait_for_ingress_controller(timeout=300):
266284
# get name of ingress controller pod
267285
sclient = get_static_client()
@@ -282,3 +300,28 @@ def get_ingress_ip_or_host():
282300
except Exception as e:
283301
print(f"Error getting ingress IP: {e}")
284302
return None
303+
304+
305+
def write_file_to_container(pod_name, container_name, dst_path, data):
306+
sclient = get_static_client()
307+
namespace = get_default_namespace()
308+
exec_command = ["sh", "-c", f"cat > {dst_path}"]
309+
try:
310+
res = stream(
311+
sclient.connect_get_namespaced_pod_exec,
312+
pod_name,
313+
namespace,
314+
command=exec_command,
315+
container=container_name,
316+
stdin=True,
317+
stderr=True,
318+
stdout=True,
319+
tty=False,
320+
_preload_content=False,
321+
)
322+
res.write_stdin(data)
323+
res.close()
324+
print(f"Successfully copied data to {pod_name}({container_name}):{dst_path}")
325+
return True
326+
except Exception as e:
327+
print(f"Failed to copy data to {pod_name}({container_name}):{dst_path}:\n{e}")

src/warnet/network.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def copy_scenario_defaults(directory: Path):
4444
directory,
4545
SCENARIOS_DIR.name,
4646
SCENARIOS_DIR,
47-
["__pycache__", "TEST_*.py"],
47+
["__pycache__", "testscenario_*.py"],
4848
)
4949

5050

test/dag_connection_test.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class DAGConnectionTest(TestBase):
1010
def __init__(self):
1111
super().__init__()
1212
self.network_dir = Path(os.path.dirname(__file__)) / "data" / "ten_semi_unconnected"
13+
self.scen_dir = Path(os.path.dirname(__file__)).parent / "resources" / "scenarios"
1314

1415
def run_test(self):
1516
try:
@@ -25,8 +26,9 @@ def setup_network(self):
2526
self.wait_for_all_edges()
2627

2728
def run_connect_dag_scenario(self):
28-
self.log.info("Running connect_dag scenario")
29-
self.warnet("run resources/scenarios/TEST_connect_dag.py")
29+
scenario_file = self.scen_dir / "testscenario_connect_dag.py"
30+
self.log.info(f"Running scenario from: {scenario_file}")
31+
self.warnet(f"run {scenario_file}")
3032
self.wait_for_all_scenarios()
3133

3234

test/scenarios_test.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ScenariosTest(TestBase):
1414
def __init__(self):
1515
super().__init__()
1616
self.network_dir = Path(os.path.dirname(__file__)) / "data" / "12_node_ring"
17+
self.scen_dir = Path(os.path.dirname(__file__)).parent / "resources" / "scenarios"
1718

1819
def run_test(self):
1920
try:
@@ -71,7 +72,7 @@ def check_blocks(self, target_blocks, start: int = 0):
7172
return count >= start + target_blocks
7273

7374
def run_and_check_miner_scenario_from_file(self):
74-
scenario_file = "resources/scenarios/miner_std.py"
75+
scenario_file = self.scen_dir / "miner_std.py"
7576
self.log.info(f"Running scenario from file: {scenario_file}")
7677
self.warnet(f"run {scenario_file} --allnodes --interval=1")
7778
start = int(self.warnet("bitcoin rpc tank-0000 getblockcount"))
@@ -82,19 +83,19 @@ def run_and_check_miner_scenario_from_file(self):
8283
self.stop_scenario()
8384

8485
def run_and_check_scenario_from_file(self):
85-
scenario_file = "resources/scenarios/TEST_p2p_interface.py"
86+
scenario_file = self.scen_dir / "testscenario_p2p_interface.py"
8687
self.log.info(f"Running scenario from: {scenario_file}")
8788
self.warnet(f"run {scenario_file}")
8889
self.wait_for_predicate(self.check_scenario_clean_exit)
8990

9091
def check_regtest_recon(self):
91-
scenario_file = "resources/scenarios/reconnaissance.py"
92+
scenario_file = self.scen_dir / "reconnaissance.py"
9293
self.log.info(f"Running scenario from file: {scenario_file}")
9394
self.warnet(f"run {scenario_file}")
9495
self.wait_for_predicate(self.check_scenario_clean_exit)
9596

9697
def check_active_count(self):
97-
scenario_file = "resources/scenarios/TEST_buggy_failure.py"
98+
scenario_file = self.scen_dir / "testscenario_buggy_failure.py"
9899
self.log.info(f"Running scenario from: {scenario_file}")
99100
self.warnet(f"run {scenario_file}")
100101

0 commit comments

Comments
 (0)