From 19100492aa70e6d79930badf2186a8ed1e155a20 Mon Sep 17 00:00:00 2001 From: Max Edwards Date: Wed, 21 Aug 2024 13:56:23 +0200 Subject: [PATCH] hooked up network start to helm --- networks/6_node_bitcoin/defaults.yaml | 41 +++++++++++++++++ networks/6_node_bitcoin/network.yaml | 10 +++++ src/warnet/cli/k8s.py | 44 +------------------ src/warnet/cli/main.py | 2 + src/warnet/cli/network.py | 2 +- src/warnet/cli/network2.py | 63 +++++++++++++++++++++++++++ src/warnet/cli/process.py | 42 ++++++++++++++++++ 7 files changed, 161 insertions(+), 43 deletions(-) create mode 100644 networks/6_node_bitcoin/defaults.yaml create mode 100644 networks/6_node_bitcoin/network.yaml create mode 100644 src/warnet/cli/network2.py create mode 100644 src/warnet/cli/process.py diff --git a/networks/6_node_bitcoin/defaults.yaml b/networks/6_node_bitcoin/defaults.yaml new file mode 100644 index 000000000..438b33d8c --- /dev/null +++ b/networks/6_node_bitcoin/defaults.yaml @@ -0,0 +1,41 @@ +collectLogs: true +metricsExport: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +image: + repository: bitcoindevproject/bitcoin + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "27.0" + +config: |2+ + regtest=1 + checkmempool=0 + acceptnonstdtxn=1 + debuglogfile=0 + logips=1 + logtimemicros=1 + capturemessages=1 + fallbackfee=0.00001000 + listen=1 + + [regtest] + rpcuser=user + rpcpassword=password + rpcport=18443 + rpcallowip=0.0.0.0/0 + rpcbind=0.0.0.0 + + zmqpubrawblock=tcp://0.0.0.0:28332 + zmqpubrawtx=tcp://0.0.0.0:28333 \ No newline at end of file diff --git a/networks/6_node_bitcoin/network.yaml b/networks/6_node_bitcoin/network.yaml new file mode 100644 index 000000000..c7c01095e --- /dev/null +++ b/networks/6_node_bitcoin/network.yaml @@ -0,0 +1,10 @@ +nodes: + - name: tank-0001 + config: + image: + tag: "26.0" + - name: tank-0002 + - name: tank-0003 + - name: tank-0004 + - name: tank-0005 + - name: tank-0006 \ No newline at end of file diff --git a/src/warnet/cli/k8s.py b/src/warnet/cli/k8s.py index 9a9439184..029a2beeb 100644 --- a/src/warnet/cli/k8s.py +++ b/src/warnet/cli/k8s.py @@ -1,10 +1,10 @@ -import os -import subprocess from importlib.resources import files from kubernetes import client, config from kubernetes.dynamic import DynamicClient +from .process import run_command + WAR_MANIFESTS = files("manifests") @@ -32,46 +32,6 @@ def get_mission(mission): return crew -def run_command(command, stream_output=False, env=None): - # Merge the current environment with the provided env - full_env = os.environ.copy() - if env: - # Convert all env values to strings (only a safeguard) - env = {k: str(v) for k, v in env.items()} - full_env.update(env) - - if stream_output: - process = subprocess.Popen( - ["/bin/bash", "-c", command], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - bufsize=1, - universal_newlines=True, - env=full_env, - ) - - for line in iter(process.stdout.readline, ""): - print(line, end="") - - process.stdout.close() - return_code = process.wait() - - if return_code != 0: - print(f"Command failed with return code {return_code}") - return False - return True - else: - result = subprocess.run( - command, shell=True, capture_output=True, text=True, executable="/bin/bash" - ) - if result.returncode != 0: - print(f"Error: {result.stderr}") - return False - print(result.stdout) - return True - - def create_namespace() -> dict: return {"apiVersion": "v1", "kind": "Namespace", "metadata": {"name": "warnet"}} diff --git a/src/warnet/cli/main.py b/src/warnet/cli/main.py index 95197bd29..ed8744190 100644 --- a/src/warnet/cli/main.py +++ b/src/warnet/cli/main.py @@ -11,6 +11,7 @@ # from .ln import ln from .network import network +from .network2 import network2 from .scenarios import scenarios QUICK_START_PATH = files("scripts").joinpath("quick_start.sh") @@ -26,6 +27,7 @@ def cli(): cli.add_command(image) # cli.add_command(ln) cli.add_command(network) +cli.add_command(network2) cli.add_command(scenarios) diff --git a/src/warnet/cli/network.py b/src/warnet/cli/network.py index 3bf410718..d11fb5a85 100644 --- a/src/warnet/cli/network.py +++ b/src/warnet/cli/network.py @@ -13,9 +13,9 @@ create_namespace, delete_namespace, deploy_base_configurations, - run_command, set_kubectl_context, ) +from .process import run_command DEFAULT_GRAPH_FILE = files("graphs").joinpath("default.graphml") WAR_MANIFESTS = files("manifests") diff --git a/src/warnet/cli/network2.py b/src/warnet/cli/network2.py new file mode 100644 index 000000000..8a439c618 --- /dev/null +++ b/src/warnet/cli/network2.py @@ -0,0 +1,63 @@ +import os +import tempfile +from pathlib import Path + +import click +import yaml + +from .process import run_command + +NETWORK_DIR = Path("networks") +DEFAULT_NETWORK = "6_node_bitcoin" +NETWORK_FILE = "network.yaml" +DEFAULTS_FILE = "defaults.yaml" +HELM_COMMAND = "helm upgrade --install --create-namespace" +BITCOIN_CHART_LOCATION = "./resources/charts/bitcoincore" +NAMESPACE = "warnet" + + +@click.group(name="network2") +def network2(): + """Network commands""" + + +@network2.command() +@click.argument("network_name", default=DEFAULT_NETWORK) +@click.option("--network", default="warnet", show_default=True) +@click.option("--logging/--no-logging", default=False) +def start2(network_name: str, logging: bool, network: str): + """Start a warnet with topology loaded from into [network]""" + full_path = os.path.join(NETWORK_DIR, network_name) + network_file_path = os.path.join(full_path, NETWORK_FILE) + defaults_file_path = os.path.join(full_path, DEFAULTS_FILE) + + network_file = {} + with open(network_file_path) as f: + network_file = yaml.safe_load(f) + + for node in network_file["nodes"]: + print(f"Starting node: {node.get('name')}") + try: + temp_override_file_path = "" + node_name = node.get("name") + node_config_override = node.get("config") + + cmd = f"{HELM_COMMAND} {node_name} {BITCOIN_CHART_LOCATION} --namespace {NAMESPACE} -f {defaults_file_path}" + + if node_config_override: + with tempfile.NamedTemporaryFile( + mode="w", suffix=".yaml", delete=False + ) as temp_file: + yaml.dump(node_config_override, temp_file) + temp_override_file_path = temp_file.name + cmd = f"{cmd} -f {temp_override_file_path}" + + if not run_command(cmd, stream_output=True): + print(f"Failed to run Helm command: {cmd}") + return + except Exception as e: + print(f"Error: {e}") + return + finally: + if temp_override_file_path: + Path(temp_override_file_path).unlink() diff --git a/src/warnet/cli/process.py b/src/warnet/cli/process.py new file mode 100644 index 000000000..80db73cd9 --- /dev/null +++ b/src/warnet/cli/process.py @@ -0,0 +1,42 @@ +import os +import subprocess + + +def run_command(command, stream_output=False, env=None): + # Merge the current environment with the provided env + full_env = os.environ.copy() + if env: + # Convert all env values to strings (only a safeguard) + env = {k: str(v) for k, v in env.items()} + full_env.update(env) + + if stream_output: + process = subprocess.Popen( + ["/bin/bash", "-c", command], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + universal_newlines=True, + env=full_env, + ) + + for line in iter(process.stdout.readline, ""): + print(line, end="") + + process.stdout.close() + return_code = process.wait() + + if return_code != 0: + print(f"Command failed with return code {return_code}") + return False + return True + else: + result = subprocess.run( + command, shell=True, capture_output=True, text=True, executable="/bin/bash" + ) + if result.returncode != 0: + print(f"Error: {result.stderr}") + return False + print(result.stdout) + return True