sssh.sh 16 KB

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