multiSSH3 6.32__tar.gz → 6.34__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.34}/PKG-INFO +16 -12
- {multissh3-6.32 → multissh3-6.34}/README.md +15 -11
- {multissh3-6.32 → multissh3-6.34}/mssh_complete.py +116 -10
- {multissh3-6.32 → multissh3-6.34/multiSSH3.egg-info}/PKG-INFO +16 -12
- {multissh3-6.32 → multissh3-6.34}/multiSSH3.egg-info/SOURCES.txt +7 -0
- {multissh3-6.32 → multissh3-6.34}/multiSSH3.py +314 -47
- {multissh3-6.32 → multissh3-6.34}/tests/complete_shell_harness.py +18 -2
- {multissh3-6.32 → multissh3-6.34}/tests/conftest.py +14 -0
- {multissh3-6.32 → multissh3-6.34}/tests/data/run_command_golden.json +189 -34
- {multissh3-6.32 → multissh3-6.34}/tests/test_cli_branches.py +1 -1
- {multissh3-6.32 → multissh3-6.34}/tests/test_cli_processing.py +2 -1
- multissh3-6.34/tests/test_closed_output.py +60 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_diagnose.py +4 -3
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_engine.py +1 -1
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_keys.py +84 -8
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_picker.py +45 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_shells.py +41 -2
- multissh3-6.34/tests/test_complete_start.py +102 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_config_cli.py +2 -2
- {multissh3-6.32 → multissh3-6.34}/tests/test_config_values.py +7 -5
- {multissh3-6.32 → multissh3-6.34}/tests/test_copy_id.py +2 -2
- {multissh3-6.32 → multissh3-6.34}/tests/test_curses_event_loop.py +94 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_expand_hostnames.py +15 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_history_replay.py +6 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_identities_only.py +1 -1
- {multissh3-6.32 → multissh3-6.34}/tests/test_ipmi_logins.py +18 -7
- {multissh3-6.32 → multissh3-6.34}/tests/test_main_lifecycle.py +2 -1
- multissh3-6.34/tests/test_no_hosts.py +46 -0
- multissh3-6.34/tests/test_password_handling.py +153 -0
- multissh3-6.34/tests/test_passwords_out_of_ps.py +109 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_command_branches.py +5 -3
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_command_characterization.py +14 -8
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_on_hosts_modes.py +7 -4
- {multissh3-6.32 → multissh3-6.34}/tests/test_runtime_branch_matrix.py +3 -2
- {multissh3-6.32 → multissh3-6.34}/tests/test_sshpass_exit.py +1 -1
- multissh3-6.34/tests/test_stopped_commands.py +287 -0
- multissh3-6.34/tests/test_underscore_settings.py +83 -0
- multissh3-6.34/tests/test_wide_wrap.py +78 -0
- multissh3-6.32/tests/test_stopped_commands.py +0 -123
- {multissh3-6.32 → multissh3-6.34}/LICENSE +0 -0
- {multissh3-6.32 → multissh3-6.34}/MANIFEST.in +0 -0
- {multissh3-6.32 → multissh3-6.34}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-6.32 → multissh3-6.34}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-6.32 → multissh3-6.34}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-6.32 → multissh3-6.34}/pytest.ini +0 -0
- {multissh3-6.32 → multissh3-6.34}/setup.cfg +0 -0
- {multissh3-6.32 → multissh3-6.34}/setup.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/bench_complete.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.bash5.1 +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.bash5.3 +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.centos7 +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.current +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.legacy +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/Dockerfile.modern +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/shells/run_matrix.sh +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_cli_option_words.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_color_helpers.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_command_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_compact_hostnames.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_blesh.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_cli.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_context.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_editor.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_eval.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_hoststate.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_index.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_lex.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_mssh_helpers.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_password_spellings.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_probe.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_store.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_suggest.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_untrusted.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_complete_zsh_options.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_config_validate.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_control_master_config.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_curses_branches.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_curses_tui.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_curses_wide_chars.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_file_trust.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_harness_smoke.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_helpers_extra.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_host.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_host_validity.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_hosts_file.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_ipmi_lockout_wait.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_key_path_home.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_login_drop_retry.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_narrow_terminal.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_option_no_effect.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_options_after_command.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_output_merge.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_output_robustness.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_packaging.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_command.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_command_exit.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_run_on_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_runtime_dir.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_smoke_optional.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_ssh_error_text.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_ssh_timeouts.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_start_run_on_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_stream_reader.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_tui_ssh_notices.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/tests/test_unavailable_hosts.py +0 -0
- {multissh3-6.32 → multissh3-6.34}/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.34
|
|
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
|
|
@@ -336,6 +336,8 @@ When hostname need to be resolved, mssh will check in the following order:
|
|
|
336
336
|
|
|
337
337
|
An alias's value is split into hosts as the hosts argument is (`,`, spaces, `;`, ...). An alias with an empty value (`eu=''`) stands for no hosts.
|
|
338
338
|
|
|
339
|
+
A member can name its user: with `dbs="postgres@db1,db2"`, mssh logs in to db1 as postgres, and `-u` changes only db2's user. A user typed with the alias replaces it: `mssh root@dbs` logs in to both as root, as a user on the command line wins over ssh config's `User`.
|
|
340
|
+
|
|
339
341
|
Inside its own expansion, directly or through other aliases, an alias's name is not expanded again but taken as a host name, as bash does with aliases: `web="web,web-b"` runs on the host `web` and on `web-b`. When no host has that name, mssh reports the loop and runs on the rest: `Error: alias loop through 'web' (web -> app -> web): 'web' is not a valid hostname or IP address!`
|
|
340
342
|
|
|
341
343
|
|
|
@@ -490,7 +492,7 @@ mssh --completion uninstall # remove it again
|
|
|
490
492
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
491
493
|
```
|
|
492
494
|
|
|
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.
|
|
495
|
+
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
496
|
|
|
495
497
|
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
498
|
|
|
@@ -551,7 +553,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
551
553
|
| Environment variable | Effect |
|
|
552
554
|
| --- | --- |
|
|
553
555
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
554
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
556
|
+
| `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
557
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
556
558
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
557
559
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -584,8 +586,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
584
586
|
- 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
587
|
- `-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
588
|
- 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.
|
|
589
|
+
- 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.
|
|
590
|
+
- 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
591
|
|
|
590
592
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
591
593
|
- 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 +713,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
711
713
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
712
714
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
713
715
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
714
|
-
-
|
|
716
|
+
- 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
717
|
|
|
716
718
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
717
719
|
- 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> -
|
|
720
|
+
- 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
721
|
|
|
720
722
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
721
723
|
- How `--ipmi` reaches a host:
|
|
722
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
724
|
+
- `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
725
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
724
726
|
- `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
727
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -876,7 +878,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
876
878
|
|
|
877
879
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
878
880
|
- The file to store command history.
|
|
879
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
881
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
880
882
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
881
883
|
- 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
884
|
|
|
@@ -970,7 +972,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
970
972
|
|
|
971
973
|
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
974
|
|
|
973
|
-
Below is a sample help message output from multiSSH3 6.
|
|
975
|
+
Below is a sample help message output from multiSSH3 6.34 @ 2026-10-16 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
974
976
|
|
|
975
977
|
```bash
|
|
976
978
|
$ mssh -h
|
|
@@ -996,7 +998,7 @@ options:
|
|
|
996
998
|
-u, --username USERNAME
|
|
997
999
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
998
1000
|
-p, --password PASSWORD
|
|
999
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
1001
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
1000
1002
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
1001
1003
|
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
1004
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1370,6 +1372,8 @@ __DEBUG_MODE = False
|
|
|
1370
1372
|
|
|
1371
1373
|
> `_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
1374
|
|
|
1375
|
+
> `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.
|
|
1376
|
+
|
|
1373
1377
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1374
1378
|
|
|
1375
1379
|
> `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
|
|
@@ -310,6 +310,8 @@ When hostname need to be resolved, mssh will check in the following order:
|
|
|
310
310
|
|
|
311
311
|
An alias's value is split into hosts as the hosts argument is (`,`, spaces, `;`, ...). An alias with an empty value (`eu=''`) stands for no hosts.
|
|
312
312
|
|
|
313
|
+
A member can name its user: with `dbs="postgres@db1,db2"`, mssh logs in to db1 as postgres, and `-u` changes only db2's user. A user typed with the alias replaces it: `mssh root@dbs` logs in to both as root, as a user on the command line wins over ssh config's `User`.
|
|
314
|
+
|
|
313
315
|
Inside its own expansion, directly or through other aliases, an alias's name is not expanded again but taken as a host name, as bash does with aliases: `web="web,web-b"` runs on the host `web` and on `web-b`. When no host has that name, mssh reports the loop and runs on the rest: `Error: alias loop through 'web' (web -> app -> web): 'web' is not a valid hostname or IP address!`
|
|
314
316
|
|
|
315
317
|
|
|
@@ -464,7 +466,7 @@ mssh --completion uninstall # remove it again
|
|
|
464
466
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
465
467
|
```
|
|
466
468
|
|
|
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.
|
|
469
|
+
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
470
|
|
|
469
471
|
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
472
|
|
|
@@ -525,7 +527,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
525
527
|
| Environment variable | Effect |
|
|
526
528
|
| --- | --- |
|
|
527
529
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
528
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
530
|
+
| `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
531
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
530
532
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
531
533
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -558,8 +560,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
558
560
|
- 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
561
|
- `-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
562
|
- 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.
|
|
563
|
+
- 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.
|
|
564
|
+
- 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
565
|
|
|
564
566
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
565
567
|
- 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 +687,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
685
687
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
686
688
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
687
689
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
688
|
-
-
|
|
690
|
+
- 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
691
|
|
|
690
692
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
691
693
|
- 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> -
|
|
694
|
+
- 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
695
|
|
|
694
696
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
695
697
|
- How `--ipmi` reaches a host:
|
|
696
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
698
|
+
- `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
699
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
698
700
|
- `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
701
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -850,7 +852,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
850
852
|
|
|
851
853
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
852
854
|
- The file to store command history.
|
|
853
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
855
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
854
856
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
855
857
|
- 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
858
|
|
|
@@ -944,7 +946,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
944
946
|
|
|
945
947
|
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
948
|
|
|
947
|
-
Below is a sample help message output from multiSSH3 6.
|
|
949
|
+
Below is a sample help message output from multiSSH3 6.34 @ 2026-10-16 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
948
950
|
|
|
949
951
|
```bash
|
|
950
952
|
$ mssh -h
|
|
@@ -970,7 +972,7 @@ options:
|
|
|
970
972
|
-u, --username USERNAME
|
|
971
973
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
972
974
|
-p, --password PASSWORD
|
|
973
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
975
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
974
976
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
975
977
|
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
978
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1344,6 +1346,8 @@ __DEBUG_MODE = False
|
|
|
1344
1346
|
|
|
1345
1347
|
> `_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
1348
|
|
|
1349
|
+
> `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.
|
|
1350
|
+
|
|
1347
1351
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1348
1352
|
|
|
1349
1353
|
> `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.7'
|
|
20
20
|
__version__ = version
|
|
21
21
|
PROTOCOL = 'MSSHC1'
|
|
22
22
|
MSSH_NAMES = ('mssh', 'mssh3', 'multissh', 'multissh3', 'multiSSH3')
|
|
@@ -2577,12 +2577,9 @@ def _run_name(host, typed_user, line_user, own_user=''):
|
|
|
2577
2577
|
The name mssh gives a host in this run: what it records a failure under in unavailable_hosts.csv
|
|
2578
2578
|
and looks up to skip the host. The user typed with the host, else -u (line_user), else none.
|
|
2579
2579
|
own_user: the user an alias member is written with. -u does not replace it, a user typed with the
|
|
2580
|
-
alias
|
|
2580
|
+
alias does (for root@dbs with dbs=postgres@db1 mssh runs root@db1).
|
|
2581
2581
|
'''
|
|
2582
|
-
|
|
2583
|
-
host = own_user + '@' + host
|
|
2584
|
-
line_user = ''
|
|
2585
|
-
user = typed_user or line_user
|
|
2582
|
+
user = typed_user or own_user or line_user
|
|
2586
2583
|
return user + '@' + host if user else host
|
|
2587
2584
|
|
|
2588
2585
|
# characters that can start an expansion the shell makes before mssh sees the word
|
|
@@ -5769,6 +5766,42 @@ class LineEditor(object):
|
|
|
5769
5766
|
self.draw(term, prompt, style)
|
|
5770
5767
|
|
|
5771
5768
|
#%% ------------ Shell glue ----------------
|
|
5769
|
+
# zsh and fish run the picker through this POSIX sh: sh -c START_SCRIPT sh SECONDS PICKER-COMMAND...
|
|
5770
|
+
# The picker creates MSSH_COMPLETE_CLAIM just before it takes the terminal (_claim_terminal). It is
|
|
5771
|
+
# given SECONDS to do so: then, or on Ctrl-C while it starts, the script creates it first and stops the
|
|
5772
|
+
# picker, which has not touched the terminal (a hung file system can keep it from starting, deaf to
|
|
5773
|
+
# Ctrl-C). mkdir succeeds for one of the two only. Exit status: the picker's, 124 when it was too slow,
|
|
5774
|
+
# 130 on Ctrl-C. The picker runs in the background of this sh, in the shell's process group: it can
|
|
5775
|
+
# read the terminal. Its answer goes through a file: a process it leaves behind when stopped cannot
|
|
5776
|
+
# keep the shell's command substitution open. bash waits for its "ready" line instead (_mssh_complete_start).
|
|
5777
|
+
START_SCRIPT = r"""limit=$1
|
|
5778
|
+
shift
|
|
5779
|
+
dir=$(mktemp -d 2>/dev/null) || exec "$@"
|
|
5780
|
+
exec 3<&0
|
|
5781
|
+
MSSH_COMPLETE_CLAIM=$dir/claim "$@" <&3 3<&- >"$dir/answer" &
|
|
5782
|
+
pid=$!
|
|
5783
|
+
exec 3<&-
|
|
5784
|
+
stop() {
|
|
5785
|
+
mkdir "$dir/claim" 2>/dev/null && : > "$dir/$1" && kill -9 "$pid"
|
|
5786
|
+
}
|
|
5787
|
+
# the sleeper: nothing of it may keep the shell's command substitution open, and Ctrl-C is the
|
|
5788
|
+
# trap's (bash does not make a background subshell ignore it, as dash and busybox do)
|
|
5789
|
+
{ trap '' INT; sleep "$limit"; stop late; } </dev/null >/dev/null 2>&1 &
|
|
5790
|
+
sleeper=$!
|
|
5791
|
+
trap 'stop stopped' INT
|
|
5792
|
+
while :; do
|
|
5793
|
+
wait "$pid"
|
|
5794
|
+
status=$?
|
|
5795
|
+
kill -0 "$pid" 2>/dev/null || break
|
|
5796
|
+
done
|
|
5797
|
+
kill "$sleeper" 2>/dev/null
|
|
5798
|
+
[ -e "$dir/stopped" ] && status=130
|
|
5799
|
+
[ -e "$dir/late" ] && status=124
|
|
5800
|
+
cat "$dir/answer" 2>/dev/null
|
|
5801
|
+
rm -rf "$dir"
|
|
5802
|
+
exit "$status"
|
|
5803
|
+
"""
|
|
5804
|
+
|
|
5772
5805
|
GLUE_MARK = 'MSSH_COMPLETE_GLUE'
|
|
5773
5806
|
|
|
5774
5807
|
BASH_GLUE = r'''# MSSH_COMPLETE_GLUE @VERSION@ bash: autocomplete for mssh (multiSSH3), protocol MSSHC1
|
|
@@ -6489,6 +6522,18 @@ _mssh_complete_engine() {
|
|
|
6489
6522
|
@ENGINE@ "$@"
|
|
6490
6523
|
}
|
|
6491
6524
|
|
|
6525
|
+
typeset -g _mssh_complete_start_script=@START@
|
|
6526
|
+
|
|
6527
|
+
_mssh_complete_start_pick() {
|
|
6528
|
+
# the picker, reading the request on stdin: MSSH_COMPLETE_START_TIMEOUT seconds (2) at most to take
|
|
6529
|
+
# the terminal, then as long as the operator takes. 124 when too slow, 130 on Ctrl-C while it
|
|
6530
|
+
# starts: see START_SCRIPT in mssh_complete.py
|
|
6531
|
+
emulate -L zsh
|
|
6532
|
+
local limit=${MSSH_COMPLETE_START_TIMEOUT:-2}
|
|
6533
|
+
[[ $limit == (<->|<->.<->|.<->) ]] || limit=2
|
|
6534
|
+
command sh -c "$_mssh_complete_start_script" sh "$limit" @ENGINE@ pick
|
|
6535
|
+
}
|
|
6536
|
+
|
|
6492
6537
|
_mssh_complete_keep_terminal() {
|
|
6493
6538
|
# after each `exec {fd}< <(...)`: before zsh 5.8 the process substitution takes the terminal from the
|
|
6494
6539
|
# shell (Ctrl-C then goes to it, and the shell's next reads can fail with "error on TTY read"); a
|
|
@@ -6517,7 +6562,10 @@ _mssh_complete_ctrl_r() {
|
|
|
6517
6562
|
emulate -L zsh
|
|
6518
6563
|
local resp line text= cursor= st
|
|
6519
6564
|
if _mssh_complete_is_mssh "$BUFFER"; then
|
|
6520
|
-
|
|
6565
|
+
# Ctrl-C while the picker starts stops it (130), and keeps the line: without a trap of its own
|
|
6566
|
+
# (local: emulate -L), zsh would end the widget and drop the line
|
|
6567
|
+
trap : INT
|
|
6568
|
+
resp=$(_mssh_complete_request 'pick=1 nul=0' "$LBUFFER" "$RBUFFER" | _mssh_complete_start_pick 2>/dev/null)
|
|
6521
6569
|
st=$?
|
|
6522
6570
|
if (( st == 0 )) && [[ $resp == MSSHC1$'\n'*$'\n'E ]]; then
|
|
6523
6571
|
for line in "${(@f)resp}"; do
|
|
@@ -6538,6 +6586,8 @@ _mssh_complete_ctrl_r() {
|
|
|
6538
6586
|
[[ -n ${_mssh_complete_warn_reason-} ]] && zle -M -- "$_mssh_complete_warn_reason"
|
|
6539
6587
|
return 0
|
|
6540
6588
|
fi
|
|
6589
|
+
# Ctrl-C while it started: the line stays as it is. Too slow (124): what Ctrl-R did before
|
|
6590
|
+
(( st == 130 )) && return 0
|
|
6541
6591
|
fi
|
|
6542
6592
|
[[ -n $_mssh_complete_previous ]] && zle $_mssh_complete_previous
|
|
6543
6593
|
return 0
|
|
@@ -7064,6 +7114,7 @@ switch "$FISH_VERSION"
|
|
|
7064
7114
|
if not set -q __mssh_complete_keys
|
|
7065
7115
|
set -g __mssh_complete_keys 1
|
|
7066
7116
|
''' + _fish_nested(_FISH_QUERY, 3) + r'''
|
|
7117
|
+
set -g __mssh_complete_start_script @START@
|
|
7067
7118
|
function __mssh_complete_is_mssh
|
|
7068
7119
|
string match -qr '^\s*(\S*/)?(mssh|mssh3|multissh|multissh3|multiSSH3)\s' -- "$argv[1]"
|
|
7069
7120
|
end
|
|
@@ -7076,10 +7127,14 @@ switch "$FISH_VERSION"
|
|
|
7076
7127
|
set -l keep 1000
|
|
7077
7128
|
set -q MSSH_COMPLETE_SHELL_HISTORY; and set keep $MSSH_COMPLETE_SHELL_HISTORY
|
|
7078
7129
|
# the history builtin: the operator's history function or alias (one showing times) would change the lines
|
|
7130
|
+
# MSSH_COMPLETE_START_TIMEOUT seconds (2) at most for the picker to take the terminal, then as
|
|
7131
|
+
# long as the operator takes: 124 when too slow, 130 on Ctrl-C while it starts (START_SCRIPT)
|
|
7132
|
+
set -l limit 2
|
|
7133
|
+
string match -qr '^(\d+|\d+\.\d*|\.\d+)$' -- "$MSSH_COMPLETE_START_TIMEOUT"; and set limit $MSSH_COMPLETE_START_TIMEOUT
|
|
7079
7134
|
set -l lines (begin
|
|
7080
7135
|
command printf '%s\0' MSSHC1 fish $FISH_VERSION "pick=1 nul=0 term=$TERM" "$before" "$after" ''
|
|
7081
7136
|
builtin history search -n $keep 2>/dev/null
|
|
7082
|
-
end | @ENGINE@ pick 2>/dev/null)
|
|
7137
|
+
end | command sh -c $__mssh_complete_start_script sh $limit @ENGINE@ pick 2>/dev/null)
|
|
7083
7138
|
set -l st $status
|
|
7084
7139
|
if test $st -eq 0; and test (count $lines) -ge 3; and test "$lines[1]" = MSSHC1; and test "$lines[-1]" = E
|
|
7085
7140
|
for line in $lines[2..-2]
|
|
@@ -7090,7 +7145,8 @@ switch "$FISH_VERSION"
|
|
|
7090
7145
|
end
|
|
7091
7146
|
end
|
|
7092
7147
|
commandline -f repaint
|
|
7093
|
-
|
|
7148
|
+
# Ctrl-C while it started: the line stays as it is. Too slow (124): what Ctrl-R did before
|
|
7149
|
+
test $st -le 1; or test $st -eq 130; and return
|
|
7094
7150
|
end
|
|
7095
7151
|
set -l previous __mssh_complete_previous_$mode
|
|
7096
7152
|
for command in $$previous
|
|
@@ -7213,6 +7269,7 @@ def render_glue(shell, command=None):
|
|
|
7213
7269
|
command = engine_command() if command is None else command
|
|
7214
7270
|
quote = _fish_quote if shell.startswith('fish') else shlex.quote
|
|
7215
7271
|
text = _GLUES[shell].replace('@VERSION@', version).replace('@ENGINE@', ' '.join(quote(word) for word in command))
|
|
7272
|
+
text = text.replace('@START@', quote(START_SCRIPT))
|
|
7216
7273
|
return _zsh_guard(text) if shell == 'zsh' else text
|
|
7217
7274
|
|
|
7218
7275
|
#%% ------------ Printing to a reader that may go ----------------
|
|
@@ -7826,8 +7883,38 @@ def uninstall(shell, home=None, environ=None):
|
|
|
7826
7883
|
return 1, messages + list(error.args)
|
|
7827
7884
|
if len(messages) == (1 if paths.get('note') else 0):
|
|
7828
7885
|
messages.append('nothing to remove')
|
|
7886
|
+
if shell == 'zsh':
|
|
7887
|
+
for dump in _zsh_dumps_naming_mssh(home, environ):
|
|
7888
|
+
messages.append("zsh's completion dump {0} still maps mssh to _mssh, which is gone: "
|
|
7889
|
+
"remove it (rm {0}) and zsh makes a new one".format(dump))
|
|
7829
7890
|
return 0, messages
|
|
7830
7891
|
|
|
7892
|
+
def _zsh_dumps_naming_mssh(home, environ):
|
|
7893
|
+
'''
|
|
7894
|
+
The zsh completion dumps (compinit's .zcompdump, oh-my-zsh's .zcompdump-HOST-VERSION) that map mssh
|
|
7895
|
+
to _mssh. A dump written while the glue was loaded keeps that after it is removed, and zsh then
|
|
7896
|
+
answers TAB with "command not found: _mssh". They are zsh's: they are named, not changed.
|
|
7897
|
+
'''
|
|
7898
|
+
candidates = [environ.get('ZSH_COMPDUMP')]
|
|
7899
|
+
for directory in (environ.get('ZDOTDIR'), home):
|
|
7900
|
+
try:
|
|
7901
|
+
names = sorted(os.listdir(directory)) if directory else []
|
|
7902
|
+
except OSError:
|
|
7903
|
+
names = []
|
|
7904
|
+
candidates.extend(os.path.join(directory, name) for name in names
|
|
7905
|
+
if name.startswith('.zcompdump') and not name.endswith('.zwc'))
|
|
7906
|
+
found = []
|
|
7907
|
+
for path in candidates:
|
|
7908
|
+
if not path or path in found:
|
|
7909
|
+
continue
|
|
7910
|
+
try:
|
|
7911
|
+
with open(path, encoding='utf-8', errors='replace') as dump:
|
|
7912
|
+
if "'_mssh'" in dump.read(4 << 20):
|
|
7913
|
+
found.append(path)
|
|
7914
|
+
except OSError:
|
|
7915
|
+
pass
|
|
7916
|
+
return found
|
|
7917
|
+
|
|
7831
7918
|
def prepare_index():
|
|
7832
7919
|
'''
|
|
7833
7920
|
Build the index now, for `mssh --completion install`: the first TAB in a new shell then answers
|
|
@@ -8235,6 +8322,25 @@ def _ready():
|
|
|
8235
8322
|
except OSError:
|
|
8236
8323
|
return False
|
|
8237
8324
|
|
|
8325
|
+
def _claim_terminal():
|
|
8326
|
+
'''
|
|
8327
|
+
Create the directory MSSH_COMPLETE_CLAIM names (zsh and fish set it), just before taking the terminal.
|
|
8328
|
+
|
|
8329
|
+
The shell waits only so long (MSSH_COMPLETE_START_TIMEOUT) for the picker to take it, and creates
|
|
8330
|
+
that directory itself when it stops waiting (also on Ctrl-C): mkdir succeeds for one of the two
|
|
8331
|
+
only, so a picker slow to start never draws after the shell went on. True when the terminal is
|
|
8332
|
+
ours (also without MSSH_COMPLETE_CLAIM, as bash runs it).
|
|
8333
|
+
'''
|
|
8334
|
+
path = os.environ.get('MSSH_COMPLETE_CLAIM')
|
|
8335
|
+
if not path:
|
|
8336
|
+
return True
|
|
8337
|
+
try:
|
|
8338
|
+
os.mkdir(path, 0o700)
|
|
8339
|
+
return True
|
|
8340
|
+
except OSError as e:
|
|
8341
|
+
_debug('pick: the shell went on ({!r}): leaving the terminal alone'.format(e))
|
|
8342
|
+
return False
|
|
8343
|
+
|
|
8238
8344
|
def _cmd_pick():
|
|
8239
8345
|
'''
|
|
8240
8346
|
mssh-complete pick: the Ctrl-R picker. Reads a request on stdin, draws on /dev/tty, prints the new
|
|
@@ -8261,7 +8367,7 @@ def _cmd_pick():
|
|
|
8261
8367
|
line = before = None
|
|
8262
8368
|
if prompt is not None:
|
|
8263
8369
|
line, before = prompt + request.before + request.after, prompt + request.before
|
|
8264
|
-
if request.flags.get('ready') == '1' and not _ready():
|
|
8370
|
+
if not _claim_terminal() or (request.flags.get('ready') == '1' and not _ready()):
|
|
8265
8371
|
return 2
|
|
8266
8372
|
with Terminal() as term:
|
|
8267
8373
|
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.34
|
|
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
|
|
@@ -336,6 +336,8 @@ When hostname need to be resolved, mssh will check in the following order:
|
|
|
336
336
|
|
|
337
337
|
An alias's value is split into hosts as the hosts argument is (`,`, spaces, `;`, ...). An alias with an empty value (`eu=''`) stands for no hosts.
|
|
338
338
|
|
|
339
|
+
A member can name its user: with `dbs="postgres@db1,db2"`, mssh logs in to db1 as postgres, and `-u` changes only db2's user. A user typed with the alias replaces it: `mssh root@dbs` logs in to both as root, as a user on the command line wins over ssh config's `User`.
|
|
340
|
+
|
|
339
341
|
Inside its own expansion, directly or through other aliases, an alias's name is not expanded again but taken as a host name, as bash does with aliases: `web="web,web-b"` runs on the host `web` and on `web-b`. When no host has that name, mssh reports the loop and runs on the rest: `Error: alias loop through 'web' (web -> app -> web): 'web' is not a valid hostname or IP address!`
|
|
340
342
|
|
|
341
343
|
|
|
@@ -490,7 +492,7 @@ mssh --completion uninstall # remove it again
|
|
|
490
492
|
mssh --completion bash # or print the script (bash, zsh or fish)
|
|
491
493
|
```
|
|
492
494
|
|
|
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.
|
|
495
|
+
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
496
|
|
|
495
497
|
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
498
|
|
|
@@ -551,7 +553,7 @@ Hosts are checked in the background by `mssh-complete probe`: DNS, `ssh -G` (whi
|
|
|
551
553
|
| Environment variable | Effect |
|
|
552
554
|
| --- | --- |
|
|
553
555
|
| `MSSH_COMPLETE_TIMEOUT` | Seconds the shell waits for an answer (default 0.3) |
|
|
554
|
-
| `MSSH_COMPLETE_START_TIMEOUT` |
|
|
556
|
+
| `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
557
|
| `MSSH_COMPLETE_GHOST_TIMEOUT` | ble.sh only: milliseconds a grey suggestion may take (default 300) |
|
|
556
558
|
| `MSSH_COMPLETE_SHELL_HISTORY` | Lines of shell history sent along (default 1000) |
|
|
557
559
|
| `MSSH_COMPLETE_EDITOR` | `1` turns on the plain-bash mssh line editor (`install bash editor` sets it) |
|
|
@@ -584,8 +586,8 @@ mssh -q -- web1 grep -r TODO /srv
|
|
|
584
586
|
- 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
587
|
- `-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
588
|
- 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.
|
|
589
|
+
- 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.
|
|
590
|
+
- 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
591
|
|
|
590
592
|
### `-k, --key, --identity [KEY]` | _`DEFAULT_IDENTITY_FILE`_
|
|
591
593
|
- 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 +713,15 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
711
713
|
- The password ipmitool (or redfishtool) logs in to the hosts' BMCs with, in `--ipmi` mode.
|
|
712
714
|
- Defaults to `admin`. It does not fall back to `-p` / `DEFAULT_PASSWORD`: see the note under `-M, --ipmi`.
|
|
713
715
|
- With `-im ssh_ipmitool` it is the ssh password instead (sent with sshpass).
|
|
714
|
-
-
|
|
716
|
+
- 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
717
|
|
|
716
718
|
### `-ia, --ipmi_args IPMI_ARGS` | _`DEFAULT_IPMI_ARGS`_
|
|
717
719
|
- 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> -
|
|
720
|
+
- 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
721
|
|
|
720
722
|
### `-im, --ipmi_method IPMI_METHOD` | _`DEFAULT_IPMI_METHOD`_
|
|
721
723
|
- How `--ipmi` reaches a host:
|
|
722
|
-
- `ipmitool` (default): runs `ipmitool -H <address> -U <user> -
|
|
724
|
+
- `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
725
|
- `redfish`: runs `redfishtool -S Always -a -r <address> -u <user> -p <password> [IPMI_ARGS] <command>` on this machine (`Systems` without a command).
|
|
724
726
|
- `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
727
|
- Any other value fails with `IPMI method ... not supported!`.
|
|
@@ -876,7 +878,7 @@ mssh -f ./data/ allServers /tmp/data/
|
|
|
876
878
|
|
|
877
879
|
### `-hf, --history_file HISTORY_FILE` | _`DEFAULT_HISTORY_FILE`_
|
|
878
880
|
- The file to store command history.
|
|
879
|
-
- By default, mssh store command history in `~/.mssh_history
|
|
881
|
+
- By default, mssh store command history in `~/.mssh_history`, readable by its owner only. Passwords are not stored (see `-p`).
|
|
880
882
|
- The history file is a TSV ( tab separated values ) file with each line containing: timestamp, mssh_path, options, hosts, commands.
|
|
881
883
|
- 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
884
|
|
|
@@ -970,7 +972,7 @@ Option names count in full only: `--user` is not `--username` and `-c` is not `-
|
|
|
970
972
|
|
|
971
973
|
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
974
|
|
|
973
|
-
Below is a sample help message output from multiSSH3 6.
|
|
975
|
+
Below is a sample help message output from multiSSH3 6.34 @ 2026-10-16 (no config file, 120 columns; the lines after the options list the programs found on that machine)
|
|
974
976
|
|
|
975
977
|
```bash
|
|
976
978
|
$ mssh -h
|
|
@@ -996,7 +998,7 @@ options:
|
|
|
996
998
|
-u, --username USERNAME
|
|
997
999
|
The general username to use to connect to the hosts via ssh. Will get overwrote by individual username@host if specified. (default: None)
|
|
998
1000
|
-p, --password PASSWORD
|
|
999
|
-
The password to use to connect to the hosts via ssh, (default: none)
|
|
1001
|
+
The password to use to connect to the hosts via ssh, "-p -" to be asked for it, or set MSSH_PASSWORD. (default: none)
|
|
1000
1002
|
-k, --identity_file, --key, --identity [IDENTITY_FILE]
|
|
1001
1003
|
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
1004
|
-uk, --use_key Attempt to use public key file to connect to the hosts. (default: False)
|
|
@@ -1370,6 +1372,8 @@ __DEBUG_MODE = False
|
|
|
1370
1372
|
|
|
1371
1373
|
> `_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
1374
|
|
|
1375
|
+
> `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.
|
|
1376
|
+
|
|
1373
1377
|
> `_etc_hosts` is a custom dict to use instead of reading /etc/hosts file for hostname resolution.
|
|
1374
1378
|
|
|
1375
1379
|
> `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.
|