executable_connect 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. #!/usr/bin/env bash
  2. set -e
  3. set -o pipefail
  4. help_main()
  5. {
  6. echo "\
  7. Usage: connect COMMANDS ARGS...
  8. Run COMMANDS with ARGS
  9. COMMAND must be one of the sub-commands listed below:
  10. general commands
  11. uptime show uptime on SERVER
  12. php show PHP status on SERVER
  13. disk commands
  14. io show input output stats on SERVER
  15. stat show iostat on SERVER
  16. sg show disk performance on SERVER
  17. docker commands
  18. containers list running containers on SERVER
  19. deploy deploy containers to SERVER
  20. images list container images on SERVER
  21. MySQL commands
  22. clean kill MySQL connections on SERVER
  23. mysql connect to MySQL on server
  24. networking commands
  25. ip invoke ip address and route on SERVER
  26. firewall print iptables rules on SERVER
  27. interfaces list network interfaces on SERVER
  28. ip-filter control ip-filter on server
  29. net show network interfaces stats on SERVER
  30. ping ping a SERVER
  31. protected add DOMAIN to protected on SERVER
  32. route show network route to SERVER
  33. sniff run tcpdump on SERVER
  34. traceroute show traceroute to SERVER
  35. logs commands
  36. apache show USER's Apache logs
  37. te show taskexecutor logs
  38. shell commands
  39. shell connect to CISCO
  40. ssh connect to server via SSH
  41. sshrc connect to server via SSH with configuration
  42. NGINX commands
  43. filter add IP address to ip-filter on SERVER
  44. unfilter delete IP address from ip-filter on SERVER
  45. nginx show top requests to NGINX
  46. nginx-config show NGINX config on SERVER
  47. junos commands
  48. br1-mr14.intr miran border
  49. sr1-mr13-14.intr miran sr
  50. sr1-dh507-508.intr datahouse sr
  51. Report bugs to: go.wigust@gmail.com."
  52. }
  53. help_mysql()
  54. {
  55. echo "\
  56. Usage: connect mysql [OPTION] COMMANDS HOST...
  57. Run COMMANDS with ARGS
  58. -c, --client=CLIENT mysql client
  59. -h, --help display this help and exit
  60. COMMAND must be one of the sub-commands listed below:
  61. connections
  62. filter
  63. Report bugs to: go.wigust@gmail.com."
  64. }
  65. help_ip_filter()
  66. {
  67. echo "\
  68. Usage: connect ip-filter [OPTION]...
  69. Connect to HOST's ip-filter.
  70. -a, --add add IP to ip-filter
  71. -r, --remove remove IP from ip-filter
  72. -d, --describe list IP address in ip-filter
  73. -d, --host ip-filter host
  74. -h, --help display this help and exit
  75. Example: 'connect ip-filter --host web30.intr --describe'.
  76. Report bugs to: go.wigust@gmail.com."
  77. }
  78. DEBUG="${DEBUG:-false}"
  79. telnet_expect_interact()
  80. {
  81. TELNET_PASSWORD="$(pass show majordomo/private/general)" \
  82. ENABLE_PASSWORD="$(pass show majordomo/private/ssh/router)" \
  83. cisco-interact "$@"
  84. }
  85. ssh_expect()
  86. {
  87. PYTHONPATH='' \
  88. SSH_KEY="$HOME/.ssh/id_rsa_majordomo_eng" \
  89. BECOME_PASSWORD="$(pass show majordomo/private/ssh/eng)" \
  90. ssh-sudo "$@"
  91. }
  92. sshrc_sudo()
  93. {
  94. if [ $# -lt 2 ]
  95. then
  96. sshrc "$1"
  97. else
  98. ssh -q -t "$1" -- "set +o history; sudo --stdin --validate --prompt='' <<< $(pass show majordomo/private/ssh/eng); exec -a sudo sudo -i ${*:2}"
  99. fi
  100. }
  101. ssh_sudo()
  102. {
  103. ssh -q -t "$1" -- "set +o history; sudo --stdin --validate --prompt='' <<< $(pass show majordomo/private/ssh/eng); exec -a sudo sudo -i ${*:2}"
  104. }
  105. mysql_command()
  106. {
  107. mysql --silent --user="root" --password="$(pass show majordomo/public/web/mysql/root)" --host="$1" "${@:2}"
  108. }
  109. mysql_list_users_by_connections()
  110. {
  111. mysql_command "$1" --execute="SELECT count(ID) as connections, USER FROM INFORMATION_SCHEMA.PROCESSLIST GROUP BY USER ORDER BY connections;"
  112. }
  113. connect_junos()
  114. {
  115. sshpass -p"$(pass show majordomo/private/ssh/router)" \
  116. ssh -F /dev/null \
  117. -q \
  118. -i "$HOME/.ssh/id_rsa_majordomo_eng" \
  119. -o UserKnownHostsFile=/dev/null \
  120. -o StrictHostKeyChecking=no \
  121. -l root \
  122. "$1" "${@:2}"
  123. }
  124. connect_h3c()
  125. {
  126. sshpass -p"$(pass show majordomo/private/h3c/oleg)" \
  127. ssh -F /dev/null \
  128. -q \
  129. -o UserKnownHostsFile=/dev/null \
  130. -o StrictHostKeyChecking=no \
  131. -l oleg \
  132. "$1" "${@:2}"
  133. }
  134. case "$1" in
  135. --help)
  136. help_main
  137. exit 0
  138. ;;
  139. br1-mr14.intr|sr1-mr13-14.intr|sr1-dh507-508.intr|sw2-mr13.intr)
  140. case "$2" in
  141. bgp)
  142. connect_junos "$1" cli 'show bgp summary'
  143. ;;
  144. log)
  145. number="${3:-$(connect_junos "$1" cli 'show system commit' | wc -l)}"
  146. for n in $(seq 0 "$number")
  147. do
  148. echo "root@$1> show system rollback $((n+1)) compare $n"
  149. connect_junos "$1" cli "show system rollback $((n+1)) compare $n"
  150. done
  151. ;;
  152. configuration)
  153. connect_junos "$1" cli "show configuration"
  154. ;;
  155. *)
  156. connect_junos "$1" "${@:2}"
  157. ;;
  158. esac
  159. exit 0
  160. ;;
  161. galera)
  162. case "$2" in
  163. show)
  164. parallel --will-cite -k "printf '{1}: '; mysql -s -h {1} -u root -p\"$(pass show majordomo/public/maxscale.intr/root)\" -e 'SELECT @@GLOBAL.gtid_binlog_pos'" ::: galera{1..3}.intr
  165. if [[ $(connect galera-backup.intr docker exec galera-slave mysql -uroot -p"$(pass show majordomo/public/maxscale.intr/root)" -e 'SHOW ALL SLAVES STATUS\G' |& grep -c 'Slave_SQL_Running: Yes') -lt 3 ]]
  166. then
  167. printf '\033[35mWARNING:\033[0m galera-backup.intr: Slave_SQL_Running: is less than 3.\n'
  168. else
  169. printf "\033[32mINFO:\033[0m galera-backup.intr: Slave_SQL_Running: is equal to 3.\n"
  170. fi
  171. # connect galera-backup.intr docker exec galera-slave mysql -uroot -p"$(pass show majordomo/public/maxscale.intr/root)" -e 'SELECT @@GLOBAL.gtid_binlog_pos'
  172. ;;
  173. snapshots)
  174. echo "zfs clone pool@zfs-auto-snap_scripted-2019-02-21-1005 pool/mariafromsnap"
  175. echo "docker run --rm --hostname galera-slave-temp --name galera-slave-temp -eMYSQL_ALLOW_EMPTY_PASSWORD=1 -v /pool/mariadb/confdir-ro:/etc/mysql/conf.d -v /pool/mariafromsnap/mariadb/datadir:/var/lib/mysql mariadb:10.3"
  176. echo "MariaDB [(none)]> stop ALL slaves;"
  177. echo "zfs destroy pool/mariafromsnap"
  178. echo "List ZFS snapshots:"
  179. connect ssh galera-backup.intr zfs list -t snapshot
  180. ;;
  181. esac
  182. ;;
  183. filter)
  184. case "$2" in
  185. list)
  186. for web in web15 web16 web17 web18 web19 web20 web21 web22 web23 web25 web26 web27 web28 web29 web30 web31 web32 web33 web34 web35 web36 web37
  187. do
  188. curl -s http://"$web.intr"/ip-filter | sed "s/^/$web.intr\t/g; s/\s/\t/g"
  189. done
  190. ;;
  191. *)
  192. for ip in $(
  193. connect ssh "$2" -- docker logs --tail 1000 nginx \
  194. | awk '{print $1}' \
  195. | sort \
  196. | uniq -c \
  197. | sort -nr \
  198. | fzf -m \
  199. | awk '{print $2}' \
  200. | tac
  201. )
  202. do
  203. whois "$ip" | tail -n $(( $(tput lines) - 2))
  204. read -p "Are you sure want to filter $ip IP address? " -n 1 -r
  205. echo
  206. if [[ $REPLY =~ ^[Yy]$ ]]
  207. then
  208. curl --silent --head --request PUT "$2/ip-filter/$ip?ttl=7200&action=setCookie"
  209. fi
  210. done
  211. esac
  212. ;;
  213. firewall)
  214. connect ssh "$2" -- iptables --line-numbers -n -v -L | jc --iptables -p | yq -y .
  215. ;;
  216. unfilter)
  217. ip="$(connect ssh "$2" -- docker logs --tail 1000 nginx | awk '{print $1}' | sort | uniq -c | sort -nr | fzf | awk '{print $2}')"
  218. curl --silent --head --request DELETE "$2/ip-filter/$ip?ttl=7200&action=setCookie"
  219. ;;
  220. kvm)
  221. racks=(
  222. 5-08
  223. 5-07
  224. )
  225. for rack in "${racks[@]}"
  226. do
  227. (
  228. set +e
  229. for host in $(fping -a $(printf "%s.intr\n" $(mjru-infa server | grep Датахаус | grep kvm | grep -v nvme | awk "/$rack/ { print \$3 }") | xargs echo))
  230. do
  231. echo -e "\n\n@ ${host}@${rack}"
  232. ssh -q "$host" 'free -h; df -h /kvm'
  233. done
  234. )
  235. done
  236. ;;
  237. ssh)
  238. host="$2"
  239. if [[ "$host" != *.intr ]] && [[ "$host" != *sw* ]]
  240. then
  241. host+=.intr
  242. fi
  243. [ "$DEBUG" == true ] && echo "Connect with ssh_sudo() to $host."
  244. ssh_sudo "$host" "${@:3}"
  245. ;;
  246. sshrc)
  247. host="$2"
  248. if [[ "$host" != *.intr ]] && [[ "$host" != *sw* ]]
  249. then
  250. host+=.intr
  251. fi
  252. [ "$DEBUG" == true ] && echo "Connect with sshrc_sudo() to $host."
  253. sshrc_sudo "$host" "${@:3}"
  254. ;;
  255. emacs)
  256. host=$3; [[ "$host" == *.intr ]] || host+=.intr
  257. GTK_THEME='' command emacs -nw "/ssh:$host|sudo:$host:"
  258. ;;
  259. io)
  260. ssh_sudo "$2" iotop -qqqtPbod1 | cut --characters="-$(tput cols)"
  261. ;;
  262. stat)
  263. ssh_sudo "$2" env S_COLORS=true iostat -xchztdk 2
  264. ;;
  265. interfaces)
  266. connect ssh "$2" ifconfig \
  267. | jc --ifconfig \
  268. | jq --raw-output '.[] | [.rx_packets, .tx_packets, .name, .ipv4_addr, .ipv4_mask, .ipv4_bcast, .mac_addr] | @tsv' \
  269. | expand -t1 | column -t | sort -n
  270. ;;
  271. route)
  272. connect ssh "$2" -- route | jc --route | jq | yq -y .
  273. ;;
  274. net)
  275. ssh_sudo "$2" iftop -nNP -i "$(connect ssh "$2" ifconfig | jc --ifconfig | jq --raw-output '.[] | .name' | fzf)"
  276. ;;
  277. sniff)
  278. ssh_sudo "$2" tcpdump -vvvApni "$(connect ssh "$2" ifconfig | jc --ifconfig | jq --raw-output '.[] | .name' | fzf)" "${@:3}"
  279. ;;
  280. mpstat)
  281. ssh_sudo "$2" mpstat 1
  282. ;;
  283. sg)
  284. echo "Hint: Install sg3-utils by invoking 'apt install sg3-utils'"
  285. for i in {1..8}; do
  286. echo -e "\n@ /dev/sg$i"
  287. time ssh_expect "${2%.intr}" "sg_read if=/dev/sg$i bs=512 count=100000"
  288. done
  289. ;;
  290. ping)
  291. ping -n -c "${4:-3}" "${2%.intr}"
  292. ;;
  293. traceroute)
  294. sudo traceroute "${2%.intr}"
  295. ;;
  296. containers)
  297. ssh_expect "${2%.intr}" docker ps --no-trunc --format "'table {{.ID}}\t{{.Names}}\t{{.Status}}'"
  298. ;;
  299. images)
  300. ssh_expect "${2%.intr}" docker images --no-trunc --format "'{{.ID}}: {{.Repository}}'"
  301. ;;
  302. web*)
  303. host="$1"; [[ "$host" == *.intr ]] || host+=.intr
  304. ssh_sudo "$host" "${@:2}"
  305. ;;
  306. shell)
  307. host="$2"; [[ "$host" == *.intr ]] || host+=.intr
  308. if ! ssh_sudo "$host" "${@:3}"
  309. then
  310. TELNET_PASSWORD="$(pass show majordomo/private/general)" cisco "$host" "${@:3}"
  311. fi
  312. ;;
  313. nginx)
  314. ssh_expect "${2%.intr}" docker logs --tail "${3:-1000}" nginx \
  315. | awk '{ print $1 }' \
  316. | grep --invert-match --fixed-strings '127.0.0.1' \
  317. | sort \
  318. | uniq --count \
  319. | sort --numeric-sort
  320. ;;
  321. nginx-config)
  322. connect ssh "$2" cat "$(connect ssh "$2" grep -RF server_name /etc/nginx/sites-available | sort -u | fzf | cut -d: -f 1)"
  323. ;;
  324. mysql)
  325. case "$2" in
  326. connections)
  327. mysql_list_users_by_connections "$3" | expand -t1 | column -t
  328. exit 0
  329. ;;
  330. filter)
  331. command="KILL USER $(mysql_list_users_by_connections "$3" | fzf | awk '{ print $NF }')"
  332. echo "$3: $command"
  333. mysql_command "$3" --execute="$command;"
  334. exit 0
  335. ;;
  336. esac
  337. if ! OPTS="$(getopt --options c:h --long client:,help --name parse-options -- "$@")"
  338. then
  339. echo "Failed parsing options."
  340. exit 1
  341. fi
  342. eval set -- "$OPTS"
  343. while true; do
  344. case "$1" in
  345. -h | --help )
  346. help_mysql
  347. exit 0
  348. ;;
  349. -c | --client )
  350. MYSQL_CLIENT="$2"
  351. shift 2
  352. ;;
  353. -- )
  354. shift
  355. break
  356. ;;
  357. ,* )
  358. break
  359. ;;
  360. esac
  361. done
  362. case $MYSQL_CLIENT in
  363. mysql )
  364. mysql -h"${2%.intr}" -p"$(pass show majordomo/public/web/mysql/root)" -uroot
  365. ;;
  366. mycli )
  367. PAGER='pspg -s 14 -X --force-uniborder --quit-if-one-screen -s 16' \
  368. mycli --password "$(pass show majordomo/public/web/mysql/root)" -d "${2%.intr}"
  369. ;;
  370. * )
  371. PAGER='pspg -s 14 -X --force-uniborder --quit-if-one-screen -s 16' \
  372. mycli --password "$(pass show majordomo/public/web/mysql/root)" -d "${2%.intr}"
  373. ;;
  374. esac
  375. ;;
  376. clean)
  377. echo "Kill MySQL connections"
  378. host="${2:-127.0.0.1}"
  379. user="root"
  380. password="$(pass show majordomo/public/web/mysql/root)"
  381. (
  382. set +e
  383. for id in $(mysql --silent --user="$user" --password="$password" --host="$host" --execute="SELECT id FROM information_schema.processlist WHERE user like 'u%'"); do
  384. echo "$id"
  385. mysql --silent --user="$user" --password="$password" --host="$host" --execute="kill $id;"
  386. done
  387. )
  388. ;;
  389. ip-filter)
  390. if ! OPTS="$(getopt --options arHhd --long add:,remove:,host:,help,describe --name parse-options -- "$@")"
  391. then
  392. echo "Failed parsing options."
  393. exit 1
  394. fi
  395. eval set -- "$OPTS"
  396. while true; do
  397. case "$1" in
  398. -h | --help )
  399. help_ip_filter
  400. exit 0
  401. ;;
  402. -H | --host )
  403. IP_FILTER_HOST="$2"
  404. shift 2
  405. ;;
  406. -a | --add )
  407. IP_FILTER_HOST_ADD="$2"
  408. shift 2
  409. ;;
  410. -r | --remove )
  411. IP_FILTER_HOST_DELETE="$2"
  412. shift 2
  413. ;;
  414. -d | --describe)
  415. IP_FILTER_HOST_DESCRIBE="$2"
  416. shift
  417. ;;
  418. -- )
  419. shift
  420. break
  421. ;;
  422. ,* )
  423. break
  424. ;;
  425. esac
  426. done
  427. if [ -n "$IP_FILTER_HOST_DESCRIBE" ]
  428. then
  429. echo "name: ip-filter-$IP_FILTER_HOST"
  430. echo -n "blocked: "
  431. curl --silent --request GET "$IP_FILTER_HOST/ip-filter" \
  432. | cut -d' ' -f 1 | sort --numeric-sort | xargs echo
  433. exit 0
  434. fi
  435. if [ -n "$IP_FILTER_HOST_DELETE" ]
  436. then
  437. curl --silent --head --request DELETE "$IP_FILTER_HOST/ip-filter/$3?ttl=7200&action=setCookie"
  438. fi
  439. if [ -n "$IP_FILTER_HOST_ADD" ]
  440. then
  441. curl --silent --head --request PUT "$IP_FILTER_HOST/ip-filter/$2?ttl=7200&action=setCookie"
  442. fi
  443. ;;
  444. protected)
  445. password="$(pass show majordomo/public/web/protected/token)"
  446. for domain in $(PYTHONPATH= grafana --host "$2")
  447. do
  448. if [[ -n $TTL ]]
  449. then
  450. echo curl -H"'Authorization: ${password}'" --include --request PUT "${2}/protected/${domain}?ttl=${TTL}"
  451. echo curl -H"'Authorization: ${password}'" --include --request PUT "${2}/protected/www.${domain}?ttl=${TTL}"
  452. else
  453. echo curl --include --request PUT "${2}/protected/${domain}"
  454. echo curl --include --request PUT "${2}/protected/www.${domain}"
  455. fi
  456. done
  457. ;;
  458. te)
  459. ssh_expect "$2" tail --lines="${3:-1000}" /var/log/taskexecutor.log \
  460. | grep -v 'malware_report' \
  461. | sed '/^[[:space:]]*$/d'
  462. ;;
  463. apache)
  464. ssh_expect "${2%.intr}" sh -c "'cat /home/$4/logs/*access.log'"
  465. ;;
  466. deploy)
  467. host="$2"; [[ "$host" == *.intr ]] || host+=.intr
  468. ansible-playbook --limit "$host" --ask-become-pass "$HOME/bin/web-docker-pull"
  469. ;;
  470. ip)
  471. case "$3" in
  472. a*)
  473. connect ssh "$2" -- ip -color=always address
  474. ;;
  475. r*)
  476. connect ssh "$2" -- ip -color=always route
  477. ;;
  478. *)
  479. connect ssh "$2" -- ip -color=always address
  480. connect ssh "$2" -- ip -color=always route
  481. ;;
  482. esac
  483. ;;
  484. uptime)
  485. connect ssh "$2" -- uptime | jc --uptime
  486. ;;
  487. ns)
  488. printf "NOTE: No expired and registrant are checked.\n\n"
  489. for ns in ns ns2 ns3 ns4
  490. do
  491. dig +short MX yacrm.ru @$ns.majordomo.ru
  492. echo ""
  493. done
  494. ;;
  495. php)
  496. parallel --will-cite -k 'printf "name: %s\n" apache2-{2}-{3}; curl --max-time 10 -L -s -o /dev/null -w "ip_address: %{remote_ip}\nstatus_code: %{http_code}" http://{1}/apache2/{2}/{3}/phpinfo.php; printf "\n\n"' ::: \
  497. "$2" ::: \
  498. "php44" "php52" "php53" "php54" "php55" "php56" "php70" "php71" "php72" "php73" "php74" "php80" ::: \
  499. "default" "unsafe" "hardened" "hardened_nochmod" \
  500. | recsel -e 'status_code != 200 && name != "apache2-php44-default" && name != "apache2-php44-unsafe" && name != "apache2-php44-hardened" && name != "apache2-php44-hardened_nochmod" && name != "apache2-php80-unsafe" && name != "apache2-php80-hardened" && name != "apache2-php80-hardened_nochmod"'
  501. ;;
  502. esac