Skip to content
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
66 changes: 66 additions & 0 deletions tests/test_debugstream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python
# coding: utf-8

from xrpld_netgen.utils.deploy_kit import build_debugstream_service, build_stop_sh


class TestBuildDebugstreamService:
"""Test build_debugstream_service returns correct dict structure"""

def test_default_port(self):
result = build_debugstream_service("xahau", "xahau-net")
assert result["container_name"] == "debugstream"
assert result["ports"] == ["9999:9999"]
assert result["build"] == {
"context": "./debugstream",
"dockerfile": "Dockerfile",
}
assert result["networks"] == ["xahau-net"]

def test_custom_port(self):
result = build_debugstream_service("xrpl", "xrpl-net", port=8888)
assert result["ports"] == ["8888:8888"]

def test_volume_readonly(self):
result = build_debugstream_service("xahau", "xahau-net")
volumes = result["volumes"]
assert len(volumes) == 1
assert volumes[0].endswith(":ro")

def test_volume_uses_protocol_name(self):
result = build_debugstream_service("xahau", "xahau-net")
assert result["volumes"] == ["xahau-log:/opt/ripple/log:ro"]

def test_depends_on_protocol(self):
result = build_debugstream_service("xahau", "xahau-net")
assert "xahau" in result["depends_on"]

def test_depends_on_xrpl(self):
result = build_debugstream_service("xrpl", "xrpl-net")
assert "xrpl" in result["depends_on"]


class TestStopShStandalone:
"""Test build_stop_sh for standalone mode"""

def test_has_volume_flag(self):
result = build_stop_sh(
basedir="/workspace",
protocol="xahau",
name="test",
num_validators=0,
num_peers=0,
standalone=True,
)
assert "down -v" in result

def test_no_log_rm(self):
result = build_stop_sh(
basedir="/workspace",
protocol="xahau",
name="test",
num_validators=0,
num_peers=0,
standalone=True,
)
assert "rm -r xahau/log" not in result
11 changes: 11 additions & 0 deletions xrpld_netgen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,13 @@ def main():
choices=["Memory", "NuDB"],
default="NuDB",
)
parser_us.add_argument(
"--debugstream_port",
type=int,
required=False,
help="The debugstream port",
default=9999,
)
# down:standalone
parser_ds = subparsers.add_parser("down:standalone", help="Down Standalone")
parser_ds.add_argument("--name", required=False, help="The name of the network")
Expand Down Expand Up @@ -615,6 +622,7 @@ def main():
BUILD_VERSION = args.version
IPFS_SERVER = args.ipfs
NODEDB_TYPE = args.nodedb_type
DEBUGSTREAM_PORT = args.debugstream_port

if PROTOCOL == "xahau" and not IMPORT_KEY:
IMPORT_KEY: str = (
Expand Down Expand Up @@ -651,6 +659,7 @@ def main():
print(f" - Build Version: {BUILD_VERSION}")
print(f" - IPFS Server: {IPFS_SERVER}")
print(f" - Node DB: {NODEDB_TYPE}")
print(f" - Debugstream Port: {DEBUGSTREAM_PORT}")

if BUILD_TYPE == "image":
create_standalone_image(
Expand All @@ -664,6 +673,7 @@ def main():
BUILD_VERSION,
IPFS_SERVER,
NODEDB_TYPE,
DEBUGSTREAM_PORT,
)
else:
create_standalone_binary(
Expand All @@ -677,6 +687,7 @@ def main():
BUILD_VERSION,
IPFS_SERVER,
NODEDB_TYPE,
DEBUGSTREAM_PORT,
)

run_start(
Expand Down
9 changes: 9 additions & 0 deletions xrpld_netgen/deploykit/debugstream/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3.12-slim

RUN pip install --no-cache-dir aiohttp

COPY server.py .

EXPOSE 9999

CMD ["python", "server.py"]
73 changes: 73 additions & 0 deletions xrpld_netgen/deploykit/debugstream/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python
# coding: utf-8

import os
import asyncio

from aiohttp import web


LOG_PATH = os.environ.get("LOG_PATH", "/opt/ripple/log/debug.log")
PORT = int(os.environ.get("PORT", "9999"))


async def tail_log(ws: web.WebSocketResponse, raddress: str):
while not os.path.exists(LOG_PATH):
if ws.closed:
return
await asyncio.sleep(0.5)

pos = os.path.getsize(LOG_PATH)

while not ws.closed:
try:
size = os.path.getsize(LOG_PATH)
except FileNotFoundError:
await asyncio.sleep(0.5)
continue

# Handle file rotation
if size < pos:
pos = 0

if size > pos:
with open(LOG_PATH, "r", errors="replace") as f:
f.seek(pos)
for line in f:
if raddress in line:
try:
await ws.send_str(line.rstrip("\n"))
except ConnectionResetError:
return
pos = f.tell()

await asyncio.sleep(0.1)


async def handle_debugstream(request: web.Request) -> web.WebSocketResponse:
raddress = request.match_info["raddress"]
ws = web.WebSocketResponse()
await ws.prepare(request)

task = asyncio.create_task(tail_log(ws, raddress))
try:
async for _ in ws:
pass
finally:
task.cancel()
try:
await task
except asyncio.CancelledError:
pass

return ws


def create_app() -> web.Application:
app = web.Application()
app.router.add_get("/debugstream/{raddress}", handle_debugstream)
return app


if __name__ == "__main__":
web.run_app(create_app(), port=PORT)
17 changes: 16 additions & 1 deletion xrpld_netgen/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from xrpld_netgen.utils.deploy_kit import (
create_dockerfile,
download_binary,
build_debugstream_service,
build_stop_sh,
build_start_sh,
build_local_start_sh,
Expand Down Expand Up @@ -184,6 +185,7 @@ def create_standalone_image(
build_name: str,
add_ipfs: bool = False,
nodedb_type: str = "NuDB",
debugstream_port: int = 9999,
) -> None:
name: str = build_name
os.makedirs(f"{basedir}/{protocol}-{name}", exist_ok=True)
Expand Down Expand Up @@ -265,6 +267,7 @@ def create_xahau_standalone_folder(
net_type: str,
log_level: str = "trace",
nodedb_type: str = "NuDB",
debugstream_port: int = 9999,
):
cfg_path = f"{basedir}/{protocol}-{name}/config"
rpc_public, rpc_admin, ws_public, ws_admin, peer = generate_ports(0, "standalone")
Expand Down Expand Up @@ -342,6 +345,12 @@ def create_xahau_standalone_folder(
f"{package_dir}/deploykit/{protocol}.entrypoint",
f"{basedir}/{protocol}-{name}/entrypoint",
)
debugstream_src = f"{package_dir}/deploykit/debugstream"
debugstream_dst = f"{basedir}/{protocol}-{name}/debugstream"
if os.path.exists(debugstream_dst):
shutil.rmtree(debugstream_dst)
shutil.copytree(debugstream_src, debugstream_dst)

print(f"✅ {bcolors.CYAN}Building docker container...")
pwd_str: str = "${PWD}"
services[f"{protocol}"] = {
Expand All @@ -360,11 +369,14 @@ def create_xahau_standalone_folder(
],
"volumes": [
f"{pwd_str}/{protocol}/config:/etc/opt/ripple",
f"{pwd_str}/{protocol}/log:/opt/ripple/log",
f"{protocol}-log:/opt/ripple/log",
f"{pwd_str}/{protocol}/lib:/opt/ripple/lib",
],
"networks": ["standalone-network"],
}
services["debugstream"] = build_debugstream_service(
protocol, "standalone-network", debugstream_port
)


def create_standalone_binary(
Expand All @@ -378,6 +390,7 @@ def create_standalone_binary(
build_version: str,
add_ipfs: bool = False,
nodedb_type: str = "NuDB",
debugstream_port: int = 9999,
) -> None:
name: str = build_version
os.makedirs(f"{basedir}/{protocol}-{name}", exist_ok=True)
Expand All @@ -404,6 +417,7 @@ def create_standalone_binary(
net_type,
log_level,
nodedb_type,
debugstream_port,
)
services["explorer"] = {
"image": "transia/explorer:latest",
Expand Down Expand Up @@ -435,6 +449,7 @@ def create_standalone_binary(
compose = {
"version": "3.9",
"services": services,
"volumes": {f"{protocol}-log": None},
"networks": {"standalone-network": {"driver": "bridge"}},
}

Expand Down
21 changes: 19 additions & 2 deletions xrpld_netgen/utils/deploy_kit.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,24 @@ def update_dockerfile(build_version: str, save_path: str) -> None:
print(f"Dockerfile has been updated with the new xrpld version: {build_version}")


def build_debugstream_service(
protocol: str,
network_name: str,
port: int = 9999,
) -> dict:
return {
"build": {
"context": "./debugstream",
"dockerfile": "Dockerfile",
},
"container_name": "debugstream",
"ports": [f"{port}:{port}"],
"volumes": [f"{protocol}-log:/opt/ripple/log:ro"],
"depends_on": [protocol],
"networks": [network_name],
}


def build_stop_sh(
basedir: str,
protocol: str,
Expand All @@ -235,10 +253,9 @@ def build_stop_sh(
stop_sh_content += f"rm -r pnode{i}/log\n"

if standalone:
stop_sh_content += f"docker compose -f {basedir}/{protocol}-{name}/docker-compose.yml down --remove-orphans\n" # noqa: E501
stop_sh_content += f"docker compose -f {basedir}/{protocol}-{name}/docker-compose.yml down -v --remove-orphans\n" # noqa: E501
stop_sh_content += f"rm -r {protocol}/config\n"
stop_sh_content += f"rm -r {protocol}/lib\n"
stop_sh_content += f"rm -r {protocol}/log\n"
stop_sh_content += f"rm -r {protocol}\n"

if local:
Expand Down
Loading