# Copyright (C) 2019 Xin Liang # See COPYING for license information. import typing from crmsh.sh import Utils from crmsh.prun import prun Error = prun.PRunError def parallax_call(nodes, cmd, *, timeout_seconds: int = -1): """ Executes the given command on a set of hosts, collecting the output, and raise exception when error occurs nodes: a set of hosts cmd: command timeout_seconds: the timeout in seconds. Returns [(host, (rc, stdout, stdin)), ...], or raises ValueError when any one of the rc != 0 """ results = prun.prun({node: cmd for node in nodes}, timeout_seconds=timeout_seconds) for node, result in results.items(): if isinstance(result, prun.PRunError): raise ValueError('Failed to run command {} on {}@{}: {}'.format(cmd, result.user, result.host, result)) elif result.returncode != 0: raise ValueError("Failed on {}: {}".format( node, Utils.decode_str(result.stderr) if result.stderr is not None else None, )) return [(node, (result.returncode, result.stdout, result.stderr)) for node, result in results.items()] def parallax_slurp(nodes: typing.Sequence[str], localdir, filename) -> typing.List[typing.Tuple[str, typing.Union[str, Error]]]: """ Copies from the remote node to the local node nodes: a set of hosts localdir: localpath filename: remote filename want to slurp Returns [(host, localpath), ...] or raises ValueError when any one of hosts fails. """ results = prun.pfetch_from_remote(nodes, filename, localdir) for node, result in results.items(): if isinstance(result, prun.PRunError): raise ValueError("Failed on {}@{}: {}".format(result.user, node, result)) return [(k, v) for k, v in results.items()] def parallax_copy(nodes, src, dst, recursive=False, *, timeout_seconds: int = -1): """ Copies from the local node to a set of remote hosts nodes: a set of hosts src: local path dst: remote path recursive: whether to copy directories recursively timeout_seconds: the timeout in seconds. Returns None, or raises ValueError when any one of hosts fails. """ results = prun.pcopy_to_remote(src, nodes, dst, recursive, timeout_seconds=timeout_seconds) for node, exc in results.items(): if exc is not None: raise ValueError("Failed on {}@{}: {}".format(exc.user, node, exc)) def parallax_run(nodes, cmd): """ Executes the given command on a set of hosts, collecting the output and any error nodes: a set of hosts cmd: command Returns [(host, (rc, stdout, stdin)), ...], or raises ValueError when any one of the hosts fails to start running the command. """ results = prun.prun({node: cmd for node in nodes}) for value in results.values(): if isinstance(value, prun.PRunError): raise ValueError('Failed to run command {} on {}@{}: {}'.format(cmd, value.user, value.host, value)) return {node: (result.returncode, result.stdout, result.stderr) for node, result in results.items()}