Skip to content

cli: move all graph RPCs out of server, to warcli #321

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

Merged
merged 1 commit into from
Mar 26, 2024
Merged
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
33 changes: 17 additions & 16 deletions src/cli/graph.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from io import BytesIO
from pathlib import Path

import click
from cli.rpc import rpc_call
import networkx as nx
from rich import print
from warnet.utils import DEFAULT_TAG
from warnet.utils import DEFAULT_TAG, create_cycle_graph, validate_graph_schema


@click.group(name="graph")
Expand All @@ -19,21 +20,19 @@ def graph():
@click.option("--random", is_flag=True)
def create(number: int, outfile: Path, version: str, bitcoin_conf: Path, random: bool = False):
"""
Create a cycle graph with <n> nodes, and additionally include 7 extra random outbounds per node.
Create a cycle graph with <number> nodes, and include 7 extra random outbounds per node.
Returns XML file as string with or without --outfile option
"""
print(
rpc_call(
"graph_generate",
{
"n": number,
"outfile": str(outfile) if outfile else "",
"version": version,
"bitcoin_conf": str(bitcoin_conf),
"random": random,
},
)
)
graph = create_cycle_graph(number, version, bitcoin_conf, random)

if outfile:
file_path = Path(outfile)
nx.write_graphml(graph, file_path, named_key_ids=True)
return f"Generated graph written to file: {outfile}"
bio = BytesIO()
nx.write_graphml(graph, bio, named_key_ids=True)
xml_data = bio.getvalue()
print(xml_data.decode("utf-8"))


@graph.command()
Expand All @@ -42,4 +41,6 @@ def validate(graph: Path):
"""
Validate a <graph file> against the schema.
"""
print(rpc_call("graph_validate", {"graph_path": Path(graph).as_posix()}))
with open(graph) as f:
graph = nx.parse_graphml(f.read(), node_type=int)
return validate_graph_schema(graph)
45 changes: 1 addition & 44 deletions src/warnet/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,14 @@
import time
import traceback
from datetime import datetime
from io import BytesIO
from pathlib import Path

import jsonschema
import networkx as nx
import scenarios
from backends import ServiceType
from flask import Flask, jsonify, request
from flask_jsonrpc.app import JSONRPC
from flask_jsonrpc.exceptions import ServerError
from warnet.utils import (
create_cycle_graph,
gen_config_dir,
validate_graph_schema,
)
from warnet.utils import gen_config_dir
from warnet.warnet import Warnet

WARNET_SERVER_PORT = 9276
Expand Down Expand Up @@ -168,9 +161,6 @@ def setup_rpc(self):
self.jsonrpc.register(self.network_status)
self.jsonrpc.register(self.network_connected)
self.jsonrpc.register(self.network_export)
# Graph
self.jsonrpc.register(self.graph_generate)
self.jsonrpc.register(self.graph_validate)
# Debug
self.jsonrpc.register(self.generate_deployment)
self.jsonrpc.register(self.exec_run)
Expand Down Expand Up @@ -505,39 +495,6 @@ def thread_start(server: Server, network):
self.logger.error(msg)
raise ServerError(message=msg) from e

def graph_generate(
self,
n: int,
outfile: str,
version: str,
bitcoin_conf: str | None = None,
random: bool = False,
) -> str:
try:
graph = create_cycle_graph(n, version, bitcoin_conf, random)

if outfile:
file_path = Path(outfile)
nx.write_graphml(graph, file_path, named_key_ids=True)
return f"Generated graph written to file: {outfile}"
bio = BytesIO()
nx.write_graphml(graph, bio, named_key_ids=True)
xml_data = bio.getvalue()
return xml_data.decode("utf-8")
except Exception as e:
msg = f"Error generating graph: {e}"
self.logger.error(msg)
raise ServerError(message=msg) from e

def graph_validate(self, graph_path: str) -> str:
with open(graph_path) as f:
graph = nx.parse_graphml(f.read(), node_type=int, force_multigraph=True)
try:
validate_graph_schema(graph)
except (jsonschema.ValidationError, jsonschema.SchemaError) as e:
raise ServerError(message=f"Schema of {graph_path} is invalid: {e}") from e
return f"Schema of {graph_path} is valid"

def network_down(self, network: str = "warnet") -> str:
"""
Stop all containers in <network>.
Expand Down
37 changes: 15 additions & 22 deletions test/graph_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,23 @@
from warnet.utils import DEFAULT_TAG

base = TestBase()
base.network = False
base.start_server()

with tempfile.TemporaryDirectory() as dir:
tf = f"{dir}/{str(uuid.uuid4())}.graphml"
if base.backend == "compose":
print(f"Server writing test graph directly to {tf}")
print(base.warcli(f"graph create 10 --outfile={tf} --version={DEFAULT_TAG}", network=False))
base.wait_for_predicate(lambda: Path(tf).exists())
else:
print(f"Client retrieving test graph from RPC and writing to {tf}")
xml = base.warcli(f"graph create 10 --version={DEFAULT_TAG}", network=False)
print(xml)
with open(tf, "w") as file:
file.write(xml)
# Does not require a running Warnet RPC server yet
test_dir = tempfile.TemporaryDirectory()
tf = f"{test_dir.name}/{str(uuid.uuid4())}.graphml"

# Validate the graph schema
assert "invalid" not in base.warcli(f"graph validate {Path(tf)}", False)
print(f"Graph at {tf} validated successfully")
print(f"CLI tool writing test graph directly to {tf}")
print(base.warcli(f"graph create 10 --outfile={tf} --version={DEFAULT_TAG}", network=False))
base.wait_for_predicate(lambda: Path(tf).exists())

# Test that the graph actually works
print(base.warcli(f"network start {Path(tf)}"))
base.wait_for_all_tanks_status(target="running")
base.wait_for_all_edges()
base.warcli("rpc 0 getblockcount")
# Validate the graph schema
assert "invalid" not in base.warcli(f"graph validate {Path(tf)}", False)
print(f"Graph at {tf} validated successfully")

# Test that the graph actually works, now we need a server
base.start_server()
print(base.warcli(f"network start {Path(tf)}"))
base.wait_for_all_tanks_status(target="running")
base.wait_for_all_edges()
base.warcli("rpc 0 getblockcount")
base.stop_server()
Loading