From 99626b5eda290dcf5e9ee049ec4a6f5cfe14a0f1 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Tue, 24 Sep 2024 13:11:53 -0400 Subject: [PATCH 01/10] scenarios: remove unecessary import logic --- resources/scenarios/ln_init.py | 7 +------ resources/scenarios/miner_std.py | 7 +------ resources/scenarios/reconnaissance.py | 7 +------ resources/scenarios/signet_miner.py | 6 +----- resources/scenarios/tx_flood.py | 8 ++------ 5 files changed, 6 insertions(+), 29 deletions(-) diff --git a/resources/scenarios/ln_init.py b/resources/scenarios/ln_init.py index 59df5e38e..391246fd0 100644 --- a/resources/scenarios/ln_init.py +++ b/resources/scenarios/ln_init.py @@ -1,12 +1,7 @@ #!/usr/bin/env python3 from time import sleep - -# The base class exists inside the commander container -try: - from commander import Commander -except ImportError: - from resources.scenarios.commander import Commander +from commander import Commander class LNInit(Commander): diff --git a/resources/scenarios/miner_std.py b/resources/scenarios/miner_std.py index 5aa368d40..764210efc 100755 --- a/resources/scenarios/miner_std.py +++ b/resources/scenarios/miner_std.py @@ -1,12 +1,7 @@ #!/usr/bin/env python3 from time import sleep - -# The base class exists inside the commander container -try: - from commander import Commander -except ImportError: - from resources.scenarios.commander import Commander +from commander import Commander class Miner: diff --git a/resources/scenarios/reconnaissance.py b/resources/scenarios/reconnaissance.py index 3fc2269e4..2d500e274 100755 --- a/resources/scenarios/reconnaissance.py +++ b/resources/scenarios/reconnaissance.py @@ -2,12 +2,7 @@ import socket -# The base class exists inside the commander container when deployed, -# but requires a relative path inside the python source code for other functions. -try: - from commander import Commander -except ImportError: - from resources.scenarios.commander import Commander +from commander import Commander # The entire Bitcoin Core test_framework directory is available as a library from test_framework.messages import MSG_TX, CInv, hash256, msg_getdata diff --git a/resources/scenarios/signet_miner.py b/resources/scenarios/signet_miner.py index 0edc635e3..7c4652240 100644 --- a/resources/scenarios/signet_miner.py +++ b/resources/scenarios/signet_miner.py @@ -11,11 +11,7 @@ # we use the authproxy from the test framework. ### -# The base class exists inside the commander container -try: - from commander import Commander -except ImportError: - from resources.scenarios.commander import Commander +from commander import Commander import json import logging diff --git a/resources/scenarios/tx_flood.py b/resources/scenarios/tx_flood.py index a4896e958..996b88de5 100755 --- a/resources/scenarios/tx_flood.py +++ b/resources/scenarios/tx_flood.py @@ -1,13 +1,9 @@ #!/usr/bin/env python3 + import threading from random import choice, randrange from time import sleep - -# The base class exists inside the commander container -try: - from commander import Commander -except ImportError: - from resources.scenarios.commander import Commander +from commander import Commander class TXFlood(Commander): From 58c82041e20156a6bce95c2ee477b61abe51aada Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Tue, 24 Sep 2024 14:37:13 -0400 Subject: [PATCH 02/10] scenarios: move test_framework in here --- pyproject.toml | 2 +- {src => resources/scenarios}/test_framework/__init__.py | 0 {src => resources/scenarios}/test_framework/address.py | 0 {src => resources/scenarios}/test_framework/authproxy.py | 0 {src => resources/scenarios}/test_framework/bdb.py | 0 .../scenarios}/test_framework/bip340_test_vectors.csv | 0 {src => resources/scenarios}/test_framework/blockfilter.py | 0 {src => resources/scenarios}/test_framework/blocktools.py | 0 {src => resources/scenarios}/test_framework/coverage.py | 0 {src => resources/scenarios}/test_framework/descriptors.py | 0 {src => resources/scenarios}/test_framework/ellswift.py | 0 .../scenarios}/test_framework/ellswift_decode_test_vectors.csv | 0 {src => resources/scenarios}/test_framework/key.py | 0 {src => resources/scenarios}/test_framework/messages.py | 0 {src => resources/scenarios}/test_framework/muhash.py | 0 {src => resources/scenarios}/test_framework/netutil.py | 0 {src => resources/scenarios}/test_framework/p2p.py | 0 {src => resources/scenarios}/test_framework/psbt.py | 0 {src => resources/scenarios}/test_framework/ripemd160.py | 0 {src => resources/scenarios}/test_framework/script.py | 0 {src => resources/scenarios}/test_framework/script_util.py | 0 {src => resources/scenarios}/test_framework/secp256k1.py | 0 {src => resources/scenarios}/test_framework/segwit_addr.py | 0 {src => resources/scenarios}/test_framework/siphash.py | 0 {src => resources/scenarios}/test_framework/socks5.py | 0 {src => resources/scenarios}/test_framework/test_framework.py | 0 {src => resources/scenarios}/test_framework/test_node.py | 0 {src => resources/scenarios}/test_framework/test_shell.py | 0 {src => resources/scenarios}/test_framework/util.py | 0 {src => resources/scenarios}/test_framework/wallet.py | 0 {src => resources/scenarios}/test_framework/wallet_util.py | 0 .../scenarios}/test_framework/xswiftec_inv_test_vectors.csv | 0 ruff.toml | 2 +- 33 files changed, 2 insertions(+), 2 deletions(-) rename {src => resources/scenarios}/test_framework/__init__.py (100%) rename {src => resources/scenarios}/test_framework/address.py (100%) rename {src => resources/scenarios}/test_framework/authproxy.py (100%) rename {src => resources/scenarios}/test_framework/bdb.py (100%) rename {src => resources/scenarios}/test_framework/bip340_test_vectors.csv (100%) rename {src => resources/scenarios}/test_framework/blockfilter.py (100%) rename {src => resources/scenarios}/test_framework/blocktools.py (100%) rename {src => resources/scenarios}/test_framework/coverage.py (100%) rename {src => resources/scenarios}/test_framework/descriptors.py (100%) rename {src => resources/scenarios}/test_framework/ellswift.py (100%) rename {src => resources/scenarios}/test_framework/ellswift_decode_test_vectors.csv (100%) rename {src => resources/scenarios}/test_framework/key.py (100%) rename {src => resources/scenarios}/test_framework/messages.py (100%) rename {src => resources/scenarios}/test_framework/muhash.py (100%) rename {src => resources/scenarios}/test_framework/netutil.py (100%) rename {src => resources/scenarios}/test_framework/p2p.py (100%) rename {src => resources/scenarios}/test_framework/psbt.py (100%) rename {src => resources/scenarios}/test_framework/ripemd160.py (100%) rename {src => resources/scenarios}/test_framework/script.py (100%) rename {src => resources/scenarios}/test_framework/script_util.py (100%) rename {src => resources/scenarios}/test_framework/secp256k1.py (100%) rename {src => resources/scenarios}/test_framework/segwit_addr.py (100%) rename {src => resources/scenarios}/test_framework/siphash.py (100%) rename {src => resources/scenarios}/test_framework/socks5.py (100%) rename {src => resources/scenarios}/test_framework/test_framework.py (100%) rename {src => resources/scenarios}/test_framework/test_node.py (100%) rename {src => resources/scenarios}/test_framework/test_shell.py (100%) rename {src => resources/scenarios}/test_framework/util.py (100%) rename {src => resources/scenarios}/test_framework/wallet.py (100%) rename {src => resources/scenarios}/test_framework/wallet_util.py (100%) rename {src => resources/scenarios}/test_framework/xswiftec_inv_test_vectors.csv (100%) diff --git a/pyproject.toml b/pyproject.toml index 73f2876d5..5fe46468b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ build-backend = "setuptools.build_meta" include-package-data = true [tool.setuptools.packages.find] -where = ["src", "."] +where = ["src", ".", "resources/scenarios"] include = ["warnet*", "test_framework*", "resources*"] [tool.setuptools.package-data] diff --git a/src/test_framework/__init__.py b/resources/scenarios/test_framework/__init__.py similarity index 100% rename from src/test_framework/__init__.py rename to resources/scenarios/test_framework/__init__.py diff --git a/src/test_framework/address.py b/resources/scenarios/test_framework/address.py similarity index 100% rename from src/test_framework/address.py rename to resources/scenarios/test_framework/address.py diff --git a/src/test_framework/authproxy.py b/resources/scenarios/test_framework/authproxy.py similarity index 100% rename from src/test_framework/authproxy.py rename to resources/scenarios/test_framework/authproxy.py diff --git a/src/test_framework/bdb.py b/resources/scenarios/test_framework/bdb.py similarity index 100% rename from src/test_framework/bdb.py rename to resources/scenarios/test_framework/bdb.py diff --git a/src/test_framework/bip340_test_vectors.csv b/resources/scenarios/test_framework/bip340_test_vectors.csv similarity index 100% rename from src/test_framework/bip340_test_vectors.csv rename to resources/scenarios/test_framework/bip340_test_vectors.csv diff --git a/src/test_framework/blockfilter.py b/resources/scenarios/test_framework/blockfilter.py similarity index 100% rename from src/test_framework/blockfilter.py rename to resources/scenarios/test_framework/blockfilter.py diff --git a/src/test_framework/blocktools.py b/resources/scenarios/test_framework/blocktools.py similarity index 100% rename from src/test_framework/blocktools.py rename to resources/scenarios/test_framework/blocktools.py diff --git a/src/test_framework/coverage.py b/resources/scenarios/test_framework/coverage.py similarity index 100% rename from src/test_framework/coverage.py rename to resources/scenarios/test_framework/coverage.py diff --git a/src/test_framework/descriptors.py b/resources/scenarios/test_framework/descriptors.py similarity index 100% rename from src/test_framework/descriptors.py rename to resources/scenarios/test_framework/descriptors.py diff --git a/src/test_framework/ellswift.py b/resources/scenarios/test_framework/ellswift.py similarity index 100% rename from src/test_framework/ellswift.py rename to resources/scenarios/test_framework/ellswift.py diff --git a/src/test_framework/ellswift_decode_test_vectors.csv b/resources/scenarios/test_framework/ellswift_decode_test_vectors.csv similarity index 100% rename from src/test_framework/ellswift_decode_test_vectors.csv rename to resources/scenarios/test_framework/ellswift_decode_test_vectors.csv diff --git a/src/test_framework/key.py b/resources/scenarios/test_framework/key.py similarity index 100% rename from src/test_framework/key.py rename to resources/scenarios/test_framework/key.py diff --git a/src/test_framework/messages.py b/resources/scenarios/test_framework/messages.py similarity index 100% rename from src/test_framework/messages.py rename to resources/scenarios/test_framework/messages.py diff --git a/src/test_framework/muhash.py b/resources/scenarios/test_framework/muhash.py similarity index 100% rename from src/test_framework/muhash.py rename to resources/scenarios/test_framework/muhash.py diff --git a/src/test_framework/netutil.py b/resources/scenarios/test_framework/netutil.py similarity index 100% rename from src/test_framework/netutil.py rename to resources/scenarios/test_framework/netutil.py diff --git a/src/test_framework/p2p.py b/resources/scenarios/test_framework/p2p.py similarity index 100% rename from src/test_framework/p2p.py rename to resources/scenarios/test_framework/p2p.py diff --git a/src/test_framework/psbt.py b/resources/scenarios/test_framework/psbt.py similarity index 100% rename from src/test_framework/psbt.py rename to resources/scenarios/test_framework/psbt.py diff --git a/src/test_framework/ripemd160.py b/resources/scenarios/test_framework/ripemd160.py similarity index 100% rename from src/test_framework/ripemd160.py rename to resources/scenarios/test_framework/ripemd160.py diff --git a/src/test_framework/script.py b/resources/scenarios/test_framework/script.py similarity index 100% rename from src/test_framework/script.py rename to resources/scenarios/test_framework/script.py diff --git a/src/test_framework/script_util.py b/resources/scenarios/test_framework/script_util.py similarity index 100% rename from src/test_framework/script_util.py rename to resources/scenarios/test_framework/script_util.py diff --git a/src/test_framework/secp256k1.py b/resources/scenarios/test_framework/secp256k1.py similarity index 100% rename from src/test_framework/secp256k1.py rename to resources/scenarios/test_framework/secp256k1.py diff --git a/src/test_framework/segwit_addr.py b/resources/scenarios/test_framework/segwit_addr.py similarity index 100% rename from src/test_framework/segwit_addr.py rename to resources/scenarios/test_framework/segwit_addr.py diff --git a/src/test_framework/siphash.py b/resources/scenarios/test_framework/siphash.py similarity index 100% rename from src/test_framework/siphash.py rename to resources/scenarios/test_framework/siphash.py diff --git a/src/test_framework/socks5.py b/resources/scenarios/test_framework/socks5.py similarity index 100% rename from src/test_framework/socks5.py rename to resources/scenarios/test_framework/socks5.py diff --git a/src/test_framework/test_framework.py b/resources/scenarios/test_framework/test_framework.py similarity index 100% rename from src/test_framework/test_framework.py rename to resources/scenarios/test_framework/test_framework.py diff --git a/src/test_framework/test_node.py b/resources/scenarios/test_framework/test_node.py similarity index 100% rename from src/test_framework/test_node.py rename to resources/scenarios/test_framework/test_node.py diff --git a/src/test_framework/test_shell.py b/resources/scenarios/test_framework/test_shell.py similarity index 100% rename from src/test_framework/test_shell.py rename to resources/scenarios/test_framework/test_shell.py diff --git a/src/test_framework/util.py b/resources/scenarios/test_framework/util.py similarity index 100% rename from src/test_framework/util.py rename to resources/scenarios/test_framework/util.py diff --git a/src/test_framework/wallet.py b/resources/scenarios/test_framework/wallet.py similarity index 100% rename from src/test_framework/wallet.py rename to resources/scenarios/test_framework/wallet.py diff --git a/src/test_framework/wallet_util.py b/resources/scenarios/test_framework/wallet_util.py similarity index 100% rename from src/test_framework/wallet_util.py rename to resources/scenarios/test_framework/wallet_util.py diff --git a/src/test_framework/xswiftec_inv_test_vectors.csv b/resources/scenarios/test_framework/xswiftec_inv_test_vectors.csv similarity index 100% rename from src/test_framework/xswiftec_inv_test_vectors.csv rename to resources/scenarios/test_framework/xswiftec_inv_test_vectors.csv diff --git a/ruff.toml b/ruff.toml index 1e17fe2d6..0d6fc35bd 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ extend-exclude = [ - "resources/images/commander/src/test_framework", + "resources/scenarios/test_framework", "resources/images/exporter/authproxy.py", "resources/scenarios/signet_miner.py", "src/test_framework/*", From 510329e235ad4d4074b68bc11b83483ab364437a Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Tue, 24 Sep 2024 14:42:24 -0400 Subject: [PATCH 03/10] scenarios: get -- --help before using any helm or k8s commands --- src/warnet/control.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/warnet/control.py b/src/warnet/control.py index 782764cd9..fed633cae 100644 --- a/src/warnet/control.py +++ b/src/warnet/control.py @@ -169,6 +169,9 @@ def run(scenario_file: str, additional_args: tuple[str]): scenario_path = Path(scenario_file).resolve() scenario_name = scenario_path.stem + if additional_args and ("--help" in additional_args or "-h" in additional_args): + return subprocess.run([sys.executable, scenario_path, "--help"]) + with open(scenario_path, "rb") as file: scenario_data = base64.b64encode(file.read()).decode() @@ -210,8 +213,6 @@ def run(scenario_file: str, additional_args: tuple[str]): # Add additional arguments if additional_args: helm_command.extend(["--set", f"args={' '.join(additional_args)}"]) - if "--help" in additional_args or "-h" in additional_args: - return subprocess.run([sys.executable, scenario_path, "--help"]) helm_command.extend([name, COMMANDER_CHART]) From f10ae754fe2c5dc9f367256c64af21f69a1f94a9 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 10:09:53 -0400 Subject: [PATCH 04/10] scenarios: add main() to all files scenarios will need a callable entrypoint for the pyz archive --- resources/scenarios/ln_init.py | 2 +- resources/scenarios/miner_std.py | 2 +- resources/scenarios/reconnaissance.py | 2 +- resources/scenarios/signet_miner.py | 2 +- resources/scenarios/tx_flood.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/scenarios/ln_init.py b/resources/scenarios/ln_init.py index 391246fd0..051c8d1ab 100644 --- a/resources/scenarios/ln_init.py +++ b/resources/scenarios/ln_init.py @@ -180,5 +180,5 @@ def funded_lnnodes(): ) -if __name__ == "__main__": +def main(): LNInit().main() diff --git a/resources/scenarios/miner_std.py b/resources/scenarios/miner_std.py index 764210efc..1411bd666 100755 --- a/resources/scenarios/miner_std.py +++ b/resources/scenarios/miner_std.py @@ -67,5 +67,5 @@ def run_test(self): sleep(self.options.interval) -if __name__ == "__main__": +def main(): MinerStd().main() diff --git a/resources/scenarios/reconnaissance.py b/resources/scenarios/reconnaissance.py index 2d500e274..1c539f5f7 100755 --- a/resources/scenarios/reconnaissance.py +++ b/resources/scenarios/reconnaissance.py @@ -80,5 +80,5 @@ def run_test(self): self.log.info(f"Got notfound message from {dstaddr}:{dstport}") -if __name__ == "__main__": +def main(): Reconnaissance().main() diff --git a/resources/scenarios/signet_miner.py b/resources/scenarios/signet_miner.py index 7c4652240..9a20ecc97 100644 --- a/resources/scenarios/signet_miner.py +++ b/resources/scenarios/signet_miner.py @@ -562,5 +562,5 @@ def get_args(parser): return args -if __name__ == "__main__": +def main(): SignetMinerScenario().main() diff --git a/resources/scenarios/tx_flood.py b/resources/scenarios/tx_flood.py index 996b88de5..aca5573bb 100755 --- a/resources/scenarios/tx_flood.py +++ b/resources/scenarios/tx_flood.py @@ -66,5 +66,5 @@ def run_test(self): sleep(30) -if __name__ == "__main__": +def main(): TXFlood().main() From 297bcf447efd824548a13c3acf88a55094b70e99 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 10:13:36 -0400 Subject: [PATCH 05/10] charts: plain python image for scenarios, run archive from configmap --- .../charts/commander/templates/configmap.yaml | 8 ++++---- resources/charts/commander/templates/pod.yaml | 18 +++++++++--------- resources/charts/commander/values.yaml | 10 ++-------- resources/images/commander/Dockerfile | 11 ----------- 4 files changed, 15 insertions(+), 32 deletions(-) delete mode 100644 resources/images/commander/Dockerfile diff --git a/resources/charts/commander/templates/configmap.yaml b/resources/charts/commander/templates/configmap.yaml index 9c45ea0d2..2e627fda1 100644 --- a/resources/charts/commander/templates/configmap.yaml +++ b/resources/charts/commander/templates/configmap.yaml @@ -1,17 +1,17 @@ apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "commander.fullname" . }}-scenario + name: {{ include "commander.fullname" . }}-warnet labels: {{- include "commander.labels" . | nindent 4 }} binaryData: - scenario.py: {{ .Values.scenario }} + warnet.json: {{ .Values.warnet }} --- apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "commander.fullname" . }}-warnet + name: {{ include "commander.fullname" . }}-archive labels: {{- include "commander.labels" . | nindent 4 }} binaryData: - warnet.json: {{ .Values.warnet }} + archive.pyz: {{ .Values.archive }} \ No newline at end of file diff --git a/resources/charts/commander/templates/pod.yaml b/resources/charts/commander/templates/pod.yaml index 94c79205f..c74d3c233 100644 --- a/resources/charts/commander/templates/pod.yaml +++ b/resources/charts/commander/templates/pod.yaml @@ -10,23 +10,23 @@ spec: restartPolicy: {{ .Values.restartPolicy }} containers: - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + image: python:3.12-slim + imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c"] args: - | - python3 /scenario.py {{ .Values.args }} + python3 /archive.pyz {{ .Values.args }} volumeMounts: - - name: scenario - mountPath: /scenario.py - subPath: scenario.py - name: warnet mountPath: /warnet.json subPath: warnet.json + - name: archive + mountPath: /archive.pyz + subPath: archive.pyz volumes: - - name: scenario - configMap: - name: {{ include "commander.fullname" . }}-scenario - name: warnet configMap: name: {{ include "commander.fullname" . }}-warnet + - name: archive + configMap: + name: {{ include "commander.fullname" . }}-archive \ No newline at end of file diff --git a/resources/charts/commander/values.yaml b/resources/charts/commander/values.yaml index fc7e8233d..594f5a976 100644 --- a/resources/charts/commander/values.yaml +++ b/resources/charts/commander/values.yaml @@ -5,12 +5,6 @@ namespace: warnet restartPolicy: Never -image: - repository: bitcoindevproject/warnet-commander - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "latest" - imagePullSecrets: [] nameOverride: "" fullnameOverride: "" @@ -71,8 +65,8 @@ volumeMounts: [] port: -scenario: "" - warnet: "" +archive: "" + args: "" diff --git a/resources/images/commander/Dockerfile b/resources/images/commander/Dockerfile deleted file mode 100644 index 3a8314c21..000000000 --- a/resources/images/commander/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -# Use an official Python runtime as the base image -FROM python:3.12-slim - -# Python dependencies -#RUN pip install --no-cache-dir prometheus_client - -COPY resources/scenarios/commander.py / -COPY src/test_framework /test_framework - -# -u: force the stdout and stderr streams to be unbuffered -ENTRYPOINT ["python", "-u", "/scenario.py"] From 1b92b8e8465e593c1b8b10a86bbe872f4923a69e Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 10:24:05 -0400 Subject: [PATCH 06/10] control: use zipapp to create archive, send as configmap to commander --- resources/scenarios/commander.py | 2 +- src/warnet/control.py | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/resources/scenarios/commander.py b/resources/scenarios/commander.py index 1ecf0b6c4..ffc9961a5 100644 --- a/resources/scenarios/commander.py +++ b/resources/scenarios/commander.py @@ -21,7 +21,7 @@ from test_framework.test_node import TestNode from test_framework.util import PortSeed, get_rpc_proxy -WARNET_FILE = Path(os.path.dirname(__file__)) / "warnet.json" +WARNET_FILE = Path("/warnet.json") try: with open(WARNET_FILE) as file: diff --git a/src/warnet/control.py b/src/warnet/control.py index fed633cae..c0af7effe 100644 --- a/src/warnet/control.py +++ b/src/warnet/control.py @@ -1,9 +1,11 @@ import base64 +import io import json import os import subprocess import sys import time +import zipapp from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path @@ -167,14 +169,13 @@ def run(scenario_file: str, additional_args: tuple[str]): Pass `-- --help` to get individual scenario help """ scenario_path = Path(scenario_file).resolve() + scenario_dir = scenario_path.parent scenario_name = scenario_path.stem if additional_args and ("--help" in additional_args or "-h" in additional_args): return subprocess.run([sys.executable, scenario_path, "--help"]) - with open(scenario_path, "rb") as file: - scenario_data = base64.b64encode(file.read()).decode() - + # Collect tank data for warnet.json name = f"commander-{scenario_name.replace('_', '')}-{int(time.time())}" namespace = get_default_namespace() tankpods = get_mission("tank") @@ -191,9 +192,21 @@ def run(scenario_file: str, additional_args: tuple[str]): for tank in tankpods ] - # Encode warnet data + # Encode tank data for warnet.json warnet_data = base64.b64encode(json.dumps(tanks).encode()).decode() + # Create in-memory buffer to store python archive instead of writing to disk + archive_buffer = io.BytesIO() + + # Compile python archive + zipapp.create_archive( + source=scenario_dir, target=archive_buffer, main=f"{scenario_name}:main", compressed=True + ) + + # Encode the binary data as Base64 + archive_buffer.seek(0) + archive_data = base64.b64encode(archive_buffer.read()).decode() + try: # Construct Helm command helm_command = [ @@ -205,9 +218,9 @@ def run(scenario_file: str, additional_args: tuple[str]): "--set", f"fullnameOverride={name}", "--set", - f"scenario={scenario_data}", - "--set", f"warnet={warnet_data}", + "--set", + f"archive={archive_data}", ] # Add additional arguments From 7df8fb64581a5c9f590809032c1d4120201c2040 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 14:08:39 -0400 Subject: [PATCH 07/10] test: move test scenarios to resources/scenarios also filter out unused files from the archive sent to the commander --- .../scenarios/test_buggy_failure.py | 2 +- .../scenarios/test_connect_dag.py | 2 +- .../scenarios/test_p2p_interface.py | 2 +- src/warnet/control.py | 20 ++++++++++++++++++- test/dag_connection_test.py | 2 +- test/scenarios_test.py | 4 ++-- 6 files changed, 25 insertions(+), 7 deletions(-) rename test/data/scenario_buggy_failure.py => resources/scenarios/test_buggy_failure.py (95%) rename test/data/scenario_connect_dag.py => resources/scenarios/test_connect_dag.py (99%) rename test/data/scenario_p2p_interface.py => resources/scenarios/test_p2p_interface.py (98%) diff --git a/test/data/scenario_buggy_failure.py b/resources/scenarios/test_buggy_failure.py similarity index 95% rename from test/data/scenario_buggy_failure.py rename to resources/scenarios/test_buggy_failure.py index 0867218d0..700f78ea1 100644 --- a/test/data/scenario_buggy_failure.py +++ b/resources/scenarios/test_buggy_failure.py @@ -20,5 +20,5 @@ def run_test(self): raise Exception("Failed execution!") -if __name__ == "__main__": +def main(): Failure().main() diff --git a/test/data/scenario_connect_dag.py b/resources/scenarios/test_connect_dag.py similarity index 99% rename from test/data/scenario_connect_dag.py rename to resources/scenarios/test_connect_dag.py index 95e50ea28..4019e8944 100644 --- a/test/data/scenario_connect_dag.py +++ b/resources/scenarios/test_connect_dag.py @@ -117,5 +117,5 @@ def assert_connection(self, connector, connectee_index, connection_type: Connect raise ValueError("ConnectionType must be of type DNS or IP") -if __name__ == "__main__": +def main(): ConnectDag().main() diff --git a/test/data/scenario_p2p_interface.py b/resources/scenarios/test_p2p_interface.py similarity index 98% rename from test/data/scenario_p2p_interface.py rename to resources/scenarios/test_p2p_interface.py index b9d0ff65f..47eee9006 100644 --- a/test/data/scenario_p2p_interface.py +++ b/resources/scenarios/test_p2p_interface.py @@ -52,5 +52,5 @@ def run_test(self): p2p_block_store.wait_until(lambda: p2p_block_store.blocks[best_block] == 1) -if __name__ == "__main__": +def main(): GetdataTest().main() diff --git a/src/warnet/control.py b/src/warnet/control.py index c0af7effe..b963bffa6 100644 --- a/src/warnet/control.py +++ b/src/warnet/control.py @@ -198,9 +198,27 @@ def run(scenario_file: str, additional_args: tuple[str]): # Create in-memory buffer to store python archive instead of writing to disk archive_buffer = io.BytesIO() + # No need to copy the entire scenarios/ directory into the archive + def filter(path): + if any( + needle in str(path) for needle in [ + ".pyc", + ".csv", + ".DS_Store" + ] + ): + return False + return any( + needle in str(path) for needle in [ + "commander.py", + "test_framework", + scenario_name + ] + ) + # Compile python archive zipapp.create_archive( - source=scenario_dir, target=archive_buffer, main=f"{scenario_name}:main", compressed=True + source=scenario_dir, target=archive_buffer, main=f"{scenario_name}:main", compressed=True, filter=filter ) # Encode the binary data as Base64 diff --git a/test/dag_connection_test.py b/test/dag_connection_test.py index 258052fc4..8dfc9fde7 100755 --- a/test/dag_connection_test.py +++ b/test/dag_connection_test.py @@ -26,7 +26,7 @@ def setup_network(self): def run_connect_dag_scenario(self): self.log.info("Running connect_dag scenario") - self.warnet("run test/data/scenario_connect_dag.py") + self.warnet("run resources/scenarios/test_connect_dag.py") self.wait_for_all_scenarios() diff --git a/test/scenarios_test.py b/test/scenarios_test.py index 867d5107f..f3187dba0 100755 --- a/test/scenarios_test.py +++ b/test/scenarios_test.py @@ -82,7 +82,7 @@ def run_and_check_miner_scenario_from_file(self): self.stop_scenario() def run_and_check_scenario_from_file(self): - scenario_file = "test/data/scenario_p2p_interface.py" + scenario_file = "resources/scenarios/test_p2p_interface.py" self.log.info(f"Running scenario from: {scenario_file}") self.warnet(f"run {scenario_file}") self.wait_for_predicate(self.check_scenario_clean_exit) @@ -94,7 +94,7 @@ def check_regtest_recon(self): self.wait_for_predicate(self.check_scenario_clean_exit) def check_active_count(self): - scenario_file = "test/data/scenario_buggy_failure.py" + scenario_file = "resources/scenarios/test_buggy_failure.py" self.log.info(f"Running scenario from: {scenario_file}") self.warnet(f"run {scenario_file}") From 4005794c216f75bc56457af2e084dd18b2e91467 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 14:57:03 -0400 Subject: [PATCH 08/10] project: exclude test scenarios --- .../networks/6_node_bitcoin/network.yaml | 2 -- .../{ => fork_observer}/node-defaults.yaml | 0 src/warnet/graph.py | 2 +- src/warnet/network.py | 22 ++++++++----------- test/dag_connection_test.py | 2 +- test/scenarios_test.py | 4 ++-- 6 files changed, 13 insertions(+), 19 deletions(-) rename resources/networks/{ => fork_observer}/node-defaults.yaml (100%) diff --git a/resources/networks/6_node_bitcoin/network.yaml b/resources/networks/6_node_bitcoin/network.yaml index 21b05875d..86c9a27ec 100644 --- a/resources/networks/6_node_bitcoin/network.yaml +++ b/resources/networks/6_node_bitcoin/network.yaml @@ -28,7 +28,5 @@ nodes: connect: - tank-0006 - name: tank-0006 -fork_observer: - enabled: true caddy: enabled: true diff --git a/resources/networks/node-defaults.yaml b/resources/networks/fork_observer/node-defaults.yaml similarity index 100% rename from resources/networks/node-defaults.yaml rename to resources/networks/fork_observer/node-defaults.yaml diff --git a/src/warnet/graph.py b/src/warnet/graph.py index 6e5b3fd6b..691aa4ec3 100644 --- a/src/warnet/graph.py +++ b/src/warnet/graph.py @@ -74,7 +74,7 @@ def custom_graph( yaml.dump(network_yaml_data, f, default_flow_style=False) # Generate node-defaults.yaml - default_yaml_path = files("resources.networks").joinpath("node-defaults.yaml") + default_yaml_path = files("resources.networks").joinpath("fork_observer").joinpath("node-defaults.yaml") with open(str(default_yaml_path)) as f: defaults_yaml_content = yaml.safe_load(f) diff --git a/src/warnet/network.py b/src/warnet/network.py index 18a064210..0cfa5be5c 100644 --- a/src/warnet/network.py +++ b/src/warnet/network.py @@ -1,4 +1,5 @@ import json +import re import shutil from pathlib import Path @@ -18,17 +19,12 @@ def copy_defaults(directory: Path, target_subdir: str, source_path: Path, exclud target_dir.mkdir(parents=True, exist_ok=True) print(f"Creating directory: {target_dir}") - def should_copy(item: Path) -> bool: - return item.name not in exclude_list - - for item in source_path.iterdir(): - if should_copy(item): - if item.is_file(): - shutil.copy2(item, target_dir) - print(f"Copied file: {item.name}") - elif item.is_dir(): - shutil.copytree(item, target_dir / item.name, dirs_exist_ok=True) - print(f"Copied directory: {item.name}") + shutil.copytree( + src=source_path, + dst=target_dir, + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(*exclude_list) + ) print(f"Finished copying files to {target_dir}") @@ -39,7 +35,7 @@ def copy_network_defaults(directory: Path): directory, NETWORK_DIR.name, NETWORK_DIR, - ["node-defaults.yaml", "__pycache__", "__init__.py"], + ["__pycache__", "__init__.py"], ) @@ -49,7 +45,7 @@ def copy_scenario_defaults(directory: Path): directory, SCENARIOS_DIR.name, SCENARIOS_DIR, - ["__init__.py", "__pycache__", "commander.py"], + ["__pycache__", "TEST_*.py"], ) diff --git a/test/dag_connection_test.py b/test/dag_connection_test.py index 8dfc9fde7..349e97449 100755 --- a/test/dag_connection_test.py +++ b/test/dag_connection_test.py @@ -26,7 +26,7 @@ def setup_network(self): def run_connect_dag_scenario(self): self.log.info("Running connect_dag scenario") - self.warnet("run resources/scenarios/test_connect_dag.py") + self.warnet("run resources/scenarios/TEST_connect_dag.py") self.wait_for_all_scenarios() diff --git a/test/scenarios_test.py b/test/scenarios_test.py index f3187dba0..a6bf6b41f 100755 --- a/test/scenarios_test.py +++ b/test/scenarios_test.py @@ -82,7 +82,7 @@ def run_and_check_miner_scenario_from_file(self): self.stop_scenario() def run_and_check_scenario_from_file(self): - scenario_file = "resources/scenarios/test_p2p_interface.py" + scenario_file = "resources/scenarios/TEST_p2p_interface.py" self.log.info(f"Running scenario from: {scenario_file}") self.warnet(f"run {scenario_file}") self.wait_for_predicate(self.check_scenario_clean_exit) @@ -94,7 +94,7 @@ def check_regtest_recon(self): self.wait_for_predicate(self.check_scenario_clean_exit) def check_active_count(self): - scenario_file = "resources/scenarios/test_buggy_failure.py" + scenario_file = "resources/scenarios/TEST_buggy_failure.py" self.log.info(f"Running scenario from: {scenario_file}") self.warnet(f"run {scenario_file}") From 48b1326284053bcf29f83870c73a0168c55bb558 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 14:57:35 -0400 Subject: [PATCH 09/10] lint --- resources/scenarios/ln_init.py | 1 + resources/scenarios/miner_std.py | 1 + resources/scenarios/tx_flood.py | 1 + src/warnet/bitcoin.py | 3 +-- src/warnet/control.py | 20 +++++++------------- src/warnet/graph.py | 4 +++- src/warnet/network.py | 3 +-- 7 files changed, 15 insertions(+), 18 deletions(-) diff --git a/resources/scenarios/ln_init.py b/resources/scenarios/ln_init.py index 051c8d1ab..9f24e5040 100644 --- a/resources/scenarios/ln_init.py +++ b/resources/scenarios/ln_init.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from time import sleep + from commander import Commander diff --git a/resources/scenarios/miner_std.py b/resources/scenarios/miner_std.py index 1411bd666..d91736d82 100755 --- a/resources/scenarios/miner_std.py +++ b/resources/scenarios/miner_std.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from time import sleep + from commander import Commander diff --git a/resources/scenarios/tx_flood.py b/resources/scenarios/tx_flood.py index aca5573bb..1197fc8a6 100755 --- a/resources/scenarios/tx_flood.py +++ b/resources/scenarios/tx_flood.py @@ -3,6 +3,7 @@ import threading from random import choice, randrange from time import sleep + from commander import Commander diff --git a/src/warnet/bitcoin.py b/src/warnet/bitcoin.py index a27da3bc7..8942662e9 100644 --- a/src/warnet/bitcoin.py +++ b/src/warnet/bitcoin.py @@ -5,10 +5,9 @@ from io import BytesIO import click -from urllib3.exceptions import MaxRetryError - from test_framework.messages import ser_uint256 from test_framework.p2p import MESSAGEMAP +from urllib3.exceptions import MaxRetryError from .k8s import get_default_namespace, get_mission from .process import run_command diff --git a/src/warnet/control.py b/src/warnet/control.py index b963bffa6..af1b1e64b 100644 --- a/src/warnet/control.py +++ b/src/warnet/control.py @@ -200,25 +200,19 @@ def run(scenario_file: str, additional_args: tuple[str]): # No need to copy the entire scenarios/ directory into the archive def filter(path): - if any( - needle in str(path) for needle in [ - ".pyc", - ".csv", - ".DS_Store" - ] - ): + if any(needle in str(path) for needle in [".pyc", ".csv", ".DS_Store"]): return False return any( - needle in str(path) for needle in [ - "commander.py", - "test_framework", - scenario_name - ] + needle in str(path) for needle in ["commander.py", "test_framework", scenario_name] ) # Compile python archive zipapp.create_archive( - source=scenario_dir, target=archive_buffer, main=f"{scenario_name}:main", compressed=True, filter=filter + source=scenario_dir, + target=archive_buffer, + main=f"{scenario_name}:main", + compressed=True, + filter=filter, ) # Encode the binary data as Base64 diff --git a/src/warnet/graph.py b/src/warnet/graph.py index 691aa4ec3..0e418b8d3 100644 --- a/src/warnet/graph.py +++ b/src/warnet/graph.py @@ -74,7 +74,9 @@ def custom_graph( yaml.dump(network_yaml_data, f, default_flow_style=False) # Generate node-defaults.yaml - default_yaml_path = files("resources.networks").joinpath("fork_observer").joinpath("node-defaults.yaml") + default_yaml_path = ( + files("resources.networks").joinpath("fork_observer").joinpath("node-defaults.yaml") + ) with open(str(default_yaml_path)) as f: defaults_yaml_content = yaml.safe_load(f) diff --git a/src/warnet/network.py b/src/warnet/network.py index 0cfa5be5c..52b67b617 100644 --- a/src/warnet/network.py +++ b/src/warnet/network.py @@ -1,5 +1,4 @@ import json -import re import shutil from pathlib import Path @@ -23,7 +22,7 @@ def copy_defaults(directory: Path, target_subdir: str, source_path: Path, exclud src=source_path, dst=target_dir, dirs_exist_ok=True, - ignore=shutil.ignore_patterns(*exclude_list) + ignore=shutil.ignore_patterns(*exclude_list), ) print(f"Finished copying files to {target_dir}") From 9337ed9f66e983e17db80eaef8f1effdb92d2ba5 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 25 Sep 2024 15:22:59 -0400 Subject: [PATCH 10/10] remove commander image deployment from CI --- .github/workflows/deploy.yml | 61 ------------------------------------ .github/workflows/test.yml | 39 +---------------------- 2 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index ac363ab0b..000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Publish Commander Docker image - -on: - push: - branches: - - main - paths: - - resources/images/commander/Dockerfile - - resources/scenarios/commander.py - tags-ignore: - - "*" - -jobs: - push_to_registry: - name: Push commander Docker image to Docker Hub - runs-on: ubuntu-latest - permissions: - packages: write - contents: read - attestations: write - id-token: write - steps: - - name: Check out the repo - uses: actions/checkout@v4 - - - name: Log in to Docker Hub - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: bitcoindevproject/warnet-commander - tags: | - type=ref,event=tag - type=ref,event=pr - type=raw,value=latest,enable={{is_default_branch}} - labels: | - maintainer=bitcoindevproject - org.opencontainers.image.title=warnet-commander - org.opencontainers.image.description=Warnet Commander - - - name: Build and push Docker image - id: push - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 - with: - context: . - file: resources/images/commander/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Generate artifact attestation - uses: actions/attest-build-provenance@v1 - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3ff8f1e8..54d2e36df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,34 +30,8 @@ jobs: enable-cache: true - run: uvx ruff format . --check - build-image: - needs: [ruff, ruff-format] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and export - uses: docker/build-push-action@v5 - with: - file: resources/images/commander/Dockerfile - context: . - tags: bitcoindevproject/warnet-commander:latest - cache-from: type=gha - cache-to: type=gha,mode=max - outputs: type=docker,dest=/tmp/commander.tar - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: commander - path: /tmp/commander.tar - test: - needs: [build-image] + needs: [ruff, ruff-format] runs-on: ubuntu-latest strategy: matrix: @@ -80,11 +54,6 @@ jobs: memory: 4000m - name: Start minikube's loadbalancer tunnel run: minikube tunnel &> /dev/null & - - name: Download commander artifact - uses: actions/download-artifact@v4 - with: - name: commander - path: /tmp - name: Install the latest version of uv uses: astral-sh/setup-uv@v2 with: @@ -94,12 +63,6 @@ jobs: run: uv python install $PYTHON_VERSION - name: Install project run: uv sync --all-extras --dev - - name: Install commander image - run: | - echo loading commander image into minikube docker - eval $(minikube -p minikube docker-env) - docker load --input /tmp/commander.tar - docker image ls -a - name: Run tests run: | source .venv/bin/activate