Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add webhook mediatype for Zabbix 6.0 or higher #60

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ executors:
tag:
type: string
default: latest
mysql_tag:
type: string
default: '5.7'
docker:
- image: circleci/ruby:2.7.2-buster
- image: mysql:5.7
- image: mysql:<< parameters.mysql_tag >>
environment:
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
Expand Down Expand Up @@ -60,6 +63,19 @@ jobs:
steps:
- integration_test_with_zabbix

integration_test_with_zabbix_60:
executor:
name: zabbix
mysql_tag: '8.0'
tag: ubuntu-6.0-latest
working_directory: ~/repo
environment:
ZABBIX_API: http://localhost:8080/
ZABBIX_USER: Admin
ZABBIX_DISPATCHER_MEDIA_TYPE: webhook
steps:
- integration_test_with_zabbix

circleci_is_disabled_job:
docker:
- image: cimg/base:stable
Expand All @@ -74,6 +90,7 @@ workflows:
jobs:
- integration_test_with_zabbix_32
- integration_test_with_zabbix_40
- integration_test_with_zabbix_60
circleci_is_disabled:
jobs:
- circleci_is_disabled_job
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## 1.1.0

- Add webhook media_type for Zabbix 6.0 or higher

## 1.0.0

- Drop python 2.7 support.
Expand Down
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ This README explains how this integration works, and how to configure it.
![Internal construction of this pack](./images/internal_construction.png)

# Requirements
## st2 pack
* Zabbix >=3.0. It has been tested with v3.0, v3.2 and v4.0.

* Zabbix >3.0. It has been tested with v3.0, v3.2 and v4.0.
## script type distpacher
* Zabbix >=3.0. It has been tested with v3.0, v3.2 and v4.0.

## webhook type dispatcher
* Zabbix >=6.0. It has been tested with v6.0.

# Installation
Install the pack:
Expand All @@ -34,6 +40,13 @@ Options:
-s Z_SENDTO, --sendto=Z_SENDTO
Address, user name or other identifier of the
recipient
-s Z_DISPATCHERTYPE, --type=Z_DISPATCHERTYPE
Type of way to dispatch. If you select script,
the Zabbix will use st2_dispatcher. On the
other hand, if you select webhook, this command
will import a webhook dispathcer mediatype which
is defined in media_stackstorm.yml

```

Example execution:
Expand All @@ -58,9 +71,12 @@ After executing the `register_st2_config_to_zabbix.py` command, you can notice t
You see following page, and you have to fill out with parameters for your st2 environment (the endpoint URLs of st2-api and st2-auth, and authentication information).
![](./images/configuration_for_mediatype2.png)

If you setup webhook dispatcher, you see following page.
![](./images/configuration_for_mediatype3.png)

You can specify additional parameters and you can handle them from the payload of the StackStorm's Trigger(`zabbix.event_handler`).

### Deploy the AlertScript
### Deploy the AlertScript for script dispatcher

The script `st2_dispatch.py` sends Zabbix events to the StackStorm server. Copy this script to the directory which Zabbix MediaType refers to. The directory is specified by the parameter of `AlertScriptsPath` in the Zabbix configuration file on the node which zabbix was installed.
```shell
Expand Down Expand Up @@ -253,6 +269,12 @@ Starting procedure to run the test is also simple, all you have to do is executi
$ bundle exec rspec
```

When you want to run test for webhook type, you have to execute following command.

```
$ ZABBIX_DISPATCHER_MEDIA_TYPE=webhook bundle exec rspec
```

# Advanced Usage
If you would prefer to use an API Key for auth in place of user/pass, you can do so by passing a JSON Dict as the first positional argument in your `Media Type` in place of:
```
Expand All @@ -277,6 +299,8 @@ This dict has the following valid keys
`api_key` will cause `st2_userid` and `st2_passwd` to be ignored (API Key prefered)
`trigger` allows you to specify your own trigger on st2 to send messages to. Default is `zabbix.event_handler`

> WARNING: webhook type dispatcher does NOT support user/pass auth, please use API Key.

### JSON Examples
API Key for Auth - `{"api_url":"https://stackstorm.yourdomain.com/api/v1", "api_key":"aaabbbccc111222333"}`
User/Pass for auth - `{"api_url":"https://stackstorm.yourdomain.com/api/v1", "auth_url":"https://stackstorm.yourdomain.com/auth", "st2_userid":"st2admin", "st2_passwd":"st2pass"}`
Expand Down
Binary file added images/configuration_for_mediatype3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
236 changes: 236 additions & 0 deletions media_stackstorm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
zabbix_export:
version: '6.0'
media_types:
-
name: StackStorm
type: WEBHOOK
description: StackStorm
parameters:
-
name: alert_message
value: '{ALERT.MESSAGE}'
-
name: alert_subject
value: '{ALERT.SUBJECT}'
-
name: alert_sendto
value: '{ALERT.SENDTO}'
-
name: event_source
value: '{EVENT.SOURCE}'
-
name: st2_api_url
value: '<PLACE ST2 API URL>'
-
name: st2_api_key
value: '<PLACE ST2 API Key>'
-
name: st2_trigger
value: zabbix.event_handler
script: |
var St2 = {
params: {},

setParams: function (params) {
if (typeof params !== 'object') {
return;
}
St2.params = params;
},

setProxy: function (HTTPProxy) {
St2.HTTPProxy = HTTPProxy;
},

urlCheckFormat: function (api_url) {
if (typeof api_url === 'string' && !api_url.endsWith('/')) {
api_url += '/';
}

if (api_url.indexOf('http://') === -1 && api_url.indexOf('https://') === -1) {
api_url = 'https://' + api_url;
}

return api_url;
},

request: function (api_url, data) {
if (typeof St2.params !== 'object' || typeof St2.params['api_key'] === 'undefined' || St2.params['api_key'] === '') {
throw 'Required St2 param is not set: "api_key".';
}

var response,
request = new HttpRequest();

request.addHeader('Content-Type: application/json');
request.addHeader('St2-Api-Key: ' + St2.params.api_key);

const webhook_url = api_url + 'webhooks/st2';

if (typeof St2.HTTPProxy !== 'undefined' && St2.HTTPProxy !== '') {
request.setProxy(St2.HTTPProxy);
}

if (typeof data !== 'undefined') {
data = JSON.stringify(data);
}

Zabbix.log(4, '[ StackStorm Webhook ] Sending request: ' + webhook_url + ((typeof data === 'string')
? ('\n' + data)
: ''));

response = request.post(webhook_url, data);

Zabbix.log(4, '[ StackStorm Webhook ] Received response with status code ' +
request.getStatus() + '\n' + response);

if (response !== null) {
try {
response = JSON.parse(response);
}
catch (error) {
Zabbix.log(4, '[ StackStorm Webhook ] Failed to parse response received from StackStorm');
response = null;
}
}

if (typeof response !== 'object') {
throw 'Failed to process response received from StackStorm. Check debug log for more information.';
}

if (request.getStatus() < 200 || request.getStatus() >= 300) {
var message = 'Request failed with status code ' + request.getStatus();

if (response.message) {
message += ': ' + response.message;
}

throw message + ' Check debug log for more information.';
}

return response;
}
};

try {
var params = JSON.parse(value),
st2 = {},
data = {},
result
required_params = [
'alert_subject', 'alert_message',
'st2_api_url', 'st2_api_key', 'st2_trigger'
];

Object.keys(params)
.forEach(function (key) {
if (key.startsWith('st2_')) {
st2[key.substring(4)] = params[key];
}
else if (required_params.indexOf(key) !== -1 && params[key] === '') {
throw 'Parameter "' + key + '" can\'t be empty.';
}
});

// Check type of event. Possible values: 0 - Trigger
if (params.event_source != 0) {
throw ('Incorrect "event_source" parameter given: ' + params.event_source
+ '\nOnly trigger-based events are supported');
}

// Check for backslash in the end of url and schema.
st2.api_url = St2.urlCheckFormat(st2.api_url);


data.trigger = st2.trigger;
data.payload = {
alert_sendto: params.alert_sendto,
alert_subject: params.alert_subject,
alert_message: params.alert_message
}

St2.setParams(st2);
St2.setProxy(params.HTTPProxy);

var response = St2.request(st2.api_url, data);

Zabbix.log(4, '[ StackStorm Webhook ] Response: ' + JSON.stringify(response));
return JSON.stringify(response);
}
catch (error) {
Zabbix.log(4, '[ StackStorm Webhook ] ERROR: ' + error);
throw 'Sending failed: ' + error;
}
message_templates:
-
event_source: TRIGGERS
operation_mode: PROBLEM
subject: '[{TRIGGER.STATUS}] {TRIGGER.NAME}'
message: |
{
"event": {
"id": "{EVENT.ID}",
"time": "{EVENT.TIME}"
},
"trigger": {
"id": "{TRIGGER.ID}",
"name": "{TRIGGER.NAME}",
"status": "{TRIGGER.STATUS}"
},
"items": [
{
"name": "{ITEM.NAME1}",
"host": "{HOST.NAME1}",
"key": "{ITEM.KEY1}",
"value": "{ITEM.VALUE1}"
},
{
"name": "{ITEM.NAME2}",
"host": "{HOST.NAME2}",
"key": "{ITEM.KEY2}",
"value": "{ITEM.VALUE2}"
},
{
"name": "{ITEM.NAME3}",
"host": "{HOST.NAME3}",
"key": "{ITEM.KEY3}",
"value": "{ITEM.VALUE3}"
},
{
"name": "{ITEM.NAME4}",
"host": "{HOST.NAME4}",
"key": "{ITEM.KEY4}",
"value": "{ITEM.VALUE4}"
},
{
"name": "{ITEM.NAME5}",
"host": "{HOST.NAME5}",
"key": "{ITEM.KEY5}",
"value": "{ITEM.VALUE5}"
},
{
"name": "{ITEM.NAME6}",
"host": "{HOST.NAME6}",
"key": "{ITEM.KEY6}",
"value": "{ITEM.VALUE6}"
},
{
"name": "{ITEM.NAME7}",
"host": "{HOST.NAME7}",
"key": "{ITEM.KEY7}",
"value": "{ITEM.VALUE7}"
},
{
"name": "{ITEM.NAME8}",
"host": "{HOST.NAME8}",
"key": "{ITEM.KEY8}",
"value": "{ITEM.VALUE8}"
},
{
"name": "{ITEM.NAME9}",
"host": "{HOST.NAME9}",
"key": "{ITEM.KEY9}",
"value": "{ITEM.VALUE9}"
}
]
}
2 changes: 1 addition & 1 deletion pack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Zabbix Monitoring System
keywords:
- zabbix
- monitoring
version: 1.0.0
version: 1.1.0
author: Hiroyasu OHYAMA
email: [email protected]
python_versions:
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ py-zabbix==1.1.3
st2client
pytz
tzlocal
pyyaml
6 changes: 4 additions & 2 deletions spec/localhost/tools_register_config_for_st2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
ZABBIX_SENDTO = ENV['ZABBIX_SENDTO'] || 'admin'
ZABBIX_PASSWORD = ENV['ZABBIX_PASSWORD'] || 'zabbix'
ZABBIX_API_ENDPOINT = ENV['ZABBIX_API'] || 'http://localhost/'
ZABBIX_DISPATCHER_MEDIA_TYPE = ENV['ZABBIX_DISPATCHER_MEDIA_TYPE'] || 'script'

describe 'Tests for registering Zabbix for StackStorm' do
before(:all) do
Expand All @@ -18,7 +19,8 @@
"-u #{ ZABBIX_USER } " \
"-s #{ ZABBIX_SENDTO } " \
"-p #{ ZABBIX_PASSWORD } " \
"-z #{ ZABBIX_API_ENDPOINT }") do
"-z #{ ZABBIX_API_ENDPOINT } " \
"-t #{ ZABBIX_DISPATCHER_MEDIA_TYPE }") do
its(:exit_status) { should eq 0 }
its(:stdout) do
should match /^Success to register the configurations for StackStorm to the Zabbix Server./
Expand All @@ -38,7 +40,7 @@
# This method wait to start and initialize Zabbix-server and Zabbix-Web
def try_to_login(retry_count = 0)
begin
return @client.login('admin', 'zabbix')
return @client.login(ZABBIX_USER, ZABBIX_PASSWORD)
rescue => e
if retry_count < 60
# make a delay before retrying
Expand Down
Loading
Loading