diff --git a/src/warnet/bitcoin.py b/src/warnet/bitcoin.py index 5b392e22e..8d6676cf2 100644 --- a/src/warnet/bitcoin.py +++ b/src/warnet/bitcoin.py @@ -151,6 +151,11 @@ def grep_logs(pattern: str, show_k8s_timestamps: bool, no_sort: bool): return matching_logs +def is_external_peer(name: str) -> bool: + """Check if tank_b is an external/non-tank peer (e.g. onion address or raw IP)""" + return ".onion" in name or not name.startswith("tank-") + + @bitcoin.command() @click.argument("tank_a", type=str, required=True) @click.argument("tank_b", type=str, required=True) @@ -159,6 +164,7 @@ def messages(tank_a: str, tank_b: str, chain: str): """ Fetch messages sent between and in [chain] + tank_b can be a tank pod name, an onion address, or any external peer identifier. Optionally, include a namespace like so: tank-name.namespace """ @@ -171,18 +177,30 @@ def parse_name_and_namespace(tank: str) -> tuple[str, Optional[str]]: return tank_split[0], namespace tank_a_split = tank_a.split(".") - tank_b_split = tank_b.split(".") - if len(tank_a_split) > 2 or len(tank_b_split) > 2: + if len(tank_a_split) > 2: click.secho("Accepted formats: tank-name OR tank-name.namespace") click.secho(f"Foramts found: {tank_a} {tank_b}") sys.exit(1) + # Only validate tank_b format if it's not an external peer + if not is_external_peer(tank_b): + tank_b_split = tank_b.split(".") + if len(tank_b_split) > 2: + click.secho("Accepted formats: tank-name OR tank-name.namespace") + click.secho(f"Format found: {tank_b}") + sys.exit(1) + tank_a, namespace_a = parse_name_and_namespace(tank_a) - tank_b, namespace_b = parse_name_and_namespace(tank_b) + + # If tank_b is an external peer (onion address etc.), skip namespace parsing + if is_external_peer(tank_b): + namespace_b = None + else: + tank_b, namespace_b = parse_name_and_namespace(tank_b) + namespace_b = get_default_namespace_or(namespace_b) try: namespace_a = get_default_namespace_or(namespace_a) - namespace_b = get_default_namespace_or(namespace_b) # Get the messages messages = get_messages( @@ -190,9 +208,8 @@ def parse_name_and_namespace(tank: str) -> tuple[str, Optional[str]]: ) if not messages: - print( - f"No messages found between {tank_a} ({namespace_a}) and {tank_b} ({namespace_b})" - ) + peer_display = tank_b if namespace_b is None else f"{tank_b} ({namespace_b})" + print(f"No messages found between {tank_a} ({namespace_a}) and {peer_display}") return # Process and print messages @@ -224,15 +241,17 @@ def get_messages(tank_a: str, tank_b: str, chain: str, namespace_a: str, namespa subdir = "" if chain == "main" else f"{chain}/" base_dir = f"/root/.bitcoin/{subdir}message_capture" - # Get the IP of node_b - cmd = f"kubectl get pod {tank_b} -o jsonpath='{{.status.podIP}}' --namespace {namespace_b}" - tank_b_ip = run_command(cmd).strip() + if namespace_b is None: + # External peer (onion address, raw IP, etc.) — use address directly for dir matching + tank_b_ip = tank_b + tank_b_service_ip = tank_b + else: + # Known tank — look up IPs via kubectl + cmd = f"kubectl get pod {tank_b} -o jsonpath='{{.status.podIP}}' --namespace {namespace_b}" + tank_b_ip = run_command(cmd).strip() - # Get the service IP of node_b - cmd = ( - f"kubectl get service {tank_b} -o jsonpath='{{.spec.clusterIP}}' --namespace {namespace_b}" - ) - tank_b_service_ip = run_command(cmd).strip() + cmd = f"kubectl get service {tank_b} -o jsonpath='{{.spec.clusterIP}}' --namespace {namespace_b}" + tank_b_service_ip = run_command(cmd).strip() # List directories in the message capture folder cmd = f"kubectl exec {tank_a} --namespace {namespace_a} -- ls {base_dir}" diff --git a/test/onion_test.py b/test/onion_test.py index 75ec6b049..b50cda486 100755 --- a/test/onion_test.py +++ b/test/onion_test.py @@ -76,6 +76,25 @@ def onion_connect(): self.wait_for_predicate(onion_connect, timeout=20 * 60) + self.check_messages(onions) + + def check_messages(self, onions: dict): + self.log.info("Checking captured messages from onion peer...") + + # tank-0001's onion address as seen by tank-0000 + onion_b = onions["tank-0001"] + + # Bitcoin message capture dirs are named like: _ or _ + # We pass the onion address with port appended as tank_b + onion_b_with_port = f"{onion_b}_18444" + + result = self.warnet(f"bitcoin messages tank-0000 {onion_b_with_port}") + self.log.info(f"Messages result: {result}") + assert result and len(result.strip()) > 0, ( + f"Expected messages between tank-0000 and {onion_b_with_port} but got none" + ) + self.log.info("Successfully retrieved messages from onion peer!") + if __name__ == "__main__": test = OnionTest()