blog.serverclub.ru
Блог компании ServerClub

Запуск локальных ssh/telnet/vnc клиентов по ссылке из карты Zabbix

10 марта 2014 г. Просмотров: 1683 RSS

Множество стоек, каждая плотно упакована серверами, маршрутизаторами, коммутаторами и прочими kvm'ами. Нужен какой-нибудь удобный способ рулить всем этим хозайством, быстро подключаться к нужному оборудованию и производить его настройку. Прямо чтобы пара кликов мышью и оп - перед тобой консоль нужного коммутатора.

Для мониторинга наших подопечных мы используем Zabbix. Так почему бы не приспособить сей дивный инструмент и для этой задачи. Ведь было бы очень удобно ткнуть в карте Zabbix на нужную стойку, перейти на её подкарту и, выбрав железку, запустить локальный ssh/telnet/vnc клиент на своем компьютере.

Озадачившись идеей, я начал мучать поисковые машины в надежде отыскать варианты реализации. Был найден данный тред на форуме Zabbix, но мне хотелось запускать именно локальные программы на моей машине кликом по ссылке в карте. Еще некоторое время поплутав по закоулкам всемирной паутины и помучав знакомых программистов глупыми вопросами я вспомнил о... Python.

Да, Python, не раз пришедший на помощь в трудную минуту. Питаю очень нежные чувства к этому языку за его простоту и приятный теплый синтаксис.

И так, вектор атаки изменился и поисковики замерли в ожидании нового вброса мыслеобразов...

Спустя некоторое время я уже четко представлял как буду решать задачу - напишу клиент-серверное приложение!

На моем компьютере будет ждать команд серверная часть, а на сервере мониторинга, при клике по ссылке, будет запускаться клиент и передавать нужную команду.

Результатом изысканий стало кроссплатформенное приложение, работает как на Linux, так и на Windows.

Эпопея проб и ошибок на пути к заветной цели ждет вас под катом.

Пролог

Начало пути.

В первую очередь отмечу, что синтаксис написанного справедлив для Python версии 2.7.

А версия Zabbix насчитала три двойки - Zabbix 2.2.2

Отвечать за коммуникацию клиента и сервера поручено Python библиотеке socket.

Помимо документации мне были полезны следующие источники:

1. http://www.binarytides.com/python-socket-programming-tutorial/

2. http://www.binarytides.com/code-chat-application-server-client-sockets-python/

3. http://java-developer.livejournal.com/6920.html

Наигравшись с примерами, подготовим основу будущего приложения.

Клиент:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
sock = socket.socket()
sock.connect(('localhost', 9090))
sock.send('/usr/bin/konsole -e  mc')
sock.close()

И сервер:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import subprocess
sock = socket.socket()
sock.bind(('localhost', 9090))
sock.listen(1)
while True:
        conn, addr = sock.accept()
        data = conn.recv(1024)
        if not data:
                break
        subprocess.call(data, shell=True)
conn.close()

Запущеный сервер "слушает" порт 9090 на интерфейсе обратной петли, выполнив клиента мы передаем команду для запуска новой консоли, а параметр -e mc указывает, что в консоли нужно запустить файловый менеджер midnight commander.

Краткая демонстрация

*Основной ОС для меня является Linux, а в качестве DE выступает KDE, но пусть вас это не смущает, итоговый вариант скриптов не будет привязан к ОС.

Основа положена, двигаемся далее!

Глава 1

В этой главе клиент научится понимать аргументы командной строки и мы отправим серверу первую команду с карты Zabbix.

Код серверной части пока не претерпел никаких изменений, а вот в код клиента добавился импорт библиотеки sys.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import sys
sock = socket.socket()
sock.connect(('localhost', 9090))
sock.send('/usr/bin/konsole -e ssh root@'+ sys.argv[1])
sock.close()

Сервер должен будет запустить консоль и инициировать подключение по ssh к IP из первого аргумента переданного клиенту.

Логином выступает root .

А теперь пришло время поместить скрипт клиента на сервер мониторинга.

В моем случае он уютно устроился здесь - /usr/local/bin/client.py

В веб интерфейсе Zabbix перейдем в Administration -> Scripts.

Создадим новый скрипт(Create new).

Через Zabbix макрос {HOST.IP} клиенту передается IP для подключения.

Перейдя на карту увидим, что у хостов появилось меню с именем вновь созданного скрипта.

Многие справедливо заметят - "Скрипт клиента до сих пор соединяется с localhost, но он же уже на сервере?!"

Все верно! Но для защиты взаимодействия сервера и клиента используется ssh туннель.

Все соединения устанавливаемые на localhost:9090 Zabbix сервера на самом деле устанавливаются со скриптом сервера на нашей локальной машине.

Для достижения такого "зеркалирования" на локальном компьютере нужно выполнить команду:

ssh -f -N -R 9090:127.0.0.1:9090  zabbix

Подробнее о ssh, и тоннелях в часности, можно прочесть в замечательных статьях на хабре - 1, 2

Видеоиллюстрация к первой главе

Глава 2

В этой главе скрипты еще немного поумнеют и научатся отличать Windows от Linux.

Идея состоит в том, чтобы клиент при соединении с сервером первым делом узнавал на какой ОС тот запущен.

И, получив это информацию, отдавал правильную команду.

Код обоих скриптов изменился.

Клиент:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import sys
sock = socket.socket()
sock.connect(('localhost', 9090))
os = sock.recv(64)
if  os == "Windows":
    sock.send('C:\\apps\\putty.exe -ssh root@' + sys.argv[1])
elif os == "Linux":
    sock.send('/usr/bin/konsole -e ssh root@'+ sys.argv[1])
sock.close()

Сервер:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import subprocess
OS = "Linux"
sock = socket.socket()
sock.bind(('127.0.0.1', 9090))
sock.listen(1)
while True:
    conn, addr = sock.accept()
    conn.sendall(OS)
    data = conn.recv(1024)
    print data
    if not data:
        break
    subprocess.call(data, shell=True)
conn.close()

* для Windows переменная OS должна быть изменена соответствующе

Как видно, при коннекте к серверу клиент перво-наперво получает строку с названием ОС, и только потом посылает команду.

Обратите внимание, что бекслэши в путях для ОС Windows нужно экранировать, т.е. ставить двойной \\

Видео ко второй главе

На видео:

"зеркалируем" порт в Windows запустив putty

запускаем сервер

кликаем ссылку для соединения с хостом

отключаем все в Windows и проделываем то же самое в Linux

Глава 3

В этой главе мы немного подправим код фронтенда Zabbix.

Научим его передавать скрипту-клиенту вторым аргументом логин зарегистрированного на веб интерфейсе администратора/оператора.

Вроде бы все здорово и уже сейчас можно пользоваться наработками для соединения с серверами, маршрутизаторами, коммутаторами.

Но что если администраторов, пользующихся Zabbix, больше одного?

Нам нужно каким-то образом дать понять скрипту кто его запустил, попросту говоря кто "ткнул" ссылку в веб интерфейсе.

Решать будем поэтапно.

  • Закрепим за каждым администратором определенный порт.
  • Научим скрипт-клиент выбирать порт в зависимости от второго аргумента - логина.
  • Изменим код Zabbix для передачи второго аргумента при клике по ссылке из веб интерфейса.

Порты:

Admin - 9090

Admin1 - 9091

и т.д.

Код скрипта-клиента с нужными изменениями:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import sys
if sys.argv[2] == 'Admin':
        PORT=9090
elif sys.argv[2] == 'Admin1':
        PORT=9091
sock = socket.socket()
sock.connect(('localhost', PORT))
os = sock.recv(64)
if  os == "Windows":
        sock.send('C:\\apps\\putty.exe -ssh root@' + sys.argv[1])
elif os == "Linux":
        sock.send('/usr/bin/konsole -e ssh root@'+ sys.argv[1])
sock.close()

А вот решить последнюю задачу, в рамках данной главы, оказалось не так просто.

Пришлось существенно увеличить лимит кофе на эту смену и даже умыкнуть кота у жены из под бока.

Кофе был выпит, кот, промурлыкав положенное, давно свалил, а я ни на йоту не приблизился к решению...

Но ощущение близости отгадки не давало мне покоя, оно крепко вцепилось в мой мозг своими клешнями, и я знал, что яблоко вот-вот должно свалиться мне на голову.

И оно свалилось!(не в прямом смысле конечно)

Работающий вариант, как это часто бывает, был практически на поверхности.

Для выполнения всех скриптов, вызванных из веб интерфейса, используется scripts_exec.php, расположеный в корневом каталоге установленного Zabbix.

Описание скриптов хранится в MySQL базе.

Значит исправив должным образом scripts_exec.php мы сможем передавать логин как второй аргумент для нашего скрипта-клиента при клике по ссылке.

Код и описание исправленного scripts_exec.php под спойлером

Показать...

А вот как это выглядит:

Смотреть лучше без звука, ноут у меня разбушевался уж очень)

Глава 4

В этой главе мы научим Zabbix запускать vnc и telnet клиентов.

Поговорим о скриптах-клиентах для прочих, перечисленных в заголовке, протоколов.

Листинг директории /usr/local/bin на Zabbix сервере :

-rwxr-xr-x 1 root staff 429 Mar 17 03:06 client_ssh.py
-rwxr-xr-x 1 root staff 418 Mar 17 04:58 client_telnet.py
-rwxr-xr-x 1 root staff 412 Mar 17 05:00 client_vnc.py

Листинг каждого скрипта-клиента под спойлером

Показать...

Подробно останавливаться на коде не будем, в предыдущих главах это уже было сделано.

Скажу лишь, что для Windows я скачал portable версию vnc клиента и положил все в c:\apps\

Для telnet и vnc из скриптов нужно повторить шаги из главы 1, в веб интерфейсе Zabbix, а для ssh достаточно скорректировать название.

Файл scripts_exeс.php так же нуждается в изменении.

Вновь измененный код scripts_exeс.php

Показать...

Уже традиционное видео.

Здесь тоже лучше без звука.

Заключение.

Наведем порядок и придадим некоторый лоск нашей разработке.

Строго говоря, здесь кросплатформеность и заканчивается.

Для ОС Linux, из множества примеров, был собран демон на Python.

Он выполняет дабл форк и преспокойно ждет команд от скриптов-клиентов.

В ОС Windows все оказалось сложнее, но, обо всем по порядку.

Листинг директории с необходимыми скриптами для ОС Linux:

fessae@workbook:~/sh/python > pwd
/home/fessae/sh/python
fessae@workbook:~/sh/python > ll
total 12
-rwxr-xr-x 1 fessae fessae 2880 Feb 28 02:56 daemon.py*
-rwxr-xr-x 1 fessae fessae  710 Mar 17 03:36 server.py*
-rwxr-xr-x 1 fessae fessae 1122 Mar 13 04:59 ZabbixTeams.py*

Код каждого из скриптов серверной части Linux

Показать...

Для запуска демона набираем

python ZabbixTeams.py start

Для остановки соответственно

python ZabbixTeams.py stop

Обратите внимание на строку

sys.path.append("/home/fessae/sh/python")

из ZabbixTeams.py, она подключает врзможность импортировать скрипты из этого каталога.

Исправьте её в соответствии вашему окружению.

Получившийся демон можно стартовать руками, прилипить иконку для его запуска, завернуть в австостарт DE или ОС.

Это уже кому как нравится.

ОС Windows.

Для написания/исправления кода я пользовался Python IDE PyCharm, поэтому и скрипты разместились по пути:

Правильнее, конечно, было бы написать сервис для этой ОС при помощи pywin32.

Но в скриптах использованы блокирующие сокеты и не отказавшись от них полноценный сервис у меня не получался.

Возможно позже я возьмусь за asyncore или вообще перепишу все на twisted, но пока мне не хотелось усложнять.

Поэтому запуск демона на Windows выглядит следующим образом:

Показать...

Итоговое видео.

*со звуком все в порядке ;)

Благодарю за внимание.

twitter.com facebook.com vkontakte.ru odnoklassniki.ru mail.ru ya.ru pikabu.ru blogger.com liveinternet.ru livejournal.ru google.com yandex.ru