Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

binary file via init #595

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ jobs:
- services_test.py
- signet_test.py
- scenarios_test.py
- binary_test.py
steps:
- uses: actions/checkout@v4
- uses: azure/[email protected]
Expand Down
10 changes: 10 additions & 0 deletions docs/warnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ options:
| scenario_file | Path | yes | |
| additional_args | String | | |

### `warnet run-binary`
Run a file in warnet
Pass `-- --help` to get individual scenario help
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- --help is specific to Commander/test framework, might not apply to all binaries


options:
| name | type | required | default |
|-----------------|--------|------------|-----------|
| file | Path | yes | |
| additional_args | String | | |

### `warnet setup`
Setup warnet

Expand Down
5 changes: 5 additions & 0 deletions resources/charts/binary-runner/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: v2
name: bin-runner
description: A Helm chart for the bin-runner Pod
version: 0.1.0
type: application
11 changes: 11 additions & 0 deletions resources/charts/binary-runner/Values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
nameOverride: ""
fullnameOverride: ""

pod:
name: bin-runner
namespace: warnet

podLabels:
app: "warnet"
mission: "binary"
1 change: 1 addition & 0 deletions resources/charts/binary-runner/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Binary executing
60 changes: 60 additions & 0 deletions resources/charts/binary-runner/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "binary-runner.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "binary-runner.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s" .Release.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "binary-runner.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "binary-runner.labels" -}}
helm.sh/chart: {{ include "binary-runner.chart" . }}
{{ include "binary-runner.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.podLabels }}
{{ toYaml . }}
{{- end }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "binary-runner.selectorLabels" -}}
app.kubernetes.io/name: {{ include "binary-runner.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "binary-runner.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "binary-runner.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
31 changes: 31 additions & 0 deletions resources/charts/binary-runner/templates/pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
apiVersion: v1
kind: Pod
metadata:
name: {{ include "binary-runner.fullname" . }}
labels:
{{- include "binary-runner.labels" . | nindent 4 }}
app: {{ include "binary-runner.name" . }}
mission: binary
spec:
restartPolicy: Never
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: {{ .Values.pod.name }}-runner
image: alpine
command: ["/bin/sh", "-c"]
args:
- |
echo "Waiting for binary file..."
while [ ! -f /data/binary ]; do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this wait was moved into the main container we wouldn't need the initContainer?

Is there another advantage to the init container?

Copy link
Contributor Author

@willcl-ark willcl-ark Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no other advantage, nice spot. This is just an artefact of me trying to migrate from configMap and, instead of taking two steps forward, only taking one.

Removed the init container in effe95d

sleep 1
done
echo "Binary found!"
chmod +x /data/binary
/data/binary
exit 0
volumeMounts:
- name: shared-data
mountPath: /data
1 change: 1 addition & 0 deletions src/warnet/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
BITCOIN_CHART_LOCATION = str(CHARTS_DIR.joinpath("bitcoincore"))
FORK_OBSERVER_CHART = str(CHARTS_DIR.joinpath("fork-observer"))
COMMANDER_CHART = str(CHARTS_DIR.joinpath("commander"))
BINARY_CHART = str(CHARTS_DIR.joinpath("binary-runner"))
NAMESPACES_CHART_LOCATION = CHARTS_DIR.joinpath("namespaces")
FORK_OBSERVER_CHART = str(files("resources.charts").joinpath("fork-observer"))
CADDY_CHART = str(files("resources.charts").joinpath("caddy"))
Expand Down
128 changes: 110 additions & 18 deletions src/warnet/control.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import base64
import json
import os
import shlex
import subprocess
import sys
import time
Expand All @@ -15,7 +16,7 @@
from rich.prompt import Confirm, Prompt
from rich.table import Table

from .constants import COMMANDER_CHART, LOGGING_NAMESPACE
from .constants import BINARY_CHART, COMMANDER_CHART, LOGGING_NAMESPACE
from .deploy import _port_stop_internal
from .k8s import (
get_default_namespace,
Expand All @@ -24,33 +25,38 @@
snapshot_bitcoin_datadir,
)
from .process import run_command, stream_command
from .status import _get_active_binaries, _get_deployed_scenarios

console = Console()


@click.command()
@click.argument("scenario_name", required=False)
def stop(scenario_name):
"""Stop a running scenario or all scenarios"""
active_scenarios = [sc.metadata.name for sc in get_mission("commander")]
@click.argument("name", required=False)
def stop(name):
"""Stop one or all running scenarios or binaries"""
all_running = [c["name"] for c in _get_deployed_scenarios()] + [
b["name"] for b in _get_active_binaries()
]

if not active_scenarios:
console.print("[bold red]No active scenarios found.[/bold red]")
if not all_running:
console.print("[bold red]No active scenarios or binaries found.[/bold red]")
return

if not scenario_name:
table = Table(title="Active Scenarios", show_header=True, header_style="bold magenta")
if not name:
table = Table(
title="Active Scenarios & binaries", show_header=True, header_style="bold magenta"
)
table.add_column("Number", style="cyan", justify="right")
table.add_column("Scenario Name", style="green")
table.add_column("Name", style="green")

for idx, name in enumerate(active_scenarios, 1):
for idx, name in enumerate(all_running, 1):
table.add_row(str(idx), name)

console.print(table)

choices = [str(i) for i in range(1, len(active_scenarios) + 1)] + ["a", "q"]
choices = [str(i) for i in range(1, len(all_running) + 1)] + ["a", "q"]
choice = Prompt.ask(
"[bold yellow]Enter the number of the scenario to stop, 'a' to stop all, or 'q' to quit[/bold yellow]",
"[bold yellow]Enter the number you want to stop, 'a' to stop all, or 'q' to quit[/bold yellow]",
choices=choices,
show_choices=False,
)
Expand All @@ -60,18 +66,18 @@ def stop(scenario_name):
return
elif choice == "a":
if Confirm.ask("[bold red]Are you sure you want to stop all scenarios?[/bold red]"):
stop_all_scenarios(active_scenarios)
stop_all_scenarios(all_running)
else:
console.print("[bold blue]Operation cancelled.[/bold blue]")
return

scenario_name = active_scenarios[int(choice) - 1]
name = all_running[int(choice) - 1]

if scenario_name not in active_scenarios:
console.print(f"[bold red]No active scenario found with name: {scenario_name}[/bold red]")
if name not in all_running:
console.print(f"[bold red]No active scenario or binary found with name: {name}[/bold red]")
return

stop_scenario(scenario_name)
stop_scenario(name)


def stop_scenario(scenario_name):
Expand Down Expand Up @@ -102,6 +108,24 @@ def stop_all_scenarios(scenarios):
console.print("[bold green]All scenarios have been stopped.[/bold green]")


def list_active_scenarios():
"""List all active scenarios"""
active_scenarios = [c["name"] for c in _get_deployed_scenarios()]
if not active_scenarios:
print("No active scenarios found.")
return

console = Console()
table = Table(title="Active Scenarios", show_header=True, header_style="bold magenta")
table.add_column("Name", style="cyan")
table.add_column("Status", style="green")

for scenario in active_scenarios:
table.add_row(scenario, "deployed")

console.print(table)


@click.command()
def down():
"""Bring down a running warnet quickly"""
Expand Down Expand Up @@ -233,6 +257,74 @@ def run(scenario_file: str, additional_args: tuple[str]):
print(f"Error: {e.stderr}")


@click.command(context_settings={"ignore_unknown_options": True})
@click.argument("file", type=click.Path(exists=True, file_okay=True, dir_okay=False))
@click.argument("additional_args", nargs=-1, type=click.UNPROCESSED)
def run_binary(file: str, additional_args: tuple[str]):
"""
Run a file in warnet
Pass `-- --help` to get individual scenario help
"""
file_path = Path(file).resolve()
file_name = file_path.stem

name = f"binary-{file_name.replace('_', '')}-{int(time.time())}"
namespace = get_default_namespace()

try:
# Construct Helm command
helm_command = [
"helm",
"upgrade",
"--install",
"--namespace",
namespace,
"--set",
f"fullnameOverride={name}",
"--set",
f"pod.name={name}",
]

# 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, file_path, "--help"])

helm_command.extend([name, BINARY_CHART])

# Execute Helm command to start the pod
result = subprocess.run(helm_command, check=True, capture_output=True, text=True)

# Wait for the pod to be ready
wait_command = [
"kubectl",
"wait",
"--for=condition=PodReadyToStartContainers",
"pod",
"--namespace",
namespace,
"--timeout=30s",
name,
]
subprocess.run(wait_command, check=True)

# Copy the binary into the container using k8s
command = f"kubectl cp {file_path} -n {namespace} {name}:/data/binary -c {name}-runner"
subprocess.run(shlex.split(command))

if result.returncode == 0:
print(f"Successfully started binary: {file_name}")
print(f"Pod name: {name}")
else:
print(f"Failed to start binary: {file_name}")
print(f"Error: {result.stderr}")

except subprocess.CalledProcessError as e:
print(f"Failed to start binary: {file_name}")
print(f"Error: {e.stderr}")


@click.command()
@click.argument("pod_name", type=str, default="")
@click.option("--follow", "-f", is_flag=True, default=False, help="Follow logs")
Expand Down
3 changes: 2 additions & 1 deletion src/warnet/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .admin import admin
from .bitcoin import bitcoin
from .control import down, logs, run, snapshot, stop
from .control import down, logs, run, run_binary, snapshot, stop
from .dashboard import dashboard
from .deploy import deploy
from .graph import create, graph
Expand All @@ -29,6 +29,7 @@ def cli():
cli.add_command(logs)
cli.add_command(new)
cli.add_command(run)
cli.add_command(run_binary)
cli.add_command(setup)
cli.add_command(snapshot)
cli.add_command(status)
Expand Down
Loading