Доброго времени суток, в общем, в компании, в которой я работаю, используется Ivideon-server версии 3.9.0 либо 3.12.0. И появилась огромная потребность в мониторинге камер: их доступности, а также, пишется ли архив с этих камер. Поэтому я начал разработку шаблона Zabbix, который бы опрашивал сервера с Ivideon-server по API. Начал я с того, что с помощью WireShark я разобрал работу Ivideon Client.
Готовые шаблоны закреплю в конце статьи. А в статье постараюсь разобрать как они работают.
Первый запрос, что я смог вытащить и считаю его основным: http://IP-Адрес сервера/streams/info?server=1&sessionId=пароль от сервера, при отправке которого мы получаем JSON ответ:
[{
"achannels" : 0,
"acodec" : "none",
"afreq" : 0,
"archive" : {
"edge" : false,
"internal_speed_play" : false,
"key_frame_seek" : true,
"smooth_speed_play" : 4,
"speeds" : [ 1, 2, 4, 8, 16, 32, 64 ],
"writable" : true
},
"custom_device_info" : {
"fw_version" : "2.800.0000000.12.R 2021-04-30",
"hardware_id" : "1.00",
"ipv4" : "19.44.0.27",
"model" : "DH-IPC-HDW1230T1P-0280B",
"name" : "401 ближний кабинет",
"serial_number" : "",
"serial_number_format" : "onvif",
"vendor" : "Dahua"
},
"features" : {
"analytics_info" : { }
},
"height" : 960,
"id" : 1245184,
"instance_id" : "",
"is_forced_as_active" : false,
"is_turned_off" : false,
"name" : "401 ближний кабинет",
"online" : true,
"preview" : {
"0" : false,
"1" : false,
"2" : false
},
"record" : {
"scheduled" : true,
"type" : "continuous"
},
"sources" : {
"0" : null,
"1" : "rtsp://admin:viewer121@0.0.0.0/cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif",
"2" : "rtsp://admin:viewer121@0.0.0.0/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"
},
"status" : 1,
"streams" : {
"0" : false,
"1" : true,
"2" : true
},
"vcodec" : "h265",
"width" : 1280
}]Здесь уже есть большая часть необходимых нам данных, IP‑Адреса камер в элементе «ipv4» а также их статус «status» где 0 — не работает 1 — работает.
Далее в Zabbix в шаблоне создается элемент данных, который как раз и будет опрашивать предполагаемый узел:

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


Все полученные данные из JSON записываются в LLD Макросы.

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

Создано 2 прототипа элемента данных,
CAMERA [{#NAME}]: Get record status
Получение состояние записи камеры, ведет ли она архивную запись
Ivideon Get Data: CAMERA [{#NAME}]: Get Status
Получение статуса камеры
![Ivideon Get Data: CAMERA [{#NAME}]: Get Status Ivideon Get Data: CAMERA [{#NAME}]: Get Status](https://habrastorage.org/r/w1560/getpro/habr/upload_files/1ea/ce5/d13/1eace5d13e82964ac61cbf3fa325695d.png)
Это зависимый элемент данных, он ссылается на созданный ранее основной элемент данных, где происходит получение JSON ответа.

Теперь разберем, как шаблон получает состояние записи архива камеры с помощью прототипа элемента данных CAMERA [{#NAME}]: Get record status
![CAMERA [{#NAME}]: Get record status CAMERA [{#NAME}]: Get record status](https://habrastorage.org/r/w1560/getpro/habr/upload_files/962/149/5d8/9621495d8cad67e6020f668ff2f20479.png)
Этот элемент данных имеет тип скрипт, мною сделан небольшой Java скрипт который отправляет запрос на сервер по камере.
var obj = JSON.parse(value);
var host_ip = obj.hostip;
var camera_id = obj.cameraid;
var ivideon_pass = obj.ivideon_password
var request = new HttpRequest();
var nowUnix = Math.floor(Date.now() / 1000);
var timestamp_offset = nowUnix - 10800
var url = "http://" + host_ip + ":8080/archive/list"
+ "?startTime=" + timestamp_offset
+ "&endTime=" + nowUnix
+ "&server=1&sessionId=" + ivideon_pass
+ "&camera=" + camera_id;
var data = JSON.parse(request.get(url));
if (Array.isArray(data) && data.length === 0) {
return 0;
} else {
return 1;
}В параметрах прототипа данных указывается все те макросы, что мы вытащили ранее.
Теперь когда у нас есть данные можно делать прототипы триггеров.

Camera {#NAME} archive not recording — ведется ли архив
Camera {#NAME} is unavailable — статус камеры

Скрипт созданный ранее имеет 2 варианта ответа, 0 — архив не ведется 1 — архив пишется, соответственно, в прототипе триггера для его срабатывания он должен получить 0, тогда триггер сработает.

В прототипе Camera {#NAME} is unavailable применяется тот же принцип 0 — не работает 1 — работает.
На этом шаблон готов. Далее создаем узел сети с применением этого шаблона.

Тип интерфейса SNMP. Также необходимо указать в макросах узла сети следующий макрос: {$IVIDEON_PASSWORD}, в значение записать пароль используемый для подключение к Ivideon-server.

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

Сразу после появления элементов данных правило обнаружения создает триггеры по каждому элементу данных.

На этом всё, все работы и тестирование проводились с версиями: Zabbix 7.4, ivideon‑server 3.9 и ivideon‑server 3.12.0.
Готовый шаблон для версии Ivideon — server 3.9.0.
zabbix_export:
version: '7.4'
template_groups:
- uuid: d37f71c7e3f7469bab645852a69a2018
name: 'Templates/Video surveillance'
templates:
- uuid: d8d1bbd1d20346f7bb5153d23f024150
template: 'ivideon-server 3.9 HTTP'
name: 'ivideon-server 3.9 HTTP'
groups:
- name: 'Templates/Video surveillance'
items:
- uuid: a8047c121f154cf2a37ff3a50d2cf52c
name: 'Ivideon Get Data'
type: HTTP_AGENT
key: ivideon.attributes
delay: 3m
value_type: TEXT
url: 'http:/{HOST.IP}:8080/streams/info'
query_fields:
- name: server
value: '1'
- name: sessionId
value: '{$IVIDEON_PASSWORD}'
output_format: JSON
triggers:
- uuid: 6aebb2b119844e7c8223e90a9afbeba9
expression: 'nodata(/ivideon-server 3.9 HTTP/ivideon.attributes,3m)=1'
name: 'Ivideon-server service is unavailable'
priority: HIGH
discovery_rules:
- uuid: 9a759a9eb47049a2bbf8e9effea1456b
name: 'Ivideon-server discovery cameras'
type: DEPENDENT
key: ivideon.cameras
item_prototypes:
- uuid: 9a900ef7424f4d00bd3200f7ecb161e3
name: 'CAMERA [{#NAME}]: Get record status'
type: SCRIPT
key: 'ivideon.cameras.record.status[{#NAME}]'
value_type: TEXT
params: |
var obj = JSON.parse(value);
var host_ip = obj.hostip;
var camera_id = obj.cameraid;
var ivideon_pass = obj.ivideon_password
var request = new HttpRequest();
var nowUnix = Math.floor(Date.now() / 1000);
var timestamp_offset = nowUnix - 10800
var url = "http://" + host_ip + ":8080/archive/list"
+ "?startTime=" + timestamp_offset
+ "&endTime=" + nowUnix
+ "&server=1&sessionId=" + ivideon_pass
+ "&camera=" + camera_id;
var data = JSON.parse(request.get(url));
if (Array.isArray(data) && data.length === 0) {
return 0;
} else {
return 1;
}
parameters:
- name: cameraid
value: '{#CAMERA_ID}'
- name: hostip
value: '{HOST.IP}'
- name: ivideon_password
value: '{$IVIDEON_PASSWORD}'
trigger_prototypes:
- uuid: 2c4c9a05f32d43f38e6d0a58c6e1d63e
expression: 'last(/ivideon-server 3.9 HTTP/ivideon.cameras.record.status[{#NAME}])=0'
name: 'Camera {#NAME} archive not recording'
priority: WARNING
dependencies:
- name: 'Camera {#NAME} is unavailable'
expression: 'last(/ivideon-server 3.9 HTTP/ivideon.cameras.status[{#NAME}])=0'
- name: 'Ivideon-server service is unavailable'
expression: 'nodata(/ivideon-server 3.9 HTTP/ivideon.attributes,3m)=1'
- uuid: f76677285bf74103acdc473a92aad686
name: 'CAMERA [{#NAME}]: Get Status'
type: DEPENDENT
key: 'ivideon.cameras.status[{#NAME}]'
trends: '0'
preprocessing:
- type: JSONPATH
parameters:
- '$.body[?(@.name=="{#NAME}")].status.first()'
master_item:
key: ivideon.attributes
trigger_prototypes:
- uuid: 4f0bd15b54b2442cba8805f361787d7f
expression: 'last(/ivideon-server 3.9 HTTP/ivideon.cameras.status[{#NAME}])=0'
name: 'Camera {#NAME} is unavailable'
priority: HIGH
dependencies:
- name: 'Ivideon-server service is unavailable'
expression: 'nodata(/ivideon-server 3.9 HTTP/ivideon.attributes,3m)=1'
master_item:
key: ivideon.attributes
lld_macro_paths:
- lld_macro: '{#CAMERA_ID}'
path: $.id
- lld_macro: '{#NAME}'
path: $.name
- lld_macro: '{#STATUS}'
path: $.status
preprocessing:
- type: JSONPATH
parameters:
- '$.body[*]'
Готовый шаблон для версии Ivideon-Server 3.12.0
zabbix_export:
version: '7.4'
template_groups:
- uuid: d37f71c7e3f7469bab645852a69a2018
name: 'Templates/Video surveillance'
templates:
- uuid: 8799d6b58bf3483895babbd76026c758
template: 'ivideon-server 3.12 HTTP'
name: 'ivideon-server 3.12 HTTP'
groups:
- name: 'Templates/Video surveillance'
items:
- uuid: a724aaa44e6e4c0d8c5fbadcb3247fa6
name: 'Ivideon Get Data'
type: HTTP_AGENT
key: ivideon.attributes
delay: 3m
value_type: TEXT
url: 'http:/{HOST.IP}:8080/streams/info'
query_fields:
- name: server
value: '1'
- name: sessionId
value: '{$IVIDEON_PASSWORD}'
output_format: JSON
triggers:
- uuid: 13e35f3290e644f09bead7f9caf78ab1
expression: 'nodata(/ivideon-server 3.12 HTTP/ivideon.attributes,3m)=1'
name: 'Ivideon-server service is unavailable'
priority: HIGH
discovery_rules:
- uuid: 66bdeec591ac4239806f6c86c0179afd
name: 'Ivideon-server discovery cameras'
type: DEPENDENT
key: ivideon.cameras
item_prototypes:
- uuid: 685ba95a1f364e1b958106b4d1eb76a0
name: 'CAMERA [{#NAME}]: Get record status'
type: SCRIPT
key: 'ivideon.cameras.record.status[{#NAME}]'
value_type: TEXT
params: |
var obj = JSON.parse(value);
var host_ip = obj.hostip;
var camera_id = obj.cameraid;
var ivideon_pass = obj.ivideon_password
var request = new HttpRequest();
var nowUnix = Math.floor(Date.now() / 1000);
var timestamp_offset = nowUnix - 10800
var url = "http://" + host_ip + ":8080/archive/list"
+ "?startTime=" + timestamp_offset
+ "&endTime=" + nowUnix
+ "&server=1&sessionId=" + ivideon_pass
+ "&camera=" + camera_id;
var data = JSON.parse(request.get(url));
if (Array.isArray(data) && data.length === 0) {
return 0;
} else {
return 1;
}
parameters:
- name: cameraid
value: '{#CAMERA_ID}'
- name: hostip
value: '{HOST.IP}'
- name: ivideon_password
value: '{$IVIDEON_PASSWORD}'
trigger_prototypes:
- uuid: 787126b8f33d4a75b8a038013a4e273e
expression: 'last(/ivideon-server 3.12 HTTP/ivideon.cameras.record.status[{#NAME}])=0'
name: 'Camera {#NAME} archive not recording'
priority: WARNING
dependencies:
- name: 'Camera {#NAME} is unavailable'
expression: 'last(/ivideon-server 3.12 HTTP/ivideon.cameras.status[{#NAME}])=0'
- name: 'Ivideon-server service is unavailable'
expression: 'nodata(/ivideon-server 3.12 HTTP/ivideon.attributes,3m)=1'
- uuid: 4e5d1fd4cb4c4f73b6cae860743c3cf3
name: 'CAMERA [{#NAME}]: Get Status'
type: DEPENDENT
key: 'ivideon.cameras.status[{#NAME}]'
trends: '0'
preprocessing:
- type: JSONPATH
parameters:
- '$.body[?(@.custom_device_info.name=="{#NAME}")].status.first()'
master_item:
key: ivideon.attributes
trigger_prototypes:
- uuid: cf2488d8a103465b983c039ae415415c
expression: 'last(/ivideon-server 3.12 HTTP/ivideon.cameras.status[{#NAME}])=0'
name: 'Camera {#NAME} is unavailable'
priority: HIGH
dependencies:
- name: 'Ivideon-server service is unavailable'
expression: 'nodata(/ivideon-server 3.12 HTTP/ivideon.attributes,3m)=1'
master_item:
key: ivideon.attributes
lld_macro_paths:
- lld_macro: '{#CAMERA_ID}'
path: $.id
- lld_macro: '{#NAME}'
path: $.custom_device_info.name
- lld_macro: '{#STATUS}'
path: $.custom_device_info.status
preprocessing:
- type: JSONPATH
parameters:
- '$.body[*]'
Чтобы использовать шаблон, вставьте содержимое в текстовый файл и сохраните с расширением yaml, после импортируйте в Zabbix.
























