diff --git a/images/utils/launcher/__init__.py b/images/utils/launcher/__init__.py index 3a3a680b2..10422821f 100644 --- a/images/utils/launcher/__init__.py +++ b/images/utils/launcher/__init__.py @@ -1,7 +1,6 @@ import logging import shlex import traceback -import os from .config import Config, ConfigLoader from .shell import Shell @@ -266,17 +265,17 @@ def launch(self): print() except ConfigError as e: if e.scope == ConfigErrorScope.COMMAND_LINE_ARGS: - print("❌ Failed to parse command-line arguments, exiting.") - print(f"Error details: {e.__cause__}") + print("Failed to parse command-line arguments, exiting.") + traceback.print_exc() elif e.scope == ConfigErrorScope.GENERAL_CONF: - print("❌ Failed to parse config file {}, exiting.".format(e.conf_file)) - print(f"Error details: {e.__cause__}") + print("Failed to parse config file {}, exiting.".format(e.conf_file)) + traceback.print_exc() elif e.scope == ConfigErrorScope.NETWORK_CONF: - print("❌ Failed to parse config file {}, exiting.".format(e.conf_file)) - print(f"Error details: {e.__cause__}") + print("Failed to parse config file {}, exiting.".format(e.conf_file)) + traceback.print_exc() except FatalError as e: if config and config.logfile: - print(f"❌ Error: {e}. For more details, see {config.logfile}") + print(f"Error: {e}. For more details, see {config.logfile}") else: traceback.print_exc() except Exception: # exclude system exceptions like SystemExit diff --git a/images/utils/launcher/config/config.py b/images/utils/launcher/config/config.py index e922545e4..0b1877e0d 100644 --- a/images/utils/launcher/config/config.py +++ b/images/utils/launcher/config/config.py @@ -279,6 +279,12 @@ def parse_command_line_arguments(self): action="store_true", help="Preserve xud xud.conf file during updates" ) + group.add_argument( + "--xud.debug", + nargs='?', + metavar="", + help="Run xud with NodeJS --inspect option on specific port (default: 9229)" + ) group = parser.add_argument_group("arby") group.add_argument( @@ -425,6 +431,29 @@ def update_ports(self, node, parsed, mapping=None): if p not in node["ports"]: node["ports"].append(p) + def update_debug(self, node, parsed): + node_name = node["name"] + + def process(value): + if not value: + if node_name == "xud": + value = 9229 + else: + raise RuntimeError("No default debug port for node %s" % node_name) + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + node["debug"] = value + p = PortPublish("%s" % value) + if p not in node["ports"]: + node["ports"].append(p) + + if "debug" in parsed: + process(parsed["debug"]) + opt = "{}.debug".format(node_name) + if hasattr(self.args, opt): + process(getattr(self.args, opt)) + def update_bitcoind_kind(self, node, parsed): if "external" in parsed: print("Warning: Using deprecated option \"external\". Please use \"mode\" instead.") @@ -655,6 +684,7 @@ def update_xud(self, parsed): """ node = self.nodes["xud"] self.update_ports(node, parsed) + self.update_debug(node, parsed) def update_disabled(self, node, parsed, opt): if "disabled" in parsed: diff --git a/images/utils/launcher/config/mainnet.conf b/images/utils/launcher/config/mainnet.conf index da2ea51ea..b1e5ae297 100644 --- a/images/utils/launcher/config/mainnet.conf +++ b/images/utils/launcher/config/mainnet.conf @@ -119,6 +119,7 @@ # 8886 - gRPC port # 8080 - webproxy port #expose-ports = ["8885", "8886", "8080"] +#debug = 9229 [arby] #live-cex="false" diff --git a/images/utils/launcher/config/simnet.conf b/images/utils/launcher/config/simnet.conf index 6bbda51d6..20269b6db 100644 --- a/images/utils/launcher/config/simnet.conf +++ b/images/utils/launcher/config/simnet.conf @@ -32,6 +32,7 @@ # 28886 - gRPC port # 28080 - webproxy port #expose-ports = ["28885", "28886", "28080:8080"] +#debug = 9229 [arby] #live-cex="false" diff --git a/images/utils/launcher/config/testnet.conf b/images/utils/launcher/config/testnet.conf index e67152369..6d2b54803 100644 --- a/images/utils/launcher/config/testnet.conf +++ b/images/utils/launcher/config/testnet.conf @@ -119,6 +119,7 @@ # 18886 - gRPC port # 18080 - webproxy port #expose-ports = ["18885", "18886", "18080:8080"] +#debug = 9229 [arby] #live-cex="false" diff --git a/images/utils/launcher/node/xud.py b/images/utils/launcher/node/xud.py index afd69e310..76c015190 100644 --- a/images/utils/launcher/node/xud.py +++ b/images/utils/launcher/node/xud.py @@ -42,6 +42,10 @@ def __init__(self, name, ctx): self.container_spec.environment.append("NODE_ENV=production") + if "debug" in self.node_config: + debug_port = self.node_config["debug"] + self.container_spec.environment.append(f"DEBUG_PORT={debug_port}") + self._cli = "xucli" self.api = XudApi(CliBackend(self.client, self.container_name, self._logger, self._cli)) diff --git a/images/xud/entrypoint.sh b/images/xud/entrypoint.sh index fa4719ccb..98cddcb19 100755 --- a/images/xud/entrypoint.sh +++ b/images/xud/entrypoint.sh @@ -109,4 +109,10 @@ cat $XUD_CONF /xud-backup.sh & # use exec to properly respond to SIGINT -exec xud $@ +if [[ -n ${DEBUG_PORT:-} ]]; then + export NODE_ENV=development + exec node --inspect-brk=0.0.0.0:$DEBUG_PORT bin/xud +else + exec xud $@ +fi + diff --git a/setup.sh b/setup.sh index b4a045684..90a059bfc 100644 --- a/setup.sh +++ b/setup.sh @@ -72,6 +72,7 @@ Connext options: Xud options: --xud.expose-ports [,] Expose xud service ports to your host machine --xud.preserve-config Preserve xud xud.conf file during updates + --xud.debug [] Run xud with NodeJS --inspect option on specific port (default: 9229) Arby options: --arby.live-cex [true|false] Production/Demo mode (default: false) diff --git a/tools/core/image.py b/tools/core/image.py index 23d9095e5..70873232a 100644 --- a/tools/core/image.py +++ b/tools/core/image.py @@ -140,36 +140,44 @@ def repo(self) -> Optional[str]: def _run_command(self, cmd): self._logger.info(cmd) - stop = threading.Event() - - def f(): - nonlocal stop - counter = 0 - on_travis = "TRAVIS_BRANCH" in os.environ - while not stop.is_set(): - counter = counter + 1 - - if on_travis: - print("Still building... ({})".format(counter), flush=True) - stop.wait(10) - continue - - print(".", end="", flush=True) - stop.wait(1) - if not on_travis: - print() - threading.Thread(target=f).start() - try: - output = execute(cmd) - self._logger.debug("$ %s\n%s", cmd, output) - stop.set() - except CalledProcessError as e: - stop.set() - print(e.output.decode(), end="", flush=True) - raise SystemExit(1) - except: - stop.set() - raise + on_travis = "TRAVIS_BRANCH" in os.environ + + if on_travis: + stop = threading.Event() + + def f(): + nonlocal stop + counter = 0 + + while not stop.is_set(): + counter = counter + 1 + + if on_travis: + print("Still building... ({})".format(counter), flush=True) + stop.wait(10) + continue + + print(".", end="", flush=True) + stop.wait(1) + if not on_travis: + print() + threading.Thread(target=f).start() + try: + output = execute(cmd) + self._logger.debug("$ %s\n%s", cmd, output) + stop.set() + except CalledProcessError as e: + stop.set() + print(e.output.decode(), end="", flush=True) + raise SystemExit(1) + except: + stop.set() + raise + else: + print("\033[1m$ %s\033[0m" % cmd) + exit_code = os.system(cmd) + if exit_code != 0: + raise RuntimeError("The command exits with non-zero code %s" % exit_code) def _build(self, args: List[str], build_dir: str, build_tag: str) -> None: cmd = "docker build {} {}".format(" ".join(args), build_dir)