- PVSM.RU - https://www.pvsm.ru -

Готовим свой UI-интерфейс к Zabbix API средствами React component

Всем привет!

Все началось с интеграции телефонной платформы в корпоративный сайт.

Будучи инженером VoIP телефонии, WEB-разработка поразила разнообразием подходов и методов реализации. Стек технологий пестрит разнообразием, выбор инструментов определяет стиль разработки, модульность или закостенелость проекта.

Про телефонную платформу я напишу в следующий раз. Сильный уклон в VoIP-специфику отвлечет от главного — методов разработки современного SPA [1]-приложения.

В статье будет описан процесс внедрения стороннего сервиса в существующую рабочую среду.

Сегодня поиграемся с Zabbix-API [2].

image

Live Demo [3]

Кому будет интересно

Тем кто лет десять назад реализовал WEB-интерактив средствами CGI-скриптов на серверной стороне, и хочет понять современные подходы. Если Вам приходилось выдумывать собственные API-интерфейсы, заниматься документацией того что получилось — решение ниже.

Ставим задачу

Первичная настройка Zabbix ведется через встроенный WEB-интерфейс. Рутина обычно сводится к простому добавлению хостов в группу.

Учет оборудования (добавление хостов) мы ведем в собственной системе на корпоративном сайте.

  • Было бы не плохо интегрировать рутинные задачи Zabbix в существующую среду учета. Свести к минимуму количество параметров, в идеале одна кнопка «добавить»

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

  • Было бы неплохо выдать им функционал в виде готового модуля. В идеале пара строчек кода «import ...» и «render ...»
  • Постараться использовать современный стек технологий, желательно стандартные интерфейсы взаимодействия

Стек технологий

ReactJS

Пользовательский интерактив классически описан схемой работы MVC [4] с ее вариациями. Изучая матчасть появились кандидаты Vue [5], Ember [6], Meteor [7], Angular [8], ReactJS [9].

Пришло понимание, что большинство фреймворков/библиотек пытается реализовать полную экосистему MVC с реализацией как на front-end так и back-end [10], называют это «full stack».
React — это только «V» от «MVC». Погружаться в чужую экосистему не хотелось, а вот простая рисовалка очень приглянулась. Порадовала перспектива со временем перескочить в React Native [11]: один код для Web, IOS, Android. А подключив Redux [12], должен получиться full stack. Отдельно порадовал JSX, киллер-фича IMHO.

JSX

JSX [13] -детище разработчиков React — синтаксическая надстройка над JavaScript, визуально упрощает работу с DOM [14]-элементами браузера.
Матерые WEB-разработчики ругают его за то, что он перемешивает HTML разметку и JavaScript код. Я не матерый разработчик и JSX считаю отличным решением.

NodeJS

Сначала казалось удобным писать на «браузерном» JavaScript. Правда там неудобно разбивать проект на модули и подгружать необходимые. Проблему решил пакетный менеджер Bower [15]. Там своя философия, Bower заботится чтобы версии модулей не конфликтовали друг с другом.

На практике оказалось что все необходимые инструменты доступны в виде npm [16] пакетов. Если нужный модуль не доступен в виде npm пакета, Bower хорошее дополнение.

Итог. Пишем на Node, используем пакетный менеджер npm.

Browserify

NodeJS [17] это серверный JavaScript, не браузерный. Хорошие люди придумали транспайлер [18] Browserify [19] который переделывает Node-код в браузерный вариант.

Babel

Браузеры не отличаются высокой скоростью обновления встроенного JavaScript движка. Хотелось бы использовать весь «сахар» современного JavasScript, отсюда еще один инструмент — Babel [20]. Транспайлер который умеет работать с последними версиями ECMAScript [21]. А еще, именно он будет распознавать JSX-синтаксис.

Gulp

Помимо работы с JavaScript современная WEB-страничка плотно использует CSS [22], которые перешли на новый уровень абстракций SASS [23]. Подгружаются собственные шрифты и картинки. HTML-текст может быть раскидан по различным файлам. В итоге, построение финального проекта сводится к десятку действий над различными файлами, разбросанными по файловой системе в разнообразном порядке.

Gulp [24] это сборщик. По сути, обычный Node скрипт, в котором автоматизированы действия обработки исходных файлов проекта.
Я выбрал Gulp, в свое время понравился принцип его работы: поточная обработка, это быстро. Он выигрывал у Grunt [25], а еще попалась статья Insayt [26], на базе которой я и сделал свой gulpfile.js [27].

В качестве альтернативы, есть смысл рассмотреть webpack [28], я не пробоавл.


Здесь стоит заметить — основные инструменты для разработки front end мы перечислили. Теперь очередь за back end.

Но сначала, сформулируем принцип работы нашей будущей React-компоненты и Zabbix-API.

Цель

  • Взаимодействие Front-Back свести до простейших REST [29]-запросов
  • Сосредоточить всю логику взаимодействия с Zabbix-сервером на back end
  • Желательно стандартный интерфейс + документация

Можно было бы взгромоздить всю логику на front end, но это плохо:

  1. Zabbix-API придется открыть для всех клиентских браузеров. Безопасней открывать отдельный ресурс с ограниченным набором действий
  2. Создаем общее решение, способное работать с кардитально разными системами: SNMP-датчиками, telnet-сессиями, с ресурсами ОС серверов и проч. (Zabbix — лишь одна из реализаций). Браузер просто не имеет подобного функционала

Итог. Нужен «умный» back end, имеющий свой API.

Еще немножко технологий

OpenAPI

При интеграции в телефонную платформу были пройдены первые «грабли». Был написан свой собственный API-сервер. Он работал. Успешно «рулил» софтсвичем, принимал REST-запросы которые по сути не являлись REST. Никакой документации по формату, методам и параметрам запросов не было.

Такая ситуация породила интерес, можно ли как-то формализовать API-интерфейс, чтобы документация формировалась автоматически? Приглянулся подход OpenAPI [30].

Суть сводится к тому, что сначала надо написать файл спецификации, в котором будут описаны все методы, поля, форматы ответов и т.п. Потом на базе этого файла можно сгенерировать готовый API-сервер. Список языков впечатляет, мы сделаем на NodeJS.

Так-как файл спецификации стандартный, для него уже придуманы инструменты: Swagger [31], ReDoc [32], OA Viewer [33],… подробней здесь [34]. Вопрос с документацией решается автоматически — это и есть файл спецификации.

Docker

Совсем скоро мы начнем писать исполнимый код. Скрипты будут на языке NodeJS. Любой язык эволюционирует, меняются версии, было бы неплохо пробовать результат на разных версиях языка. В каждом языке есть спец.инструменты для «жонглирования» версиями.

Я поступаю радикальней. Есть отличная технология LXC [35], предлагающая очень легкую виртуализацию на уровне ядра Linux. Грех было бы ей не воспользоваться. В случае с другими ОС есть своя специфика, разработчики учли нюансы и создали продукт Docker [36].

Необходимую среду разработки мы будем строить в нужном Docker-контейнере.

Приступим

Проект доступен на Github [37]

git clone https://github.com/ars-anosov/zabbix-react.git

zabbix-reactor-node

Back end сервер назовем «zabbix-reactor-node». Просматриваем файл спецификации. Проверяем поле «host».

less zabbix-react/node-back/api/zabbix-api.yaml

Если разворачиваем сервер на своей машине

host: 'localhost:8002'

Сервер собран при помощи swagger editor [38] на базе «zabbix-api.yaml». Структура такова:

index.js — стартовый скрипт

var app = require('connect')()
var swaggerTools = require('swagger-tools')
var http = require('http')

  • http — WEB-сервер
  • connect при помощи middleware swagger-tools — обработка запросов

  // Route validated requests to appropriate controller
  app.use(middleware.swaggerRouter(options));

  // Serve the Swagger documents and Swagger UI
  app.use(middleware.swaggerUi({
    apiDocs: '/spec/swagger.json',
    swaggerUi: '/spec-ui'

Методы:

  • middleware.swaggerRouter — роутер, прокидывает запросы на соответствующий контроллер в директории zabbix-react/node-back/controllers
  • middleware.swaggerUi — инструмент SwaggerUI. Это и есть наша документация к API, позволяет выполнять тестовые REST-запросы

controllers/ — скрипты отвечающие за обработку API-запросов

Configuration.js
Data.js
config_host_del.js
config_host_get.js
config_host_post.js
config_host_put.js
config_hostgroup_get.js
data_hostlink_get.js

Именно здесь наполняем логикой наши взаимодействия с Zabbix-API.

В Docker-контейнер будет прокинута директория «node-back»: переходим в нее.

cd zabbix-react/node-back/

Запускаем «zabbix-reactor-node». Передаем в контейнер переменные окружения ZX_URL, ZX_USER, ZX_PASS — вбиваем свои, если есть свой Zabbix. В качестве примера можете использовать мой тестовый Zabbix:

docker run 
  --name zabbix-reactor-node 
  -v $PWD:/zabbix-reactor-node 
  -w /zabbix-reactor-node 
  --publish=8002:8002 
  --env="ZX_URL=http://zabbix-server.react.com.ru/api_jsonrpc.php" 
  --env="ZX_USER=guest" 
  --env="ZX_PASS=" 
  -it 
  node:8 bash

Старые версии заббикса могут принимать запросы на другом URL. Смотрим Zabbix doc. [39]

Дальше все действия внутри контейнера.

npm install
node index.js $ZX_URL $ZX_USER $ZX_PASS

Выскочить из контейнера: Ctrl+P+Q

Проверяем доступноать SwaggerUI — http://localhost:8002/spec-ui/ [40]
В поле «token» вписываем «test». Здесь будет токен авторизации, его проверкой занимается скрипт node-back/sub_modules/aaa_handle.js.

Zabbix настройки

Мы хотим открыть доступ только к определенным Host group на Zabbix. Для этого необходимо создать отдельного пользователя «react_user».

  1. Administration/User groups — добавляем группу пользователей «react_user_group»
  2. Administration/User groups/Permissions — добавляем Host groups, с которыми будет позволено работать «react_user». Выставляем Read-write.
  3. Administration/Users — добавляем пользователя, включаем в группу пользователей созданную в пп.1
  4. Administration/Users/Permissions — User type выставляем «Zabbix Admin»

zabbix-react-front

Строим среду разработку назовем ее «zabbix-react-front».
В Docker-контейнер будет прокинута директория «web-front»: переходим в нее.

cd zabbix-react/web-front/

Запускаем «zabbix-react-front»:

docker run 
  --name zabbix-react-front 
  -v $PWD:/web-front 
  -w /web-front 
  --publish=8003:8003 
  -it 
  node:8 bash

Дальше все действия внутри контейнера.

# глобально устанавливаем gulp-cli
npm install -g gulp-cli

# Теперь все необходимое (транспайлеры, утилиты, плагины)
npm install

Компоненты находятся в директории web-front/src/js/components, они имеют свои зависимости.

Устанавливаем:

npm run install-components

Собираем проект в директорию web-front/build

gulp

Выскочить из контейнера: Ctrl+P+Q

Проверяем работу компонент — http://localhost:8003/ [41]

zabbix-react-component

Вот мы и добрались до работы с компонентами. Посмотрим что сейчас запущено.

  • zabbix-reactor-node — OpenAPI-сервер, открыт для приема REST-запросов на http://localhost:8002/... [42]
  • zabbix-react-front — livereload-web-сервер для отображения React-компонент, рисует на http://localhost:8003/ [41]

Работаем со следующей структурой файлов:

web-front/src/index.jsx — JSX-скрипт с компонентами

import React from 'react';
import ReactDOM from 'react-dom'
import { OpenApiSwagger, HostConfig, HostGraph } from './components/zabbix-react-component'

window.localStorage.setItem('token', 'test')


const specUrl = 'http://localhost:8002/spec/swagger.json'
const swg = new OpenApiSwagger(specUrl)

swg.connect((client, err) => {
  if (err) {
    ReactDOM.render(
      <div className='std-win'>no spec - <a href={specUrl}>{specUrl}</a> !</div>,
      document.getElementById('root')
    )
  }
  else {
    ReactDOM.render(
      <div>
        <HostConfig swgClient={client} />
        <HostGraph swgClient={client} />
      </div>,
      document.getElementById('root')
    )
  }
})

  • specUrl — путь к файлу спецификации на zabbix-reactor-node

web-front/src/components/ — директория с компонентами

web-front/src/components/zabbix-react-component.js — экспортируемые классы

export { OpenApiSwagger }       from './OpenApiSwagger.js'
export { HostConfig }           from './HostConfig.jsx'
export { HostGraph }            from './HostGraph.jsx'

С этого места можно смело ваять свои компоненты, наращивать функционал.
В качестве примера, приделал инструмент, который есть в Nagios [43] но отсутствует в Zabbix. Автоматическое построение карты сети на базе мета-информации «source-target» в описании элементов сети.

Смотрим компоненту HostGraph. Для хранения информации использую в Zabbix Host закладку «Host inventory» поле «Notes». Туда в JSON-формате заносим связки элементов «source-target». Для визуализации использовал проект d3 [44]Force-Directed Graph [45].

Заключение

Теперь у нас в руках находится среда разработки, front-end и back-end. Для работы достаточно знания JavaScript и специфики NodeJS.

API-документирован и доступен для тестирования сторонними front-end разработчиками. API-сервер не привязан именно к Zabbix, это общее решение. Возможна интеграция к любой системе.

Собраны готовые React-компоненты выполняющие стандартные CRUD [46] функции. Компоненты освобождены от сложностей взаимодействия с интегрируемыми системами, только отображение.

Автор: Арсений

Источник [47]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/nodejs/270000

Ссылки в тексте:

[1] SPA: https://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5

[2] Zabbix-API: https://www.zabbix.com/documentation/3.2/manual/api

[3] Live Demo: http://zabbix.react.com.ru/

[4] MVC: https://ru.wikipedia.org/wiki/Model-View-Controller

[5] Vue: https://vuejs.org/

[6] Ember: https://www.emberjs.com/

[7] Meteor: https://www.meteor.com/

[8] Angular: https://angularjs.org/

[9] ReactJS: https://reactjs.org/

[10] front-end так и back-end: https://ru.wikipedia.org/wiki/Front_end_%D0%B8_back_end

[11] React Native: https://facebook.github.io/react-native/

[12] Redux: https://redux.js.org/

[13] JSX: https://reactjs.org/docs/introducing-jsx.html

[14] DOM: https://ru.wikipedia.org/wiki/Document_Object_Model

[15] Bower: https://bower.io/

[16] npm: https://www.npmjs.com/

[17] NodeJS: https://nodejs.org/en/

[18] транспайлер: https://en.wikipedia.org/wiki/Source-to-source_compiler

[19] Browserify: https://www.npmjs.com/package/browserify

[20] Babel: https://babeljs.io/

[21] ECMAScript: https://ru.wikipedia.org/wiki/ECMAScript

[22] CSS: https://ru.wikipedia.org/wiki/CSS

[23] SASS: https://ru.wikipedia.org/wiki/Sass

[24] Gulp: https://gulpjs.com/

[25] Grunt: https://gruntjs.com/

[26] Insayt: https://habrahabr.ru/users/insayt/

[27] gulpfile.js: https://github.com/ars-anosov/zabbix-react/blob/master/web-front/gulpfile.js

[28] webpack: https://webpack.js.org/

[29] REST: https://ru.wikipedia.org/wiki/REST

[30] OpenAPI: https://www.openapis.org/

[31] Swagger: http://petstore.swagger.io/

[32] ReDoc: http://rebilly.github.io/ReDoc/

[33] OA Viewer: https://koumoul.com/openapi-viewer

[34] здесь: https://github.com/OAI/OpenAPI-Specification/blob/master/IMPLEMENTATIONS.md

[35] LXC: https://ru.wikipedia.org/wiki/LXC

[36] Docker: https://www.docker.com/

[37] Github: https://github.com/ars-anosov/zabbix-react

[38] swagger editor: https://editor.swagger.io/

[39] Zabbix doc.: https://www.zabbix.com/documentation/2.2/ru/manual/api

[40] http://localhost:8002/spec-ui/: http://localhost:8002/spec-ui/

[41] http://localhost:8003/: http://localhost:8003/

[42] http://localhost:8002/...: http://localhost:8002/spec/swagger.json

[43] Nagios: https://www.nagios.org/

[44] d3: https://d3js.org/

[45] Force-Directed Graph: https://bl.ocks.org/mbostock/4062045

[46] CRUD: https://ru.wikipedia.org/wiki/CRUD

[47] Источник: https://habrahabr.ru/post/344040/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox