sssh.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. #!/usr/bin/env bash
  2. # ##########################################################
  3. #
  4. # Super SSH Script
  5. #
  6. # Version 2 [06/2021]
  7. #
  8. # v2 start new version, complete rewrite of code
  9. # ---
  10. # V1.9.2 Rewrite project menu output, change from echo to printf
  11. # V1.9.1 Project overview now accept project names as input [08.11.2017]
  12. # V1.9 [06.10.2017]
  13. # V1.8 Added group function again [08.2017]
  14. # V1.7 Rewrite script - now with functions [06.2016]
  15. # V1.6 Added function to pass parameters to server menu [05.2012]
  16. # V1.5 Added function to choose by hostname [05.2012]
  17. # V1.4 Added group function [11.2011]
  18. # V1.3 Added avaibility function
  19. # V1.2 color output
  20. # V1.0 Create script
  21. ## some infos
  22. ##
  23. ## There are 3 types of arrays:
  24. ##
  25. ## - array_projects, contain the projectnames
  26. ## - array_${project_name}, dynamic generates from file name
  27. ## - array_${host_name}, dynamic generates from project-configuration
  28. ##
  29. #### config ####
  30. ## Wenn true wird jeder Host 1x angepingt und der Status ausgegeben
  31. PINGHOST="true" # gueltige Werte [true,false]
  32. DEBUG="false"
  33. ## print full fqdn in project menu [default: false]
  34. ## fqdn is always used to connect even is deactivated!!
  35. FQDN="false"
  36. #### do not change ####
  37. ## used to kill from subshell
  38. MAINPID=$$
  39. ## locationOfScript
  40. locationOfScript=$(dirname "$(readlink -e "$0")")
  41. ## declare project-array
  42. declare -a array_projects
  43. #=== FUNCTION ================================================================
  44. # NAME: get_projects
  45. # DESCRIPTION: read project-files (*.lst) to arrays
  46. # PARAMETERS:
  47. # RETURNS:
  48. #===============================================================================
  49. function get_projects() {
  50. ## empty array
  51. array_projects=()
  52. array_projects+=('defaults')
  53. while read file
  54. do
  55. projectname=`basename "${file}" .lst`
  56. ## write projectname to project array
  57. array_projects+=("${projectname}")
  58. declare -ga ${projectname}
  59. eval "${projectname}+=('defaults')"
  60. ## parse project file
  61. while read VARNAME VALUE
  62. do
  63. if [ "${VARNAME}" == "HOST" ]
  64. then
  65. HOSTNAME=`echo ${VALUE} | sed 's/-/_/g'`
  66. [[ ${HOSTNAME} =~ '.' ]] && { VAR_HOSTNAME=${HOSTNAME}; HOSTNAME=`echo ${HOSTNAME} | cut -d'.' -f1` ; }
  67. declare -Ag "${HOSTNAME}"
  68. [[ ${VAR_HOSTNAME} ]] && { eval "${HOSTNAME}+=(['fqdn']=\"${VAR_HOSTNAME}\")"; }
  69. eval "${projectname}+=(\"${HOSTNAME}\")"
  70. continue
  71. else
  72. ## add configuration to host-array
  73. ## varnames getting lower case (https://stackoverflow.com/questions/2264428/how-to-convert-a-string-to-lower-case-in-bash/2265268#2265268)
  74. ## eval "nas+=([port]="22")"
  75. eval "${HOSTNAME}+=([\"${VARNAME,,}\"]=\"${VALUE}\")"
  76. fi
  77. done <<<$( egrep -v "(^\s*$|^#)" "${file}" )
  78. done <<<$( find ${locationOfScript} -iname *.lst | sort )
  79. }
  80. #=== FUNCTION ================================================================
  81. # NAME: get_groups
  82. # DESCRIPTION: find all groups of given project
  83. # PARAMETERS: project_name
  84. # RETURNS:
  85. #===============================================================================
  86. function get_groups() {
  87. ## reset groups/groupscount (neccessary for project reload)
  88. groups=""
  89. groups_count=0
  90. counter=0
  91. ## be carfully: $GROUPS is an BASH internal variable
  92. declare -n array_project="$project"
  93. declare -Ag array_groups
  94. # x y z sind mit sonderfunktionen belegt!
  95. arr_character=( a b c d e f g h i j k l m n o p q r s t u v w )
  96. for host in "${array_project[@]}"; do
  97. [ "${host}" == "defaults" ] && continue
  98. declare -n vars="$host"
  99. if [ -n "${vars['group']}" ];
  100. then
  101. if [[ ! " ${array_groups[@]} " =~ " ${vars['group']} " ]]
  102. then
  103. eval array_groups+=([\"${arr_character[${groups_count}]}\"]=\"${vars['group']}\")
  104. groups_count=$[groups_count+1]
  105. fi
  106. fi
  107. done
  108. ## print groups
  109. ## loop allowed characters
  110. for i in "${arr_character[@]}"; do
  111. ## if character is key of array_groups
  112. if [[ "${!array_groups[@]}" =~ "${i}" ]]; then
  113. printf "[\033[1;33m%s\033[0m]\033[1;32m%s\033[0m " "${i}" "${array_groups[$i]}"
  114. fi
  115. done
  116. }
  117. #=== FUNCTION ================================================================
  118. # NAME: get_projectname
  119. # DESCRIPTION: detect the project name
  120. # PARAMETERS: project nr or name
  121. # RETURNS:
  122. #===============================================================================
  123. function get_projectname() {
  124. declare -g project
  125. ## check if given projectname or projectnumber
  126. if [[ $1 =~ ^[0-9]+$ ]] ; then
  127. ## projectnumber, read projectname from "projects" string
  128. project="${array_projects["$1"]}"
  129. else
  130. ## projectname ...
  131. project=$1
  132. fi
  133. }
  134. #=== FUNCTION ================================================================
  135. # NAME: print_mainmenu
  136. # DESCRIPTION: print out main menu of all projects
  137. # PARAMETERS:
  138. # RETURNS:
  139. #===============================================================================
  140. function print_mainmenu() {
  141. declare -g INPUT_PROJECT
  142. while ! check_input "${INPUT_PROJECT}"; do
  143. clear
  144. echo " == Super SSH Sprungmenu =="
  145. echo
  146. for i in "${!array_projects[@]}"; do
  147. [ $i -ne 0 ] && printf "%6s %s\n" "$i" "${array_projects[$i]}"
  148. done
  149. echo
  150. echo " x Abbruch"
  151. echo
  152. echo " ===================="
  153. echo -ne "Auswahl: "
  154. read INPUT_PROJECT
  155. done
  156. }
  157. #=== FUNCTION ================================================================
  158. # NAME: print_projectmenu
  159. # DESCRIPTION: print out projectmenu for given project
  160. # PARAMETERS: project,group
  161. # RETURNS:
  162. #===============================================================================
  163. function print_projectmenu() {
  164. ## reset variables
  165. GROUP_FILTER=
  166. LINENUMBER=
  167. clear
  168. echo -e " == SSH Sprungmenu ==\n\n Projekt: $project\n"
  169. ## just read out all groups
  170. get_groups ${project}
  171. ## group filter given
  172. if [ -n "$2" ]; then
  173. for i in "${!arr_character[@]}"; do
  174. if [ "${arr_character[$i]}" == "$2" ]; then
  175. #GROUP_FILTER=$( echo $groups | cut -d ":" -f $(($i+1)) )
  176. GROUP_FILTER=${array_groups["$2"]}
  177. fi
  178. done
  179. fi
  180. # Ausgabe des Headers
  181. if [ "$PINGHOST" == "true" ]; then
  182. printf "\n\n\033[1;33m%3s %11s %-25s %-12s %-13s %s\033[0m\n" "ID" "<USER> @" "Host:<port>" "[Status]" "Gruppe" "Beschreibung"
  183. else
  184. echo -e "\033[1;33mID USER\t Host\tGruppe\t\t\tBeschreibung \033[0m "
  185. fi
  186. declare -n array_project="$project"
  187. for host in "${array_project[@]}"; do
  188. # GROUP=""
  189. [ "${host}" == "defaults" ] && continue
  190. declare -n vars="$host"
  191. LINENUMBER=$[LINENUMBER+1]
  192. SSHHOST=${host}
  193. DESCRIBTION="${vars['desc']}"
  194. USERNAME="${vars['user']}"
  195. GROUP="${vars['group']}"
  196. SSHPORT="${vars['port']}"
  197. ALIAS="${vars['alias']}"
  198. if ( [ -n "${GROUP_FILTER}" ] && [ "${GROUP}" != "${GROUP_FILTER}" ]); then continue; fi
  199. [[ -z ${GROUP} ]] && SSHPORT="22"
  200. ## print full fqdn if defined and not deactivated by conf
  201. if ( ${FQDN} && [ ${vars['fqdn']} ] ); then SSHHOST=${vars['fqdn']}; fi
  202. ## FQDN allways used to ping host
  203. if ( [ ${vars['fqdn']} ] ); then SSHPINGHOST="${vars['fqdn']}"; fi
  204. ## check some variables
  205. [[ -z ${USERNAME} ]] && USERNAME="" || USERNAME="$USERNAME @"
  206. [[ -z ${SSHPORT} ]] && SSHPORT="22"
  207. [[ "${PINGHOST}" == "true" ]] && ping_host ${SSHPINGHOST} ${SSHPORT} || STATUS="\t"
  208. [[ ! -z ${ALIAS} ]] && SSHHOST="${ALIAS}"
  209. [[ "${SSHPORT}" != "22" ]] && SSHPORT_PRINT=":${SSHPORT}"
  210. printf "%2s %12s %-25s ${STATUSCOLOR}%-12s\033[0m %-13s %s\n" "${LINENUMBER}" "${USERNAME}" "${SSHHOST}${SSHPORT_PRINT}" "${STATUS}" "${GROUP}" "${DESCRIBTION}"
  211. done
  212. # Ausgabe der Standarteintraege
  213. echo -en "\n\n x Abbruch\n z Zurueck ins Basemenu\n ============================\nAuswahl: "
  214. }
  215. #=== FUNCTION ================================================================
  216. # NAME: ping_host
  217. # DESCRIPTION: check if given ssh port is open
  218. # PARAMETERS: host, portnumber
  219. # RETURNS:
  220. #===============================================================================
  221. function ping_host() {
  222. ## returncode doesn't work in subshell ...
  223. PING=$(netcat -w 1 -z $1 $2 >> /dev/null 2>&1 ; echo $? )
  224. if [ "$PING" -eq 0 ]; then
  225. STATUS="[UP]"
  226. STATUSCOLOR="\033[1;32m"
  227. else
  228. STATUS="[DOWN]"
  229. STATUSCOLOR="\033[1;31m"
  230. fi
  231. }
  232. #=== FUNCTION ================================================================
  233. # NAME: check_input
  234. # DESCRIPTION: check if given input is correct and digit is in list range
  235. # PARAMETERS: PROJECT, HOST (optional)
  236. # RETURNS: true/false
  237. #===============================================================================
  238. function check_input() {
  239. ## if host is given project must known!
  240. [ -z $2 ] && SEARCHSTRING=$1 || SEARCHSTRING=$2
  241. case "${SEARCHSTRING}" in
  242. dummy)
  243. return 1
  244. ;;
  245. [[:digit:]]*)
  246. ## projectnumber is given
  247. ## 0-9
  248. if [ -z "$2" ]; then
  249. [[ "${!array_projects[@]}" =~ "${1}" ]] && return 0 || return 1
  250. else
  251. ## array_hosts => dynamic array "{projectname}"
  252. declare -n array_hosts="${array_projects[${1}]}"
  253. ## check if given digit is an host (index number of array)
  254. [[ "${!array_hosts[@]}" =~ "${1}" ]] && return 0 || return 1
  255. fi
  256. ;;
  257. z)
  258. ## back to mainmenu
  259. bash $0
  260. ;;
  261. x)
  262. ## exit
  263. echo "Du weißt auch nicht was du willst ..."
  264. kill $MAINPID
  265. ;;
  266. [[:alpha:]])
  267. ## group filter
  268. return 1
  269. ;;
  270. [[:alpha:]]*)
  271. ## check for project-names
  272. ## a-z or A-Z
  273. if [ -z "$2" ]; then
  274. [[ "${array_projects[@]}" =~ "${1}" ]] && return 0 || return 1
  275. else
  276. ## array_hosts => dynamic array "{projectname}"
  277. declare -n array_hosts="${array_projects[${1}]}"
  278. ## check if given project name is in dynamic project array
  279. [[ "${array_hosts[@]}" =~ "${1}" ]] && return 0 || return 1
  280. fi
  281. ;;
  282. *)
  283. return 1
  284. ;;
  285. esac
  286. }
  287. #=== FUNCTION ================================================================
  288. # NAME: ssh_to_host
  289. # DESCRIPTION: connect to host
  290. # PARAMETERS: project, host
  291. # RETURNS: true/false
  292. #===============================================================================
  293. function ssh_to_host() {
  294. PROJECT=$1
  295. HOST=$2
  296. ## check if number or hostname given
  297. if [ `echo ${HOST} | grep -E ^[[:digit:]]+$` ]; then
  298. ## linenumber
  299. declare -n ARR_PROJECT="${PROJECT}"
  300. SSHHOST=${ARR_PROJECT[${HOST}]}
  301. else
  302. ## hostname
  303. SSHHOST=${HOST}
  304. fi
  305. declare -n ARRAY_SSHHOST="${SSHHOST}"
  306. USERNAME=${ARRAY_SSHHOST["user"]}
  307. SSHPORT=${ARRAY_SSHHOST["port"]}
  308. SSHFQDN=${ARRAY_SSHHOST["fqdn"]}
  309. ## if fqdn is defined we allways connect to this
  310. # [ -n ${ARRAY_SSHHOST['fqdn']} ] && SSHHOST="${ARRAY_SSHHOST['fqdn']}"
  311. # TMP_FQDN="${ARRAY_SSHHOST['fqdn']}"
  312. # [ -n ${SSHFQDN} ] && SSHHOST="${SSHFQDN}"
  313. # if ( ${ARRAY_SSHHOST['fqdn']} && [ -n ${ARRAY_SSHHOST['fqdn']} ] ); then SSHHOST="${ARRAY_SSHHOST['fqdn']}"; fi
  314. ## add ssh-parameter if optional params defined
  315. [[ -n ${USERNAME} ]] && USERNAME="-l ${USERNAME}"
  316. [[ -n ${SSHPORT} ]] && SSHPORT="-p ${SSHPORT}"
  317. [[ -n ${SSHFQDN} ]] && SSHHOST="${SSHFQDN}"
  318. echo "Executing: ssh $SSHPORT $USERNAME $SSHHOST"
  319. ssh $SSHPORT $USERNAME $SSHHOST
  320. }
  321. #=== FUNCTION ================================================================
  322. # NAME: debug
  323. # DESCRIPTION: print the arrays
  324. # PARAMETERS:
  325. # RETURNS:
  326. #===============================================================================
  327. function debug() {
  328. echo -e '\n### DEBUG START ##########################\n'
  329. echo "Debug: array_projects"
  330. for project in "${array_projects[@]}"; do
  331. echo -e "\nproject: $project"
  332. declare -n hosts="${project}"
  333. for host in "${hosts[@]}"; do
  334. declare -n vars="${host}"
  335. printf " - %s\n" "server: ${host}"
  336. for i in "${!vars[@]}"; do
  337. printf " - %s: %s\n" "$i" "${vars[$i]}"
  338. done
  339. done
  340. done
  341. echo -e '\n### DEBUG END ############################\n'
  342. }
  343. #=== Main Script =============================================================
  344. #
  345. #
  346. #===============================================================================
  347. INPUT_PROJECT=$1
  348. [ -n "$2" ] && INPUT_HOST="$2" || INPUT_HOST="dummy"
  349. get_projects
  350. if ${DEBUG}; then debug; fi
  351. print_mainmenu
  352. get_projectname ${INPUT_PROJECT}
  353. ## check if group OR host given
  354. while ! check_input "${INPUT_PROJECT}" "${INPUT_HOST}" ; do
  355. print_projectmenu "${INPUT_PROJECT}" "${INPUT_HOST}"
  356. read INPUT_HOST
  357. INPUT_HOST="${INPUT_HOST:-dummy}"
  358. done
  359. ssh_to_host ${project} ${INPUT_HOST}