multiSSH3 6.32__tar.gz → 6.33__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {multissh3-6.32/multiSSH3.egg-info → multissh3-6.33}/PKG-INFO +14 -12
- {multissh3-6.32 → multissh3-6.33}/README.md +13 -11
- {multissh3-6.32 → multissh3-6.33}/mssh_complete.py +114 -5
- {multissh3-6.32 → multissh3-6.33/multiSSH3.egg-info}/PKG-INFO +14 -12
- {multissh3-6.32 → multissh3-6.33}/multiSSH3.egg-info/SOURCES.txt +7 -0
- {multissh3-6.32 → multissh3-6.33}/multiSSH3.py +227 -34
- {multissh3-6.32 → multissh3-6.33}/tests/conftest.py +14 -0
- {multissh3-6.32 → multissh3-6.33}/tests/data/run_command_golden.json +189 -34
- {multissh3-6.32 → multissh3-6.33}/tests/test_cli_branches.py +1 -1
- {multissh3-6.32 → multissh3-6.33}/tests/test_cli_processing.py +2 -1
- multissh3-6.33/tests/test_closed_output.py +60 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_engine.py +1 -1
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_keys.py +82 -6
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_picker.py +45 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_shells.py +39 -0
- multissh3-6.33/tests/test_complete_start.py +102 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_config_cli.py +2 -2
- {multissh3-6.32 → multissh3-6.33}/tests/test_config_values.py +7 -5
- {multissh3-6.32 → multissh3-6.33}/tests/test_copy_id.py +2 -2
- {multissh3-6.32 → multissh3-6.33}/tests/test_curses_event_loop.py +66 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_history_replay.py +6 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_identities_only.py +1 -1
- {multissh3-6.32 → multissh3-6.33}/tests/test_ipmi_logins.py +18 -7
- {multissh3-6.32 → multissh3-6.33}/tests/test_main_lifecycle.py +2 -1
- multissh3-6.33/tests/test_no_hosts.py +46 -0
- multissh3-6.33/tests/test_password_handling.py +153 -0
- multissh3-6.33/tests/test_passwords_out_of_ps.py +109 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_command_branches.py +5 -3
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_command_characterization.py +14 -8
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_on_hosts_modes.py +7 -4
- {multissh3-6.32 → multissh3-6.33}/tests/test_runtime_branch_matrix.py +3 -2
- {multissh3-6.32 → multissh3-6.33}/tests/test_sshpass_exit.py +1 -1
- multissh3-6.33/tests/test_underscore_settings.py +83 -0
- multissh3-6.33/tests/test_wide_wrap.py +78 -0
- {multissh3-6.32 → multissh3-6.33}/LICENSE +0 -0
- {multissh3-6.32 → multissh3-6.33}/MANIFEST.in +0 -0
- {multissh3-6.32 → multissh3-6.33}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-6.32 → multissh3-6.33}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-6.32 → multissh3-6.33}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-6.32 → multissh3-6.33}/pytest.ini +0 -0
- {multissh3-6.32 → multissh3-6.33}/setup.cfg +0 -0
- {multissh3-6.32 → multissh3-6.33}/setup.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/bench_complete.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/complete_shell_harness.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.bash5.1 +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.bash5.3 +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.centos7 +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.current +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.legacy +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/Dockerfile.modern +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/shells/run_matrix.sh +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_cli_option_words.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_color_helpers.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_command_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_compact_hostnames.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_blesh.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_cli.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_context.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_diagnose.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_editor.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_eval.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_hoststate.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_index.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_lex.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_mssh_helpers.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_password_spellings.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_probe.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_store.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_suggest.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_untrusted.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_complete_zsh_options.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_config_validate.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_control_master_config.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_curses_branches.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_curses_tui.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_curses_wide_chars.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_expand_hostnames.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_file_trust.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_harness_smoke.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_helpers_extra.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_host.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_host_validity.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_hosts_file.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_ipmi_lockout_wait.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_key_path_home.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_login_drop_retry.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_narrow_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_option_no_effect.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_options_after_command.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_output_merge.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_output_robustness.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_packaging.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_command.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_command_exit.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_run_on_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_runtime_dir.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_smoke_optional.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_ssh_error_text.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_ssh_timeouts.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_start_run_on_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_stopped_commands.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_stream_reader.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_tui_ssh_notices.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/test_unavailable_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.33}/tests/vt_grid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multiSSH3
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.33
|
|
4
4
|
Summary: Run commands on multiple hosts via SSH
|
|
5
5
|
Home-page: https://github.com/yufei-pan/multiSSH3
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -182,7 +182,7 @@ Defaults are read from the following chain map stored as json files, top ones ov
|
|
|
182
182
|
>
|
|
183
183
|
> A config file that is a symlink (e.g. into a dotfiles repository) is written through the link; its backup (`.bak`, the default answer when the file exists) is a copy next to the link.
|
|
184
184
|
>
|
|
185
|
-
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null
|
|
185
|
+
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null` is `all`). A file that is not a JSON object is skipped the same way. `--config_file` applies a file exactly as the chain does, `_sshPath`, `DEFAULT_ENV_FILE` and `ERROR_MESSAGES_TO_IGNORE` included.
|
|
186
186
|
|
|
187
187
|
### Generating / Storing Config File
|
|
188
188
|
To store / generate a config file with the current command line options, you can use
|
|
@@ -490,7 +490,7 @@ mssh --completion uninstall # remove it again
|
|
|
490
490
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
491
491
|
```
|
|
492
492
|
|
|
493
|
-
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
493
|
+
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. A zsh completion dump (`.zcompdump`) written while the script was loaded still maps `mssh` to the removed `_mssh`; uninstall names such a file, for you to delete, and zsh makes a new one. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
494
494
|
|
|
495
495
|
A new block is appended to your rc file; changing or removing it replaces the file in one step, so a full disk or quota leaves it as it was. A link stays a link (the file it points to is the one changed), and the file keeps its permissions and owner (not ACLs or other extended attributes). If the block's `# >>> mssh completion >>>` or `# <<< mssh completion <<<` line is missing or repeated, install and uninstall change nothing and print the line numbers to fix by hand. When mssh may not change the file (read-only, or linked into a read-only store as home-manager does, or not a regular file, such as a link to `/dev/null`), or cannot replace it safely to change a block (bind-mounted, hard-linked, or another user's), it leaves the file as it is and prints the lines to add, replace or delete by hand.
|
|
496
496
|
|
|
@@ -551,7 +551,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
551
551
|
| Environment variable | Effect |
|
|
552
552
|
| --- | --- |
|
|
553
553
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
554
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
554
|
+
| `MSSH_COMPLETE_START_TIMEOUT` | seconds the shell waits for the Ctrl-R menu (and bash's line editor) to open (default 2); past that, Ctrl-R does what it did before and space is a space. Ctrl-C while it opens keeps the line. A menu that opens later leaves the terminal alone |
|
|
555
555
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
556
556
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
557
557
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -584,8 +584,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
584
584
|
- You can specify the password for all hosts using this option. Although it is recommended to use SSH keys / store password in config file for authentication.
|
|
585
585
|
- `-p` needs `sshpass`, which types the password when ssh asks for it and answers nothing else. When ssh asks again or asks about a host key, sshpass gives up without a word, and mssh says why next to the return code: 5 the password was not accepted, 6 ssh asked whether to trust a host key that is not in `known_hosts` (the host's own with `SSH_STRICT_HOST_KEY_CHECKING` true, else a ProxyJump host's), 7 `known_hosts` has a different key for the host's IP address. A command of yours that prints nothing can exit with the same codes, so the line says `unless the command itself exited with N`; with `SSH_STRICT_HOST_KEY_CHECKING` false and no ProxyJump (or ProxyCommand) in the ssh config, 6 and 7 can only be the command's and mssh adds nothing.
|
|
586
586
|
- Warning: by default mssh does not check host keys, so the password goes to whichever machine answers at the host's address. See [Host Key Checking](#host-key-checking).
|
|
587
|
-
-
|
|
588
|
-
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included.
|
|
587
|
+
- mssh never shows or stores the password: the `> mssh ...` line and the history file (`-hf`, default `~/.mssh_history`) list it as `-p -`, so running either again asks for it. Typed on mssh's own command line, though, it can be seen by other local users (in `ps`) and lands in your shell history. To keep it off the command line, `-p -` asks for it on the terminal (nothing is echoed; without a terminal, or without an answer, mssh stops before running anything), or set `MSSH_PASSWORD` in the environment, or `DEFAULT_PASSWORD` in a config file (plain text, so keep that file private). `-p` on the command line wins over `MSSH_PASSWORD`, which wins over `DEFAULT_PASSWORD`; neither of those two is listed in the `> mssh ...` line or the history, as a replay gets them again, and `--store_config_file` does not write `MSSH_PASSWORD` into the config.
|
|
588
|
+
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included. They reach `sshpass` and `ipmitool`, as a password typed on the command line does, through their environment (`sshpass -e`, `ipmitool -E` with `IPMI_PASSWORD` and `IPMITOOL_PASSWORD`), which other local users cannot read, not as arguments `ps` shows them. `redfishtool` has no such option: it gets its password as an argument, visible in `ps` while it runs.
|
|
589
589
|
|
|
590
590
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
591
591
|
- You can specify the identity file or folder to use for public key authentication. If a folder is specified, it will search for a key file inside the folder.
|
|
@@ -711,15 +711,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
711
711
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
712
712
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
713
713
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
714
|
-
-
|
|
714
|
+
- It is left out of the `> mssh ...` line and the history file (not even as `-p -` is for `-p`), and when it is given, so are `-iu`, `-ia`, `-im`, `-mpre` and `-irlt`: with the configured password they would make a login you did not give, tried on every BMC (each failed login counts towards the BMC locking the account). A replayed history line tries the configured logins, as `--ipmi` alone does; give the IPMI options again to use yours.
|
|
715
715
|
|
|
716
716
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
717
717
|
- Extra arguments for ipmitool (or redfishtool) in `--ipmi` mode, in one string, placed as they are before the command. `-ea` arguments only go to ssh / scp / rsync.
|
|
718
|
-
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -
|
|
718
|
+
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -E -I lanplus power status`, with the password in its environment. Use `=`, as the value starts with `-`.
|
|
719
719
|
|
|
720
720
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
721
721
|
- How `--ipmi` reaches a host:
|
|
722
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
722
|
+
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -E [IPMI_ARGS] <command>` on this machine; `-E` reads the password from the environment mssh gives it.
|
|
723
723
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
724
724
|
- `ssh_ipmitool`: logs in to the host over ssh with the IPMI username and password (`-iu` / `-ip`, so `admin` / `admin` unless set) and runs `ipmitool <command>` there.
|
|
725
725
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -876,7 +876,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
876
876
|
|
|
877
877
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
878
878
|
- The file to store command history.
|
|
879
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
879
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
880
880
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
881
881
|
- A line records the command so that replaying it (the Ctrl-R picker, `mssh-complete`) runs it the same way: the hosts as typed and every option that changes what runs, where, or what is shown; a flag when it is on, an option with a value when the value is not the default (the config files' `DEFAULT_*`). `-T`, `-uk` (or `-k` with a folder), `--script` and `-s PATH` are recorded as the timeout, key file and options they chose, `--config_file` and `--host_file` with their absolute paths. Not recorded: `-ip` (and with it the other IPMI options, see `-ip`), and `--generate_config_file`, `--store_config_file` and `--add_control_master_config`, which do something besides the run. The `> mssh ...` line mssh prints at start lists the same options.
|
|
882
882
|
|
|
@@ -970,7 +970,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
970
970
|
|
|
971
971
|
Putting the command after `--` is no substitute for quotes: every word after the hosts is a command of its own, so `mssh web1 -- bash -c 'echo hi'` runs `bash`, `-c` and `echo hi` one after another (when each word is a single word, as in `mssh web1 -- ls -la`, mssh asks whether to join them).
|
|
972
972
|
|
|
973
|
-
Below is a sample help message output from multiSSH3 6.
|
|
973
|
+
Below is a sample help message output from multiSSH3 6.33 @ 2026-10-14 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
974
974
|
|
|
975
975
|
```bash
|
|
976
976
|
$ mssh -h
|
|
@@ -996,7 +996,7 @@ options:
|
|
|
996
996
|
-u, --username USERNAME
|
|
997
997
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
998
998
|
-p, --password PASSWORD
|
|
999
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
999
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
1000
1000
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
1001
1001
|
The identity file to use to connect to the hosts. Implies --use_key. Specify a folder for program to search for a key. Use option without value to use ~/.ssh/ (default: None)
|
|
1002
1002
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1370,6 +1370,8 @@ __DEBUG_MODE = False
|
|
|
1370
1370
|
|
|
1371
1371
|
> `_DEFAULT_NO_START` is somewhat analogous to "demo mode" where mssh will return Host objects without actually allocating and starting the execution threads. Although they still can be started using `start_run_on_hosts()` but you should really be looking for `return_unfinished` instead for asynchronicity.
|
|
1372
1372
|
|
|
1373
|
+
> `run_command_on_hosts` reads `_DEFAULT_CALLED`, `_DEFAULT_RETURN_UNFINISHED`, `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` and `_DEFAULT_NO_START` each time it is called, so setting them after `import multiSSH3`, or in a file given with `--config_file`, works. The `mssh` command always starts its hosts and waits for them: of these four, only `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` changes what it does.
|
|
1374
|
+
|
|
1373
1375
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1374
1376
|
|
|
1375
1377
|
> `ERROR_MESSAGES_TO_IGNORE` lists regexes for ssh's own notices, which mssh leaves out of each host's stderr (also in `--json` and `--greppable` output). Each regex is searched anywhere in every stderr line, so anchor yours with `^` and `$` to match whole lines (in the JSON config file, write a regex backslash as `\\`). The defaults are anchored to the lines OpenSSH prints, so a remote program's error that uses the same words, such as curl's `Recv failure: Connection reset by peer`, is kept. Connection resets are not hidden: `kex_exchange_identification: read: Connection reset by peer` is how sshd's `MaxStartups` turns away connections opened at once. Config files that `--store_config_file` or `--generate_config_file` wrote before 6.20 hold a copy of the old, unanchored defaults; mssh ignores such an unchanged copy and uses the current defaults.
|
|
@@ -156,7 +156,7 @@ Defaults are read from the following chain map stored as json files, top ones ov
|
|
|
156
156
|
>
|
|
157
157
|
> A config file that is a symlink (e.g. into a dotfiles repository) is written through the link; its backup (`.bak`, the default answer when the file exists) is a copy next to the link.
|
|
158
158
|
>
|
|
159
|
-
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null
|
|
159
|
+
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null` is `all`). A file that is not a JSON object is skipped the same way. `--config_file` applies a file exactly as the chain does, `_sshPath`, `DEFAULT_ENV_FILE` and `ERROR_MESSAGES_TO_IGNORE` included.
|
|
160
160
|
|
|
161
161
|
### Generating / Storing Config File
|
|
162
162
|
To store / generate a config file with the current command line options, you can use
|
|
@@ -464,7 +464,7 @@ mssh --completion uninstall # remove it again
|
|
|
464
464
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
465
465
|
```
|
|
466
466
|
|
|
467
|
-
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
467
|
+
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. A zsh completion dump (`.zcompdump`) written while the script was loaded still maps `mssh` to the removed `_mssh`; uninstall names such a file, for you to delete, and zsh makes a new one. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
468
468
|
|
|
469
469
|
A new block is appended to your rc file; changing or removing it replaces the file in one step, so a full disk or quota leaves it as it was. A link stays a link (the file it points to is the one changed), and the file keeps its permissions and owner (not ACLs or other extended attributes). If the block's `# >>> mssh completion >>>` or `# <<< mssh completion <<<` line is missing or repeated, install and uninstall change nothing and print the line numbers to fix by hand. When mssh may not change the file (read-only, or linked into a read-only store as home-manager does, or not a regular file, such as a link to `/dev/null`), or cannot replace it safely to change a block (bind-mounted, hard-linked, or another user's), it leaves the file as it is and prints the lines to add, replace or delete by hand.
|
|
470
470
|
|
|
@@ -525,7 +525,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
525
525
|
| Environment variable | Effect |
|
|
526
526
|
| --- | --- |
|
|
527
527
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
528
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
528
|
+
| `MSSH_COMPLETE_START_TIMEOUT` | seconds the shell waits for the Ctrl-R menu (and bash's line editor) to open (default 2); past that, Ctrl-R does what it did before and space is a space. Ctrl-C while it opens keeps the line. A menu that opens later leaves the terminal alone |
|
|
529
529
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
530
530
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
531
531
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -558,8 +558,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
558
558
|
- You can specify the password for all hosts using this option. Although it is recommended to use SSH keys / store password in config file for authentication.
|
|
559
559
|
- `-p` needs `sshpass`, which types the password when ssh asks for it and answers nothing else. When ssh asks again or asks about a host key, sshpass gives up without a word, and mssh says why next to the return code: 5 the password was not accepted, 6 ssh asked whether to trust a host key that is not in `known_hosts` (the host's own with `SSH_STRICT_HOST_KEY_CHECKING` true, else a ProxyJump host's), 7 `known_hosts` has a different key for the host's IP address. A command of yours that prints nothing can exit with the same codes, so the line says `unless the command itself exited with N`; with `SSH_STRICT_HOST_KEY_CHECKING` false and no ProxyJump (or ProxyCommand) in the ssh config, 6 and 7 can only be the command's and mssh adds nothing.
|
|
560
560
|
- Warning: by default mssh does not check host keys, so the password goes to whichever machine answers at the host's address. See [Host Key Checking](#host-key-checking).
|
|
561
|
-
-
|
|
562
|
-
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included.
|
|
561
|
+
- mssh never shows or stores the password: the `> mssh ...` line and the history file (`-hf`, default `~/.mssh_history`) list it as `-p -`, so running either again asks for it. Typed on mssh's own command line, though, it can be seen by other local users (in `ps`) and lands in your shell history. To keep it off the command line, `-p -` asks for it on the terminal (nothing is echoed; without a terminal, or without an answer, mssh stops before running anything), or set `MSSH_PASSWORD` in the environment, or `DEFAULT_PASSWORD` in a config file (plain text, so keep that file private). `-p` on the command line wins over `MSSH_PASSWORD`, which wins over `DEFAULT_PASSWORD`; neither of those two is listed in the `> mssh ...` line or the history, as a replay gets them again, and `--store_config_file` does not write `MSSH_PASSWORD` into the config.
|
|
562
|
+
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included. They reach `sshpass` and `ipmitool`, as a password typed on the command line does, through their environment (`sshpass -e`, `ipmitool -E` with `IPMI_PASSWORD` and `IPMITOOL_PASSWORD`), which other local users cannot read, not as arguments `ps` shows them. `redfishtool` has no such option: it gets its password as an argument, visible in `ps` while it runs.
|
|
563
563
|
|
|
564
564
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
565
565
|
- You can specify the identity file or folder to use for public key authentication. If a folder is specified, it will search for a key file inside the folder.
|
|
@@ -685,15 +685,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
685
685
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
686
686
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
687
687
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
688
|
-
-
|
|
688
|
+
- It is left out of the `> mssh ...` line and the history file (not even as `-p -` is for `-p`), and when it is given, so are `-iu`, `-ia`, `-im`, `-mpre` and `-irlt`: with the configured password they would make a login you did not give, tried on every BMC (each failed login counts towards the BMC locking the account). A replayed history line tries the configured logins, as `--ipmi` alone does; give the IPMI options again to use yours.
|
|
689
689
|
|
|
690
690
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
691
691
|
- Extra arguments for ipmitool (or redfishtool) in `--ipmi` mode, in one string, placed as they are before the command. `-ea` arguments only go to ssh / scp / rsync.
|
|
692
|
-
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -
|
|
692
|
+
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -E -I lanplus power status`, with the password in its environment. Use `=`, as the value starts with `-`.
|
|
693
693
|
|
|
694
694
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
695
695
|
- How `--ipmi` reaches a host:
|
|
696
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
696
|
+
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -E [IPMI_ARGS] <command>` on this machine; `-E` reads the password from the environment mssh gives it.
|
|
697
697
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
698
698
|
- `ssh_ipmitool`: logs in to the host over ssh with the IPMI username and password (`-iu` / `-ip`, so `admin` / `admin` unless set) and runs `ipmitool <command>` there.
|
|
699
699
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -850,7 +850,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
850
850
|
|
|
851
851
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
852
852
|
- The file to store command history.
|
|
853
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
853
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
854
854
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
855
855
|
- A line records the command so that replaying it (the Ctrl-R picker, `mssh-complete`) runs it the same way: the hosts as typed and every option that changes what runs, where, or what is shown; a flag when it is on, an option with a value when the value is not the default (the config files' `DEFAULT_*`). `-T`, `-uk` (or `-k` with a folder), `--script` and `-s PATH` are recorded as the timeout, key file and options they chose, `--config_file` and `--host_file` with their absolute paths. Not recorded: `-ip` (and with it the other IPMI options, see `-ip`), and `--generate_config_file`, `--store_config_file` and `--add_control_master_config`, which do something besides the run. The `> mssh ...` line mssh prints at start lists the same options.
|
|
856
856
|
|
|
@@ -944,7 +944,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
944
944
|
|
|
945
945
|
Putting the command after `--` is no substitute for quotes: every word after the hosts is a command of its own, so `mssh web1 -- bash -c 'echo hi'` runs `bash`, `-c` and `echo hi` one after another (when each word is a single word, as in `mssh web1 -- ls -la`, mssh asks whether to join them).
|
|
946
946
|
|
|
947
|
-
Below is a sample help message output from multiSSH3 6.
|
|
947
|
+
Below is a sample help message output from multiSSH3 6.33 @ 2026-10-14 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
948
948
|
|
|
949
949
|
```bash
|
|
950
950
|
$ mssh -h
|
|
@@ -970,7 +970,7 @@ options:
|
|
|
970
970
|
-u, --username USERNAME
|
|
971
971
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
972
972
|
-p, --password PASSWORD
|
|
973
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
973
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
974
974
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
975
975
|
The identity file to use to connect to the hosts. Implies --use_key. Specify a folder for program to search for a key. Use option without value to use ~/.ssh/ (default: None)
|
|
976
976
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1344,6 +1344,8 @@ __DEBUG_MODE = False
|
|
|
1344
1344
|
|
|
1345
1345
|
> `_DEFAULT_NO_START` is somewhat analogous to "demo mode" where mssh will return Host objects without actually allocating and starting the execution threads. Although they still can be started using `start_run_on_hosts()` but you should really be looking for `return_unfinished` instead for asynchronicity.
|
|
1346
1346
|
|
|
1347
|
+
> `run_command_on_hosts` reads `_DEFAULT_CALLED`, `_DEFAULT_RETURN_UNFINISHED`, `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` and `_DEFAULT_NO_START` each time it is called, so setting them after `import multiSSH3`, or in a file given with `--config_file`, works. The `mssh` command always starts its hosts and waits for them: of these four, only `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` changes what it does.
|
|
1348
|
+
|
|
1347
1349
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1348
1350
|
|
|
1349
1351
|
> `ERROR_MESSAGES_TO_IGNORE` lists regexes for ssh's own notices, which mssh leaves out of each host's stderr (also in `--json` and `--greppable` output). Each regex is searched anywhere in every stderr line, so anchor yours with `^` and `$` to match whole lines (in the JSON config file, write a regex backslash as `\\`). The defaults are anchored to the lines OpenSSH prints, so a remote program's error that uses the same words, such as curl's `Recv failure: Connection reset by peer`, is kept. Connection resets are not hidden: `kex_exchange_identification: read: Connection reset by peer` is how sshd's `MaxStartups` turns away connections opened at once. Config files that `--store_config_file` or `--generate_config_file` wrote before 6.20 hold a copy of the old, unanchored defaults; mssh ignores such an unchanged copy and uses the current defaults.
|
|
@@ -16,7 +16,7 @@ import sys
|
|
|
16
16
|
import time
|
|
17
17
|
from bisect import bisect_left
|
|
18
18
|
|
|
19
|
-
version = '0.
|
|
19
|
+
version = '0.6'
|
|
20
20
|
__version__ = version
|
|
21
21
|
PROTOCOL = 'MSSHC1'
|
|
22
22
|
MSSH_NAMES = ('mssh', 'mssh3', 'multissh', 'multissh3', 'multiSSH3')
|
|
@@ -5769,6 +5769,42 @@ class LineEditor(object):
|
|
|
5769
5769
|
self.draw(term, prompt, style)
|
|
5770
5770
|
|
|
5771
5771
|
#%% ------------ Shell glue ----------------
|
|
5772
|
+
# zsh and fish run the picker through this POSIX sh: sh -c START_SCRIPT sh SECONDS PICKER-COMMAND...
|
|
5773
|
+
# The picker creates MSSH_COMPLETE_CLAIM just before it takes the terminal (_claim_terminal). It is
|
|
5774
|
+
# given SECONDS to do so: then, or on Ctrl-C while it starts, the script creates it first and stops the
|
|
5775
|
+
# picker, which has not touched the terminal (a hung file system can keep it from starting, deaf to
|
|
5776
|
+
# Ctrl-C). mkdir succeeds for one of the two only. Exit status: the picker's, 124 when it was too slow,
|
|
5777
|
+
# 130 on Ctrl-C. The picker runs in the background of this sh, in the shell's process group: it can
|
|
5778
|
+
# read the terminal. Its answer goes through a file: a process it leaves behind when stopped cannot
|
|
5779
|
+
# keep the shell's command substitution open. bash waits for its "ready" line instead (_mssh_complete_start).
|
|
5780
|
+
START_SCRIPT = r"""limit=$1
|
|
5781
|
+
shift
|
|
5782
|
+
dir=$(mktemp -d 2>/dev/null) || exec "$@"
|
|
5783
|
+
exec 3<&0
|
|
5784
|
+
MSSH_COMPLETE_CLAIM=$dir/claim "$@" <&3 3<&- >"$dir/answer" &
|
|
5785
|
+
pid=$!
|
|
5786
|
+
exec 3<&-
|
|
5787
|
+
stop() {
|
|
5788
|
+
mkdir "$dir/claim" 2>/dev/null && : > "$dir/$1" && kill -9 "$pid"
|
|
5789
|
+
}
|
|
5790
|
+
# the sleeper: nothing of it may keep the shell's command substitution open, and Ctrl-C is the
|
|
5791
|
+
# trap's (bash does not make a background subshell ignore it, as dash and busybox do)
|
|
5792
|
+
{ trap '' INT; sleep "$limit"; stop late; } </dev/null >/dev/null 2>&1 &
|
|
5793
|
+
sleeper=$!
|
|
5794
|
+
trap 'stop stopped' INT
|
|
5795
|
+
while :; do
|
|
5796
|
+
wait "$pid"
|
|
5797
|
+
status=$?
|
|
5798
|
+
kill -0 "$pid" 2>/dev/null || break
|
|
5799
|
+
done
|
|
5800
|
+
kill "$sleeper" 2>/dev/null
|
|
5801
|
+
[ -e "$dir/stopped" ] && status=130
|
|
5802
|
+
[ -e "$dir/late" ] && status=124
|
|
5803
|
+
cat "$dir/answer" 2>/dev/null
|
|
5804
|
+
rm -rf "$dir"
|
|
5805
|
+
exit "$status"
|
|
5806
|
+
"""
|
|
5807
|
+
|
|
5772
5808
|
GLUE_MARK = 'MSSH_COMPLETE_GLUE'
|
|
5773
5809
|
|
|
5774
5810
|
BASH_GLUE = r'''# MSSH_COMPLETE_GLUE @VERSION@ bash: autocomplete for mssh (multiSSH3), protocol MSSHC1
|
|
@@ -6489,6 +6525,18 @@ _mssh_complete_engine() {
|
|
|
6489
6525
|
@ENGINE@ "$@"
|
|
6490
6526
|
}
|
|
6491
6527
|
|
|
6528
|
+
typeset -g _mssh_complete_start_script=@START@
|
|
6529
|
+
|
|
6530
|
+
_mssh_complete_start_pick() {
|
|
6531
|
+
# the picker, reading the request on stdin: MSSH_COMPLETE_START_TIMEOUT seconds (2) at most to take
|
|
6532
|
+
# the terminal, then as long as the operator takes. 124 when too slow, 130 on Ctrl-C while it
|
|
6533
|
+
# starts: see START_SCRIPT in mssh_complete.py
|
|
6534
|
+
emulate -L zsh
|
|
6535
|
+
local limit=${MSSH_COMPLETE_START_TIMEOUT:-2}
|
|
6536
|
+
[[ $limit == (<->|<->.<->|.<->) ]] || limit=2
|
|
6537
|
+
command sh -c "$_mssh_complete_start_script" sh "$limit" @ENGINE@ pick
|
|
6538
|
+
}
|
|
6539
|
+
|
|
6492
6540
|
_mssh_complete_keep_terminal() {
|
|
6493
6541
|
# after each `exec {fd}< <(...)`: before zsh 5.8 the process substitution takes the terminal from the
|
|
6494
6542
|
# shell (Ctrl-C then goes to it, and the shell's next reads can fail with "error on TTY read"); a
|
|
@@ -6517,7 +6565,10 @@ _mssh_complete_ctrl_r() {
|
|
|
6517
6565
|
emulate -L zsh
|
|
6518
6566
|
local resp line text= cursor= st
|
|
6519
6567
|
if _mssh_complete_is_mssh "$BUFFER"; then
|
|
6520
|
-
|
|
6568
|
+
# Ctrl-C while the picker starts stops it (130), and keeps the line: without a trap of its own
|
|
6569
|
+
# (local: emulate -L), zsh would end the widget and drop the line
|
|
6570
|
+
trap : INT
|
|
6571
|
+
resp=$(_mssh_complete_request 'pick=1 nul=0' "$LBUFFER" "$RBUFFER" | _mssh_complete_start_pick 2>/dev/null)
|
|
6521
6572
|
st=$?
|
|
6522
6573
|
if (( st == 0 )) && [[ $resp == MSSHC1$'\n'*$'\n'E ]]; then
|
|
6523
6574
|
for line in "${(@f)resp}"; do
|
|
@@ -6538,6 +6589,8 @@ _mssh_complete_ctrl_r() {
|
|
|
6538
6589
|
[[ -n ${_mssh_complete_warn_reason-} ]] && zle -M -- "$_mssh_complete_warn_reason"
|
|
6539
6590
|
return 0
|
|
6540
6591
|
fi
|
|
6592
|
+
# Ctrl-C while it started: the line stays as it is. Too slow (124): what Ctrl-R did before
|
|
6593
|
+
(( st == 130 )) && return 0
|
|
6541
6594
|
fi
|
|
6542
6595
|
[[ -n $_mssh_complete_previous ]] && zle $_mssh_complete_previous
|
|
6543
6596
|
return 0
|
|
@@ -7064,6 +7117,7 @@ switch "$FISH_VERSION"
|
|
|
7064
7117
|
if not set -q __mssh_complete_keys
|
|
7065
7118
|
set -g __mssh_complete_keys 1
|
|
7066
7119
|
''' + _fish_nested(_FISH_QUERY, 3) + r'''
|
|
7120
|
+
set -g __mssh_complete_start_script @START@
|
|
7067
7121
|
function __mssh_complete_is_mssh
|
|
7068
7122
|
string match -qr '^\s*(\S*/)?(mssh|mssh3|multissh|multissh3|multiSSH3)\s' -- "$argv[1]"
|
|
7069
7123
|
end
|
|
@@ -7076,10 +7130,14 @@ switch "$FISH_VERSION"
|
|
|
7076
7130
|
set -l keep 1000
|
|
7077
7131
|
set -q MSSH_COMPLETE_SHELL_HISTORY; and set keep $MSSH_COMPLETE_SHELL_HISTORY
|
|
7078
7132
|
# the history builtin: the operator's history function or alias (one showing times) would change the lines
|
|
7133
|
+
# MSSH_COMPLETE_START_TIMEOUT seconds (2) at most for the picker to take the terminal, then as
|
|
7134
|
+
# long as the operator takes: 124 when too slow, 130 on Ctrl-C while it starts (START_SCRIPT)
|
|
7135
|
+
set -l limit 2
|
|
7136
|
+
string match -qr '^(\d+|\d+\.\d*|\.\d+)$' -- "$MSSH_COMPLETE_START_TIMEOUT"; and set limit $MSSH_COMPLETE_START_TIMEOUT
|
|
7079
7137
|
set -l lines (begin
|
|
7080
7138
|
command printf '%s\0' MSSHC1 fish $FISH_VERSION "pick=1 nul=0 term=$TERM" "$before" "$after" ''
|
|
7081
7139
|
builtin history search -n $keep 2>/dev/null
|
|
7082
|
-
end | @ENGINE@ pick 2>/dev/null)
|
|
7140
|
+
end | command sh -c $__mssh_complete_start_script sh $limit @ENGINE@ pick 2>/dev/null)
|
|
7083
7141
|
set -l st $status
|
|
7084
7142
|
if test $st -eq 0; and test (count $lines) -ge 3; and test "$lines[1]" = MSSHC1; and test "$lines[-1]" = E
|
|
7085
7143
|
for line in $lines[2..-2]
|
|
@@ -7090,7 +7148,8 @@ switch "$FISH_VERSION"
|
|
|
7090
7148
|
end
|
|
7091
7149
|
end
|
|
7092
7150
|
commandline -f repaint
|
|
7093
|
-
|
|
7151
|
+
# Ctrl-C while it started: the line stays as it is. Too slow (124): what Ctrl-R did before
|
|
7152
|
+
test $st -le 1; or test $st -eq 130; and return
|
|
7094
7153
|
end
|
|
7095
7154
|
set -l previous __mssh_complete_previous_$mode
|
|
7096
7155
|
for command in $$previous
|
|
@@ -7213,6 +7272,7 @@ def render_glue(shell, command=None):
|
|
|
7213
7272
|
command = engine_command() if command is None else command
|
|
7214
7273
|
quote = _fish_quote if shell.startswith('fish') else shlex.quote
|
|
7215
7274
|
text = _GLUES[shell].replace('@VERSION@', version).replace('@ENGINE@', ' '.join(quote(word) for word in command))
|
|
7275
|
+
text = text.replace('@START@', quote(START_SCRIPT))
|
|
7216
7276
|
return _zsh_guard(text) if shell == 'zsh' else text
|
|
7217
7277
|
|
|
7218
7278
|
#%% ------------ Printing to a reader that may go ----------------
|
|
@@ -7826,8 +7886,38 @@ def uninstall(shell, home=None, environ=None):
|
|
|
7826
7886
|
return 1, messages + list(error.args)
|
|
7827
7887
|
if len(messages) == (1 if paths.get('note') else 0):
|
|
7828
7888
|
messages.append('nothing to remove')
|
|
7889
|
+
if shell == 'zsh':
|
|
7890
|
+
for dump in _zsh_dumps_naming_mssh(home, environ):
|
|
7891
|
+
messages.append("zsh's completion dump {0} still maps mssh to _mssh, which is gone: "
|
|
7892
|
+
"remove it (rm {0}) and zsh makes a new one".format(dump))
|
|
7829
7893
|
return 0, messages
|
|
7830
7894
|
|
|
7895
|
+
def _zsh_dumps_naming_mssh(home, environ):
|
|
7896
|
+
'''
|
|
7897
|
+
The zsh completion dumps (compinit's .zcompdump, oh-my-zsh's .zcompdump-HOST-VERSION) that map mssh
|
|
7898
|
+
to _mssh. A dump written while the glue was loaded keeps that after it is removed, and zsh then
|
|
7899
|
+
answers TAB with "command not found: _mssh". They are zsh's: they are named, not changed.
|
|
7900
|
+
'''
|
|
7901
|
+
candidates = [environ.get('ZSH_COMPDUMP')]
|
|
7902
|
+
for directory in (environ.get('ZDOTDIR'), home):
|
|
7903
|
+
try:
|
|
7904
|
+
names = sorted(os.listdir(directory)) if directory else []
|
|
7905
|
+
except OSError:
|
|
7906
|
+
names = []
|
|
7907
|
+
candidates.extend(os.path.join(directory, name) for name in names
|
|
7908
|
+
if name.startswith('.zcompdump') and not name.endswith('.zwc'))
|
|
7909
|
+
found = []
|
|
7910
|
+
for path in candidates:
|
|
7911
|
+
if not path or path in found:
|
|
7912
|
+
continue
|
|
7913
|
+
try:
|
|
7914
|
+
with open(path, encoding='utf-8', errors='replace') as dump:
|
|
7915
|
+
if "'_mssh'" in dump.read(4 << 20):
|
|
7916
|
+
found.append(path)
|
|
7917
|
+
except OSError:
|
|
7918
|
+
pass
|
|
7919
|
+
return found
|
|
7920
|
+
|
|
7831
7921
|
def prepare_index():
|
|
7832
7922
|
'''
|
|
7833
7923
|
Build the index now, for `mssh --completion install`: the first TAB in a new shell then answers
|
|
@@ -8235,6 +8325,25 @@ def _ready():
|
|
|
8235
8325
|
except OSError:
|
|
8236
8326
|
return False
|
|
8237
8327
|
|
|
8328
|
+
def _claim_terminal():
|
|
8329
|
+
'''
|
|
8330
|
+
Create the directory MSSH_COMPLETE_CLAIM names (zsh and fish set it), just before taking the terminal.
|
|
8331
|
+
|
|
8332
|
+
The shell waits only so long (MSSH_COMPLETE_START_TIMEOUT) for the picker to take it, and creates
|
|
8333
|
+
that directory itself when it stops waiting (also on Ctrl-C): mkdir succeeds for one of the two
|
|
8334
|
+
only, so a picker slow to start never draws after the shell went on. True when the terminal is
|
|
8335
|
+
ours (also without MSSH_COMPLETE_CLAIM, as bash runs it).
|
|
8336
|
+
'''
|
|
8337
|
+
path = os.environ.get('MSSH_COMPLETE_CLAIM')
|
|
8338
|
+
if not path:
|
|
8339
|
+
return True
|
|
8340
|
+
try:
|
|
8341
|
+
os.mkdir(path, 0o700)
|
|
8342
|
+
return True
|
|
8343
|
+
except OSError as e:
|
|
8344
|
+
_debug('pick: the shell went on ({!r}): leaving the terminal alone'.format(e))
|
|
8345
|
+
return False
|
|
8346
|
+
|
|
8238
8347
|
def _cmd_pick():
|
|
8239
8348
|
'''
|
|
8240
8349
|
mssh-complete pick: the Ctrl-R picker. Reads a request on stdin, draws on /dev/tty, prints the new
|
|
@@ -8261,7 +8370,7 @@ def _cmd_pick():
|
|
|
8261
8370
|
line = before = None
|
|
8262
8371
|
if prompt is not None:
|
|
8263
8372
|
line, before = prompt + request.before + request.after, prompt + request.before
|
|
8264
|
-
if request.flags.get('ready') == '1' and not _ready():
|
|
8373
|
+
if not _claim_terminal() or (request.flags.get('ready') == '1' and not _ready()):
|
|
8265
8374
|
return 2
|
|
8266
8375
|
with Terminal() as term:
|
|
8267
8376
|
outcome = picker.run(term, line, before)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multiSSH3
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.33
|
|
4
4
|
Summary: Run commands on multiple hosts via SSH
|
|
5
5
|
Home-page: https://github.com/yufei-pan/multiSSH3
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -182,7 +182,7 @@ Defaults are read from the following chain map stored as json files, top ones ov
|
|
|
182
182
|
>
|
|
183
183
|
> A config file that is a symlink (e.g. into a dotfiles repository) is written through the link; its backup (`.bak`, the default answer when the file exists) is a copy next to the link.
|
|
184
184
|
>
|
|
185
|
-
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null
|
|
185
|
+
> Each value is checked against the type of the setting's default. Values whose meaning is clear are converted (`"true"` / `"false"`, `"yes"` / `"no"` for true / false settings, numbers written as strings, a list of host names for `DEFAULT_HOSTS`); anything else, such as `"DEFAULT_TIMEOUT": "fifty"` or an encoding Python does not know, is ignored with a warning naming the file and the key, and the setting keeps its value from the rest of the chain (no warning when a more specific file sets that key anyway). `null` for a string setting means its default (`DEFAULT_HOSTS: null` is `all`). A file that is not a JSON object is skipped the same way. `--config_file` applies a file exactly as the chain does, `_sshPath`, `DEFAULT_ENV_FILE` and `ERROR_MESSAGES_TO_IGNORE` included.
|
|
186
186
|
|
|
187
187
|
### Generating / Storing Config File
|
|
188
188
|
To store / generate a config file with the current command line options, you can use
|
|
@@ -490,7 +490,7 @@ mssh --completion uninstall # remove it again
|
|
|
490
490
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
491
491
|
```
|
|
492
492
|
|
|
493
|
-
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
493
|
+
Install writes the script to `~/.local/share/multiSSH3/` and adds a marked block that loads it to `~/.bashrc` (bash) or `$ZDOTDIR/.zshrc` (zsh, which install asks, so a `ZDOTDIR` set in `~/.zshenv` counts; `~/.zshrc` when `ZDOTDIR` is not set); for fish it writes files under `~/.config/fish/` (`$XDG_CONFIG_HOME/fish/` when that is set). It prints every file it changes, and leaves alone a script file in its way that mssh did not write. Uninstall removes exactly what install added. A zsh completion dump (`.zcompdump`) written while the script was loaded still maps `mssh` to the removed `_mssh`; uninstall names such a file, for you to delete, and zsh makes a new one. bash login shells (ssh logins, macOS terminals) read `~/.bash_profile`, `~/.bash_login` or `~/.profile` instead of `~/.bashrc`; those usually load `~/.bashrc`, and install prints the line to add when yours does not.
|
|
494
494
|
|
|
495
495
|
A new block is appended to your rc file; changing or removing it replaces the file in one step, so a full disk or quota leaves it as it was. A link stays a link (the file it points to is the one changed), and the file keeps its permissions and owner (not ACLs or other extended attributes). If the block's `# >>> mssh completion >>>` or `# <<< mssh completion <<<` line is missing or repeated, install and uninstall change nothing and print the line numbers to fix by hand. When mssh may not change the file (read-only, or linked into a read-only store as home-manager does, or not a regular file, such as a link to `/dev/null`), or cannot replace it safely to change a block (bind-mounted, hard-linked, or another user's), it leaves the file as it is and prints the lines to add, replace or delete by hand.
|
|
496
496
|
|
|
@@ -551,7 +551,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
551
551
|
| Environment variable | Effect |
|
|
552
552
|
| --- | --- |
|
|
553
553
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
554
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
554
|
+
| `MSSH_COMPLETE_START_TIMEOUT` | seconds the shell waits for the Ctrl-R menu (and bash's line editor) to open (default 2); past that, Ctrl-R does what it did before and space is a space. Ctrl-C while it opens keeps the line. A menu that opens later leaves the terminal alone |
|
|
555
555
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
556
556
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
557
557
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -584,8 +584,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
584
584
|
- You can specify the password for all hosts using this option. Although it is recommended to use SSH keys / store password in config file for authentication.
|
|
585
585
|
- `-p` needs `sshpass`, which types the password when ssh asks for it and answers nothing else. When ssh asks again or asks about a host key, sshpass gives up without a word, and mssh says why next to the return code: 5 the password was not accepted, 6 ssh asked whether to trust a host key that is not in `known_hosts` (the host's own with `SSH_STRICT_HOST_KEY_CHECKING` true, else a ProxyJump host's), 7 `known_hosts` has a different key for the host's IP address. A command of yours that prints nothing can exit with the same codes, so the line says `unless the command itself exited with N`; with `SSH_STRICT_HOST_KEY_CHECKING` false and no ProxyJump (or ProxyCommand) in the ssh config, 6 and 7 can only be the command's and mssh adds nothing.
|
|
586
586
|
- Warning: by default mssh does not check host keys, so the password goes to whichever machine answers at the host's address. See [Host Key Checking](#host-key-checking).
|
|
587
|
-
-
|
|
588
|
-
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included.
|
|
587
|
+
- mssh never shows or stores the password: the `> mssh ...` line and the history file (`-hf`, default `~/.mssh_history`) list it as `-p -`, so running either again asks for it. Typed on mssh's own command line, though, it can be seen by other local users (in `ps`) and lands in your shell history. To keep it off the command line, `-p -` asks for it on the terminal (nothing is echoed; without a terminal, or without an answer, mssh stops before running anything), or set `MSSH_PASSWORD` in the environment, or `DEFAULT_PASSWORD` in a config file (plain text, so keep that file private). `-p` on the command line wins over `MSSH_PASSWORD`, which wins over `DEFAULT_PASSWORD`; neither of those two is listed in the `> mssh ...` line or the history, as a replay gets them again, and `--store_config_file` does not write `MSSH_PASSWORD` into the config.
|
|
588
|
+
- mssh does not show the passwords from your config file: `-h` and the autocomplete only say whether one is set, the `> mssh ...` line and the history leave them out, and the commands the TUI, `--debug` and `--copy_id` show have `***` in their place. Only `--generate_config_file` (and `--store_config_file` when it cannot write the file) print the config itself, passwords included. They reach `sshpass` and `ipmitool`, as a password typed on the command line does, through their environment (`sshpass -e`, `ipmitool -E` with `IPMI_PASSWORD` and `IPMITOOL_PASSWORD`), which other local users cannot read, not as arguments `ps` shows them. `redfishtool` has no such option: it gets its password as an argument, visible in `ps` while it runs.
|
|
589
589
|
|
|
590
590
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
591
591
|
- You can specify the identity file or folder to use for public key authentication. If a folder is specified, it will search for a key file inside the folder.
|
|
@@ -711,15 +711,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
711
711
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
712
712
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
713
713
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
714
|
-
-
|
|
714
|
+
- It is left out of the `> mssh ...` line and the history file (not even as `-p -` is for `-p`), and when it is given, so are `-iu`, `-ia`, `-im`, `-mpre` and `-irlt`: with the configured password they would make a login you did not give, tried on every BMC (each failed login counts towards the BMC locking the account). A replayed history line tries the configured logins, as `--ipmi` alone does; give the IPMI options again to use yours.
|
|
715
715
|
|
|
716
716
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
717
717
|
- Extra arguments for ipmitool (or redfishtool) in `--ipmi` mode, in one string, placed as they are before the command. `-ea` arguments only go to ssh / scp / rsync.
|
|
718
|
-
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -
|
|
718
|
+
- Ex: `mssh -M -ia='-I lanplus' bmc[1-4] 'power status'` runs `ipmitool -H <address> -U <user> -E -I lanplus power status`, with the password in its environment. Use `=`, as the value starts with `-`.
|
|
719
719
|
|
|
720
720
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
721
721
|
- How `--ipmi` reaches a host:
|
|
722
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
722
|
+
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -E [IPMI_ARGS] <command>` on this machine; `-E` reads the password from the environment mssh gives it.
|
|
723
723
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
724
724
|
- `ssh_ipmitool`: logs in to the host over ssh with the IPMI username and password (`-iu` / `-ip`, so `admin` / `admin` unless set) and runs `ipmitool <command>` there.
|
|
725
725
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -876,7 +876,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
876
876
|
|
|
877
877
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
878
878
|
- The file to store command history.
|
|
879
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
879
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
880
880
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
881
881
|
- A line records the command so that replaying it (the Ctrl-R picker, `mssh-complete`) runs it the same way: the hosts as typed and every option that changes what runs, where, or what is shown; a flag when it is on, an option with a value when the value is not the default (the config files' `DEFAULT_*`). `-T`, `-uk` (or `-k` with a folder), `--script` and `-s PATH` are recorded as the timeout, key file and options they chose, `--config_file` and `--host_file` with their absolute paths. Not recorded: `-ip` (and with it the other IPMI options, see `-ip`), and `--generate_config_file`, `--store_config_file` and `--add_control_master_config`, which do something besides the run. The `> mssh ...` line mssh prints at start lists the same options.
|
|
882
882
|
|
|
@@ -970,7 +970,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
970
970
|
|
|
971
971
|
Putting the command after `--` is no substitute for quotes: every word after the hosts is a command of its own, so `mssh web1 -- bash -c 'echo hi'` runs `bash`, `-c` and `echo hi` one after another (when each word is a single word, as in `mssh web1 -- ls -la`, mssh asks whether to join them).
|
|
972
972
|
|
|
973
|
-
Below is a sample help message output from multiSSH3 6.
|
|
973
|
+
Below is a sample help message output from multiSSH3 6.33 @ 2026-10-14 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
974
974
|
|
|
975
975
|
```bash
|
|
976
976
|
$ mssh -h
|
|
@@ -996,7 +996,7 @@ options:
|
|
|
996
996
|
-u, --username USERNAME
|
|
997
997
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
998
998
|
-p, --password PASSWORD
|
|
999
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
999
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
1000
1000
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
1001
1001
|
The identity file to use to connect to the hosts. Implies --use_key. Specify a folder for program to search for a key. Use option without value to use ~/.ssh/ (default: None)
|
|
1002
1002
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1370,6 +1370,8 @@ __DEBUG_MODE = False
|
|
|
1370
1370
|
|
|
1371
1371
|
> `_DEFAULT_NO_START` is somewhat analogous to "demo mode" where mssh will return Host objects without actually allocating and starting the execution threads. Although they still can be started using `start_run_on_hosts()` but you should really be looking for `return_unfinished` instead for asynchronicity.
|
|
1372
1372
|
|
|
1373
|
+
> `run_command_on_hosts` reads `_DEFAULT_CALLED`, `_DEFAULT_RETURN_UNFINISHED`, `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` and `_DEFAULT_NO_START` each time it is called, so setting them after `import multiSSH3`, or in a file given with `--config_file`, works. The `mssh` command always starts its hosts and waits for them: of these four, only `_DEFAULT_UPDATE_UNREACHABLE_HOSTS` changes what it does.
|
|
1374
|
+
|
|
1373
1375
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1374
1376
|
|
|
1375
1377
|
> `ERROR_MESSAGES_TO_IGNORE` lists regexes for ssh's own notices, which mssh leaves out of each host's stderr (also in `--json` and `--greppable` output). Each regex is searched anywhere in every stderr line, so anchor yours with `^` and `$` to match whole lines (in the JSON config file, write a regex backslash as `\\`). The defaults are anchored to the lines OpenSSH prints, so a remote program's error that uses the same words, such as curl's `Recv failure: Connection reset by peer`, is kept. Connection resets are not hidden: `kex_exchange_identification: read: Connection reset by peer` is how sshd's `MaxStartups` turns away connections opened at once. Config files that `--store_config_file` or `--generate_config_file` wrote before 6.20 hold a copy of the old, unanchored defaults; mssh ignores such an unchanged copy and uses the current defaults.
|
|
@@ -16,6 +16,7 @@ tests/conftest.py
|
|
|
16
16
|
tests/test_cli_branches.py
|
|
17
17
|
tests/test_cli_option_words.py
|
|
18
18
|
tests/test_cli_processing.py
|
|
19
|
+
tests/test_closed_output.py
|
|
19
20
|
tests/test_color_helpers.py
|
|
20
21
|
tests/test_command_terminal.py
|
|
21
22
|
tests/test_compact_hostnames.py
|
|
@@ -36,6 +37,7 @@ tests/test_complete_password_spellings.py
|
|
|
36
37
|
tests/test_complete_picker.py
|
|
37
38
|
tests/test_complete_probe.py
|
|
38
39
|
tests/test_complete_shells.py
|
|
40
|
+
tests/test_complete_start.py
|
|
39
41
|
tests/test_complete_store.py
|
|
40
42
|
tests/test_complete_suggest.py
|
|
41
43
|
tests/test_complete_terminal.py
|
|
@@ -65,11 +67,14 @@ tests/test_key_path_home.py
|
|
|
65
67
|
tests/test_login_drop_retry.py
|
|
66
68
|
tests/test_main_lifecycle.py
|
|
67
69
|
tests/test_narrow_terminal.py
|
|
70
|
+
tests/test_no_hosts.py
|
|
68
71
|
tests/test_option_no_effect.py
|
|
69
72
|
tests/test_options_after_command.py
|
|
70
73
|
tests/test_output_merge.py
|
|
71
74
|
tests/test_output_robustness.py
|
|
72
75
|
tests/test_packaging.py
|
|
76
|
+
tests/test_password_handling.py
|
|
77
|
+
tests/test_passwords_out_of_ps.py
|
|
73
78
|
tests/test_run_command.py
|
|
74
79
|
tests/test_run_command_branches.py
|
|
75
80
|
tests/test_run_command_characterization.py
|
|
@@ -87,6 +92,8 @@ tests/test_stopped_commands.py
|
|
|
87
92
|
tests/test_stream_reader.py
|
|
88
93
|
tests/test_tui_ssh_notices.py
|
|
89
94
|
tests/test_unavailable_hosts.py
|
|
95
|
+
tests/test_underscore_settings.py
|
|
96
|
+
tests/test_wide_wrap.py
|
|
90
97
|
tests/vt_grid.py
|
|
91
98
|
tests/data/run_command_golden.json
|
|
92
99
|
tests/shells/Dockerfile.bash5.1
|