diff --git a/README.md b/README.md index 97f8ba9258e6972d1f26a947ab3845f544f50c24..49e7beb7acf15fdf966ad12d635df2931f11c88c 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,12 @@ -# MULTI REMOTE EXECUTION WITH SSH +# Multi SSH -A shellscript written in Bash to execute a single command on one or many target hosts via ssh. -A target host can define a jumphost if it is not accessible directly. +Send a command via ssh to one or multiple servers -The script is designed to run in interactive mode but supports command line parameters for scripting too. +This is a shellscript written in Bash to execute a single command on one or many target hosts via ssh - optional via jumphost. -## Installation -Go to your directory where you place scripts and clone it +Free software and Open Source from University of Bern :: IML - Institute for Medical Education -With read access - via https: - -```txt -cd ~/scripts -git clone https://git-repo.iml.unibe.ch/admins/multi-remote-execution.git`` -``` - -As developer - to submit changes into git via ssh - -```txt -cd ~/scripts -git clone git@git-repo.iml.unibe.ch:admins/multi-remote-execution.git -``` - -## First start - -Just start `multi_ssh.sh` - it will initialize a user config file with the defaults. -Without a parameter you reach the interactive mode. - -To see the parameters start `multi_ssh.sh -h` - -```txt -_______________________________________________________________________________ - - MULTI REMOTE EXECUTION WITH SSH ______ -________________________________________________________________________/ v0.14 - -SYNTAX: - multi_ssh.sh [OPTIONS] [SERVERLIST] - -OPTIONS: - -c|--command [COMMAMD] - set a command for remote execution. A 2nd value - for the new command is optional. Without param - you reach an interactive mode. - Save config and exit. - -h|--help show this help and exit - -l|--list list servers - -t|--tag [TAGNAME(s)] - set a tag to filter serverlist. - To set multiple tags quote it as a single string - and seperate them wih a space. Without param - you reach an interactive mode. - Save config and exit. -PARAMETERS: - The serverlist is a combination of servers that should - execute the command [hostname -f]. - It can be the number of a server or a - A special item is ALL - it executes the command on all servers - - Without a parameter you reach the interactive mode. - -EXAMPLES: - multi_ssh.sh -c - set a new command. Enter it on the prompt - multi_ssh.sh -c "sudo reboot" - set a given command - multi_ssh.sh -t "mon live" - set filter tags "mon" and "live" - multi_ssh.sh -l - list servers that match all tags (AND condition) - multi_ssh.sh 1 2 5 - run the command on 1st, 2nd and 5th server - multi_ssh.sh monitor - run the command on the first server that matches 'monitor' - -``` - -## File structure - -```txt -├── color.class.sh needed file with functions for coloring -├── config -│ ├── commands.txt list of pre defined commands -│ ├── serverlist.json Json file with servers and tags -│ └── userconfig.sh local userspecific config -├── logs -│ └── returncodes.log log of executed commands -├── multi_ssh.sh << main script to run -└── README.md this file -``` +📄 Source: <https://git-repo.iml.unibe.ch/iml-open-source/multi_ssh/> \ +📜 License: GNU GPL 3.0 \ +📗 Docs: <https://os-docs.iml.unibe.ch/multi_ssh/> diff --git a/docs/10_Introduction b/docs/10_Introduction index 935b5d4f2db479904f9ef13fa363207ec7bbc236..c54509eb78655cbadb9a7754e21bc5f23a49760f 100644 --- a/docs/10_Introduction +++ b/docs/10_Introduction @@ -5,18 +5,25 @@ A target host can define a jumphost if it is not accessible directly. The script is designed to run in interactive mode but supports a few command line parameters for scripting too. -In a server configuration file you can put your servers. Each server can have +In a server configuration file you can put your servers. Each server can have * multiple tags, eg. for OS/ for hardware os VM/ for application/ for maintenance group * optional: a jumphost (if it is not accessible directly). +The script is designed to run in interactive mode but supports command line parameters for scripting too. + +In the interactive mode you see a list of servers of a selected profile (and maybe filtered by tags). You can run a selected command an one or many servers. Each command will be in an extra terminal that stays open as long the process is finished and you press RETURN. + +In the server list a timestamp will be shown when a command was successful. This is can be used as a checklist to rollout a command on all wanted servers. + ## Requirements * Bash * GNU tools * OpenSSH client +* console tool supporting parameter -e (eg. gnome-terminal, xterm, konsole) The script was written on Linux. -It was not tested on other OS - but it "should" run. On MS Windows you can use WSL or Cygwin / MSYS or similiar compiled binaries. +It was not tested on other OS - but it "could" run. On MS Windows you can use WSL or Cygwin / MSYS or similiar compiled binaries. Mac OS ensure to have GNU variants of tools like sed, grep, ... in the PATH. diff --git a/docs/20_Installation.md b/docs/20_Installation.md index 102f0159e6b4b943a5bf2db6e30fc9565c31edef..6c5bac238cdb22b14114009e07b3a35087b6d0fe 100644 --- a/docs/20_Installation.md +++ b/docs/20_Installation.md @@ -6,39 +6,57 @@ With read access - via https: ```txt cd ~/scripts -git clone https://git-repo.iml.unibe.ch/admins/multi-remote-execution.git`` -``` - -As developer - to submit changes into git via ssh - -```txt -cd ~/scripts -git clone git@git-repo.iml.unibe.ch:admins/multi-remote-execution.git +git clone https://git-repo.iml.unibe.ch/iml-open-source/multi_ssh.git ``` ## File structure -These files are needed to run: +You get these files in the multi_ssh directory: ```txt +. +├── README.md ├── color.class.sh needed file with functions for coloring ├── config -│ ├── commands.txt list of pre defined commands (*) -│ ├── serverlist.json Json file with servers and tags (*) -│ └── userconfig.sh local userspecific config +│ ├── commands.txt.dist +│ └── default +│ ├── commands.txt.dist +│ └── serverlist.json.dist +├── docs +│ ... ├── logs -│ └── returncodes.log log of executed commands (will be created) -└── multi_ssh.sh << main script +└── multi_ssh.sh << main script ``` -(*) This file comes with a .dist file. +Dome configuration files come with a .dist file. +See next chapter for configuration. -## Create configuration +## First start -In the config directory copy 2 *.dist files to the same filename without .dist: +When you start the main script the first time a userconfig will be created. +The script stops because a list of servers is missed. ```txt -cd dist -cp commands.txt.dist commands.txt -cp serverlist.json.dist serverlist.json +> ./multi_ssh.sh +_______________________________________________________________________________ + + MULTI REMOTE EXECUTION WITH SSH ______ +________________________________________________________________________/ v0.17 + +INIT: Creating user config... +saved: +-rw-r--r-- 1 axel axel 684 May 24 11:58 config/userconfig.sh + +INIT: Creating default commands ./config/commands.txt ... + +WELCOME! +We need a file <serverlist.json> to start. + +Create a file config/default/serverlist.json ... OR +You can create a new profile directory ./config/<PROFILE>/ and for a +seperate network with custom servers and commands. +HINT: Copy the template config/default/serverlist.json.dist to start. + +If you want to switch to another profile use multi_ssh.sh -p + ``` diff --git a/docs/30_Configuration.md b/docs/30_Configuration.md index 602cd61bf815d5416822ac69fdec438ce87d1a2a..5cab00b457e48c04169dd713c6c9fdafad2f3d35 100644 --- a/docs/30_Configuration.md +++ b/docs/30_Configuration.md @@ -1,16 +1,67 @@ -## Configuration +## Configuration structure -In the subfolder ``./config/`` are these files +In the subfolder ``./config/`` are all configuration files -* config/commands.txt -* config/serverlist.json -* config/userconfig.sh +```txt +├── config +│ ├── commands.txt +│ ├── default +│ │ ├── commands.txt +│ │ └── serverlist.json +│ └── userconfig.sh +``` -### File commands.txt +### User configuration + +The file `./config/userconfig.sh` will be created on the first run and updated during usage when setting a command, tag or profile. + +The file is plain bash shell script and will be sourced by multi_ssh. + +Do not add other variables here - it will be overwritten on next save process. + +```txt +#!/bin/bash +# CONFIG for multi_ssh.sh - saved Wed May 15 15:50:16 CEST 2024 + +# profile +export MRE_PROFILE=default + +# admin user to connecto to other hosts +export MRE_SSHUSER=sshuser + +# terminal program to open per connection +export MRE_TERMINAL=gnome-terminal + +# filter hosts, set command +export MRE_TAGS="" + +# command to execute on target host(s) +export MRE_COMMAND="hostname -f" + +# colors +export COLOR_PRESET_cmd=( blue ) +export COLOR_PRESET_bastion=( purple ) +export COLOR_PRESET_lastexec=( green ) +export COLOR_PRESET_terminal=( brown ) +export COLOR_PRESET_prompt=( green ) +export COLOR_PRESET_output=( darkgray ) +export COLOR_PRESET_ok=( green ) +export COLOR_PRESET_error=( red ) +``` -This is a textfile with pre defined commands you want to use more often. The file is just plain text. Structure its content like you want. +**Variables**: -**Example**: +* COLOR_PRESET_(...): {array} foreground and background color for a few presets. +* remotecommand: {string} saved remote command +* sshuser: {string} a user to be used for ssh connection. If a connection is via bastion host this user is used for bastion and for target. +* taglist: {string} savd list of tags seperated by space. The active servers are these that match all given tags (AND condition). +* terminal: {string} command to start a terminal. In it the ssh command will be executed. If a command will be executed you get a single terminal per target. The terminal must know the param "-e" to execute a command. Known as compatible: gnome-terminal (default), konsole (KDE), xterm + +### Commands + +The file `./config/commands.txt` is a textfile with pre defined commands you want to use more often on all systems. The file is just plain text. Structure its content like you want. + +Example: ```txt # --- simple things / testing @@ -21,8 +72,29 @@ sleep 20 sudo reboot ``` +Remark: + +You can add an additional commands.txt in a profile directory. See profiles below. + +## Profiles + +Below the config directory you can create subdirectories to create custom profiles. + +A subfolder "default" is delivered with *.dist files. + +Each new profile can contain these files + +* commands.txt +* serverlist.json + +### File commands.txt + +A `./config/<profile>/commands.txt` in a profile directory is optional. It will be shown when setting a command. Its content will be displayed below the content of `./config/commands.txt`. + ### File serverlist.json +A file `./config/<profile>/serverlist.json` is required. It contains all servers you want to handle with that profile. + This is the example configuration in the dist file: ```txt @@ -46,7 +118,7 @@ This is the example configuration in the dist file: } ``` -#### Commants +#### Comments The serverlist.json is nearly JSON: next to plain JSON you can start a comment with ``#`` character that sets a comment up to the end of line. The ``#`` cannot be used inside you JSON data. @@ -70,47 +142,3 @@ In the subkey "servers" are array values for each server you want to use as ssh * tags: {array} * bastion: {string} optional jumphost if a target is not reachable directly -### File userconfig.sh - -This file wil be created on the first run. -It contains user inputs and some customizations. - -The file is plain bash shell script and will be sourced by multi_ssh. - -The file will be written if you set a tag or a command in multi_ssh. All other variables you need to confure in the file directly. - -```bash -#!/bin/bash -# CONFIG for multi_ssh.sh - saved Do 19 Okt 2023 12:23:23 CEST - -# admin user to connecto to other hosts -export sshuser=admin - -# terminal program to open per connection -export terminal=gnome-terminal - -# filter hosts, set command -export taglist="mon" - -# command to execute on target host(s) -export remotecommand="hostname -f" - -# colors -export COLOR_PRESET_cmd=( blue ) -export COLOR_PRESET_bastion=( purple ) -export COLOR_PRESET_lastexec=( green ) -export COLOR_PRESET_terminal=( brown ) -export COLOR_PRESET_prompt=( green ) -export COLOR_PRESET_output=( darkgray ) -export COLOR_PRESET_ok=( green ) -export COLOR_PRESET_error=( red ) - -``` - -**Variables**: - -* COLOR_PRESET_(...): {array} foreground and background color for a few presets. -* remotecommand: {string} saved remote command -* sshuser: {string} a user to be used for ssh connection. If a connection is via bastion host this user is used for bastion and for target. -* taglist: {string} savd list of tags seperated by space. The active servers are these that match all given tags (AND condition). -* terminal: {string} command to start a terminal. In it the ssh command will be executed. If a command will be executed you get a single terminal per target. The terminal must know the param "-e" to execute a command. Known as compatible: gnome-terminal (default), konsole (KDE), xterm diff --git a/docs/40_Usage.md b/docs/40_Usage.md index f09b3dc3f011daaec86dec59b79884080d6504f5..c9ce6c9c9b9df2c7a6d33f632566546ee4403c4f 100644 --- a/docs/40_Usage.md +++ b/docs/40_Usage.md @@ -1,4 +1,4 @@ -## First start +## Usage Just start `multi_ssh.sh` - it will initialize a user config file with the defaults. Without a parameter you reach the interactive mode. @@ -9,7 +9,7 @@ To see the parameters start `multi_ssh.sh -h` _______________________________________________________________________________ MULTI REMOTE EXECUTION WITH SSH ______ -________________________________________________________________________/ v0.14 +________________________________________________________________________/ v0.17 SYNTAX: multi_ssh.sh [OPTIONS] [SERVERLIST] @@ -22,6 +22,8 @@ OPTIONS: Save config and exit. -h|--help show this help and exit -l|--list list servers + -p|--profile [PROFILE] + set a profile for network environment -t|--tag [TAGNAME(s)] set a tag to filter serverlist. To set multiple tags quote it as a single string diff --git a/docs/_index.md b/docs/_index.md index 817598a4052af78ff2cf6b9e6e1a326615dd9e21..ea06d6bd7f94000c6a1805fed3fcf3ab719aba74 100755 --- a/docs/_index.md +++ b/docs/_index.md @@ -5,10 +5,8 @@ </div> </html> -TODO - Free software and Open Source from University of Bern :: IML - Institute of Medical Education -📄 Source: TODO \ +📄 Source: <https://git-repo.iml.unibe.ch/iml-open-source/multi_ssh/> \ 📜 License: GNU GPL 3.0 \ -📗 Docs: TODO +📗 Docs: <https://os-docs.iml.unibe.ch/multi_ssh/> diff --git a/docs/config.json b/docs/config.json index 0b38adf485826da0193007039dfb8e3b77caff9d..f8f2b164c73dd656ba832678c3ca1b7fcbc040af 100644 --- a/docs/config.json +++ b/docs/config.json @@ -12,13 +12,13 @@ "date_modified": false, "jump_buttons": true, "edit_on_github_": "iml-it/__PROJECT__/tree/master/docs", - "edit_on_": { + "edit_on": { "name": "Gitlab", - "basepath": "https://git-repo.iml.unibe.ch/iml-open-source/__PROJECT__/tree/master/docs" + "basepath": "https://git-repo.iml.unibe.ch/iml-open-source/multi_ssh/tree/main/docs" }, "links": { "Git Repo": "__GITURL__", - "IML Opensource": "https://os-docs.iml.unibe.ch/" + "IML Opensource": "https://os-docs.iml.unibe.ch/multi_ssh/" }, "theme": "daux-blue", "search": true diff --git a/docs/style.css b/docs/style.css index 4186d17f75909f2d9190cff5152d48366c829baf..45383c3288f17a74d88fc2ffca48307f794d4592 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,13 +1,14 @@ /* override css elements of daux.io blue theme - version 2023-10-09 + version 2023-11-10 */ :root { /* Axels Overrides */ --color-text: #234; - --link-color: #822; + --link-color: #228; --brand-color: var(--color-text); --brand-background: var(--body-background); + --code-tag-border-color: #d8d8d8; --hr-color: none; --search-field-background: none; --search-field-border-color: none; @@ -46,9 +47,10 @@ .dark { /* Axels Overrides */ --color-text: #c0c0c0; - --link-color: #c66; + --link-color: #88e; --brand-color: var(--color-text); --brand-background: var(--body-background); + --body-background: #101418; --hr-color: none; --code-tag-background-color_: #bcc; --search-field-background: none; @@ -175,10 +177,12 @@ img{ .s-content .TableOfContentsContainer h4 { margin: 1em 0; - font-size: 100%; + font-size: 110%; text-align: center; - background-color: rgba(0, 0, 0, 0.05); + background-color: rgba(0, 0, 0, 0.1); padding: 0.3em; + font-weight: bold; + font-family: Arial; } ul.TableOfContents a{ color: var(--color-text); diff --git a/multi_ssh.sh b/multi_ssh.sh index 1da61322ab5cd7e813551db3ecb718a2077bb734..e50e575c1174195488e78a727caacc256bd683ab 100755 --- a/multi_ssh.sh +++ b/multi_ssh.sh @@ -19,9 +19,10 @@ # 2023-10-18 0.14 <axel.hahn@unibe.ch> automatically init of userconfig; check terminal # 2023-10-19 0.15 <axel.hahn@unibe.ch> Fix: Show running terminal in server list # 2024-05-15 0.16 <axel.hahn@unibe.ch> add profiles; rename internal variables -# ====================================================================== +# 2024-05-24 0.17 <axel.hahn@unibe.ch> update headlines; fix param -t + ====================================================================== -_version=0.16 +_version=0.17 _self=$( basename $0 ) cd "$( dirname $0 )" @@ -42,6 +43,7 @@ MRE_TAGS= COLOR_PRESET_cmd=("blue") COLOR_PRESET_bastion=("purple") COLOR_PRESET_lastexec=("green") +COLOR_PRESET_headline=("yellow") COLOR_PRESET_terminal=("brown") COLOR_PRESET_prompt=("green") COLOR_PRESET_output=("darkgray") @@ -100,6 +102,8 @@ EXAMPLES: function _setProfile(){ local new="$1" if [ -z "$new" ]; then + echo + color.echo "headline" ">>>>> List of profiles:" find config -maxdepth 1 -type d | sed "s#^config[/]*##g" echo echo -n "Current: " @@ -150,6 +154,9 @@ function _getProfile(){ # show a list of stored commands function _getCommandlist(){ + echo + color.echo "headline" ">>>>> Commands:" + echo echo "---- List default commands :: ./config/commands.txt" echo color.preset "output" @@ -236,7 +243,9 @@ function _getHostProperty(){ # show a list of all tags on screen function _gettags(){ local _spacer=" " - + echo + color.echo "headline" ">>>>> Tags:" + echo echo "-- all current tags in hosts:" color.preset output _getJSON | jq ".servers[] | .tags " | grep '"' | tr -d ',"' | sort -u | sed "s#^ *##g" | sed "s#^#${_spacer}#g" @@ -297,6 +306,7 @@ export MRE_COMMAND="$MRE_COMMAND" export COLOR_PRESET_cmd=( ${COLOR_PRESET_cmd[*]} ) export COLOR_PRESET_bastion=( ${COLOR_PRESET_bastion[*]} ) export COLOR_PRESET_lastexec=( ${COLOR_PRESET_lastexec[*]} ) +export COLOR_PRESET_headline=( ${COLOR_PRESET_headline[*]} ) export COLOR_PRESET_terminal=( ${COLOR_PRESET_terminal[*]} ) export COLOR_PRESET_prompt=( ${COLOR_PRESET_prompt[*]} ) export COLOR_PRESET_output=( ${COLOR_PRESET_output[*]} ) @@ -352,7 +362,7 @@ function showServers(){ _processes=$( _getTerminals ) # --- show bastion and last successful execution - echo "---- List of servers - $( date )" + color.echo "headline" ">>>>> List of servers - $( date )" echo color.underline @@ -502,7 +512,7 @@ while [[ "$#" -gt 0 ]]; do case $1 in -c|--command) _setCommand "$2"; exit 0;; -h|--help) echo "$USAGE"; exit 0;; -l|--list) showServers ; echo; exit 0;; - -t|--tag) _setTags "$2"; exit 0;; + -t|--tag) test -z "$MRE_JSONFILE" && _getProfile; _setTags "$2"; exit 0;; -p|--profile) _setProfile "$2"; exit 0;; *) if echo "$1" | grep "^-" >/dev/null; then color.echo "error" "ERROR: Unknown parameter: $1"; echo "${USAGE}"; exit 1;