Skip to content

Commit 48aad04

Browse files
committed
add preNode/postNode; add exec/waitFor
1 parent a1403f9 commit 48aad04

File tree

5 files changed

+94
-6
lines changed

5 files changed

+94
-6
lines changed

docs/plugins.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@ nodes:
1111
<<snip>>
1212

1313
plugins:
14-
- path/to/plugin/file/relative/to/the/network/dot/yaml/file/plugin.py
14+
preNode: # Run commands before each node launches
15+
- "echo This is preNode" # This command is a simple string
16+
postNode: # Run commands after each node launches
17+
- exec: "echo This is also postNode, but we waited for 'warnet status'" # This command is also a simple string ...
18+
waitFor: "warnet status" # ... but it will execute after this command completes successfully
19+
- exec: "echo This is postNode" # Simply using 'exec' also just works
20+
preDeploy: # Run commands before Warnet runs the bulk of its `deploy` code
21+
- "echo This is preDeploy"
22+
postDeploy: # Run these commands after Warnet has finished the bulk of its `deploy` code
23+
- "../../plugins/simln/plugin.py launch-activity '[{\"source\": \"tank-0003-ln\", \"destination\": \"tank-0005-ln\", \"interval_secs\": 1, \"amount_msat\": 2000}]'"
24+
- exec: "../../plugins/simln/plugin.py list-pod-names"
25+
waitFor: "../../plugins/simln/plugin.py get-example-activity"
1526
````
1627

1728
Warnet will execute these plugin commands after each invocation of `warnet deploy`.

src/warnet/constants.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030
class HookValue(Enum):
3131
PRE_DEPLOY = "preDeploy"
3232
POST_DEPLOY = "postDeploy"
33+
PRE_NODE = "preNode"
34+
POST_NODE = "postNode"
35+
36+
37+
class HookOptions(Enum):
38+
EXEC = "exec"
39+
WAIT_FOR = "waitFor"
3340

3441

3542
# Directories and files for non-python assets, e.g., helm charts, example scenarios, default configs

src/warnet/deploy.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import subprocess
23
import sys
34
import tempfile
@@ -24,6 +25,7 @@
2425
NETWORK_FILE,
2526
SCENARIOS_DIR,
2627
WARGAMES_NAMESPACE_PREFIX,
28+
HookOptions,
2729
HookValue,
2830
)
2931
from .control import _run
@@ -35,7 +37,7 @@
3537
wait_for_ingress_controller,
3638
wait_for_pod_ready,
3739
)
38-
from .process import run_command, stream_command
40+
from .process import run_command, stream_command, wait_for_run
3941

4042
HINT = "\nAre you trying to run a scenario? See `warnet run --help`"
4143

@@ -129,6 +131,12 @@ def _deploy(directory, debug, namespace, to_all_users):
129131

130132

131133
def run_plugins(directory, hook_value: HookValue):
134+
""" " Run the plugin commands within a given hook value"""
135+
136+
def is_relative(path: str) -> bool:
137+
"""Determine if the path is a command or a path to a command"""
138+
return os.path.dirname(path) != ""
139+
132140
network_file_path = directory / NETWORK_FILE
133141

134142
with network_file_path.open() as f:
@@ -139,9 +147,39 @@ def run_plugins(directory, hook_value: HookValue):
139147
plugins_section = network_file.get("plugins", {})
140148
plugins = plugins_section.get(hook_value.value) or []
141149
for plugin_cmd in plugins:
142-
fully_qualified_cmd = network_file_path.parent / plugin_cmd # relative to network.yaml
143-
print(f"Plugin command: {fully_qualified_cmd}")
144-
print(run_command(str(fully_qualified_cmd)))
150+
match plugin_cmd:
151+
case {HookOptions.EXEC.value: cmd, HookOptions.WAIT_FOR.value: predicate}:
152+
if is_relative(cmd):
153+
cmd = network_file_path.parent / cmd
154+
print(f"{HookOptions.EXEC.value}: {cmd}")
155+
156+
if is_relative(predicate):
157+
predicate = network_file_path.parent / predicate
158+
print(f"{HookOptions.WAIT_FOR.value}: {predicate}")
159+
160+
wait_for_run(str(predicate))
161+
print(run_command(str(cmd)))
162+
163+
case {HookOptions.EXEC.value: cmd}:
164+
if is_relative(cmd):
165+
cmd = network_file_path.parent / cmd
166+
print(f"{HookOptions.EXEC.value}: {cmd}")
167+
print(run_command(str(cmd)))
168+
169+
case str():
170+
cmd = plugin_cmd
171+
if is_relative(cmd):
172+
cmd = network_file_path.parent / plugin_cmd
173+
print(f"{cmd}")
174+
print(run_command(str(cmd)))
175+
176+
case _:
177+
print(
178+
f"The following plugin command does not match known plugin command structures: {plugin_cmd}"
179+
)
180+
print(f"Known hook values: {[v.value for v in HookValue]}")
181+
print(f"Known hook options: {[v.value for v in HookOptions]}")
182+
sys.exit(1)
145183

146184

147185
def check_logging_required(directory: Path):
@@ -358,9 +396,14 @@ def deploy_single_node(node, directory: Path, debug: bool, namespace: str):
358396
temp_override_file_path = Path(temp_file.name)
359397
cmd = f"{cmd} -f {temp_override_file_path}"
360398

399+
run_plugins(directory, HookValue.PRE_NODE)
400+
361401
if not stream_command(cmd):
362402
click.echo(f"Failed to run Helm command: {cmd}")
363403
return
404+
405+
run_plugins(directory, HookValue.POST_NODE)
406+
364407
except Exception as e:
365408
click.echo(f"Error: {e}")
366409
return

src/warnet/process.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import subprocess
2+
from time import sleep
23

34

45
def run_command(command: str) -> str:
@@ -29,3 +30,21 @@ def stream_command(command: str) -> bool:
2930
if return_code != 0:
3031
raise Exception(message)
3132
return True
33+
34+
35+
def wait_for_run(predicate, timeout=5 * 60, interval=5):
36+
print(f"Waiting for predicate with timeout {timeout}s and interval {interval}s")
37+
print(predicate)
38+
while timeout > 0:
39+
try:
40+
if run_command(predicate):
41+
return
42+
except Exception:
43+
pass
44+
sleep(interval)
45+
timeout -= interval
46+
import inspect
47+
48+
raise Exception(
49+
f"Timed out waiting for Truth from predicate: {inspect.getsource(predicate).strip()}"
50+
)

test/data/ln/network.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ nodes:
5454
lnd: true
5555

5656
plugins:
57+
preNode:
58+
- "echo This is preNode"
59+
postNode:
60+
- exec: "echo This is postNode"
61+
- exec: "echo This is also postNode, but we waited for 'warnet status'"
62+
waitFor: "warnet status"
5763
preDeploy:
58-
- "../../../resources/plugins/simln/plugin.py"
64+
- "echo This is preDeploy"
5965
postDeploy:
6066
- "../../../resources/plugins/simln/plugin.py launch-activity '[{\"source\": \"tank-0003-ln\", \"destination\": \"tank-0005-ln\", \"interval_secs\": 1, \"amount_msat\": 2000}]'"
67+
- exec: "../../../resources/plugins/simln/plugin.py list-pod-names"
68+
waitFor: "../../../resources/plugins/simln/plugin.py get-example-activity"

0 commit comments

Comments
 (0)