Skip to content

Instantly share code, notes, and snippets.

@mpolinowski
Created September 16, 2020 14:46
Show Gist options
  • Select an option

  • Save mpolinowski/adb16dc08fb29db6d3755dde06286799 to your computer and use it in GitHub Desktop.

Select an option

Save mpolinowski/adb16dc08fb29db6d3755dde06286799 to your computer and use it in GitHub Desktop.
Zabbix Webhook configuration
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>5.0</version>
<date>2020-08-11T00:00:00Z</date>
<media_types>
<media_type>
<name>Slack</name>
<type>WEBHOOK</type>
<parameters>
<parameter>
<name>alert_message</name>
<value>{ALERT.MESSAGE}</value>
</parameter>
<parameter>
<name>alert_subject</name>
<value>{ALERT.SUBJECT}</value>
</parameter>
<parameter>
<name>bot_token</name>
<value>&lt;PLACE YOUR KEY HERE&gt;</value>
</parameter>
<parameter>
<name>channel</name>
<value>{ALERT.SENDTO}</value>
</parameter>
<parameter>
<name>discovery_host_dns</name>
<value>{DISCOVERY.DEVICE.DNS}</value>
</parameter>
<parameter>
<name>discovery_host_ip</name>
<value>{DISCOVERY.DEVICE.IPADDRESS}</value>
</parameter>
<parameter>
<name>event_date</name>
<value>{EVENT.DATE}</value>
</parameter>
<parameter>
<name>event_id</name>
<value>{EVENT.ID}</value>
</parameter>
<parameter>
<name>event_nseverity</name>
<value>{EVENT.NSEVERITY}</value>
</parameter>
<parameter>
<name>event_opdata</name>
<value>{EVENT.OPDATA}</value>
</parameter>
<parameter>
<name>event_recovery_date</name>
<value>{EVENT.RECOVERY.DATE}</value>
</parameter>
<parameter>
<name>event_recovery_time</name>
<value>{EVENT.RECOVERY.TIME}</value>
</parameter>
<parameter>
<name>event_severity</name>
<value>{EVENT.SEVERITY}</value>
</parameter>
<parameter>
<name>event_source</name>
<value>{EVENT.SOURCE}</value>
</parameter>
<parameter>
<name>event_tags</name>
<value>{EVENT.TAGS}</value>
</parameter>
<parameter>
<name>event_time</name>
<value>{EVENT.TIME}</value>
</parameter>
<parameter>
<name>event_update_date</name>
<value>{EVENT.UPDATE.DATE}</value>
</parameter>
<parameter>
<name>event_update_status</name>
<value>{EVENT.UPDATE.STATUS}</value>
</parameter>
<parameter>
<name>event_update_time</name>
<value>{EVENT.UPDATE.TIME}</value>
</parameter>
<parameter>
<name>event_value</name>
<value>{EVENT.VALUE}</value>
</parameter>
<parameter>
<name>host_conn</name>
<value>{HOST.CONN}</value>
</parameter>
<parameter>
<name>host_name</name>
<value>{HOST.HOST}</value>
</parameter>
<parameter>
<name>slack_as_user</name>
<value>true</value>
</parameter>
<parameter>
<name>slack_mode</name>
<value>alarm</value>
</parameter>
<parameter>
<name>trigger_description</name>
<value>{TRIGGER.DESCRIPTION}</value>
</parameter>
<parameter>
<name>trigger_id</name>
<value>{TRIGGER.ID}</value>
</parameter>
<parameter>
<name>zabbix_url</name>
<value>{$ZABBIX.URL}</value>
</parameter>
</parameters>
<script>var SEVERITY_COLORS = [&#13;
'#97AAB3', '#7499FF', '#FFC859',&#13;
'#FFA059', '#E97659', '#E45959'&#13;
];&#13;
&#13;
var RESOLVE_COLOR = '#009900';&#13;
&#13;
var SLACK_MODE_HANDLERS = {&#13;
alarm: handlerAlarm,&#13;
event: handlerEvent&#13;
};&#13;
&#13;
&#13;
if (!String.prototype.format) {&#13;
String.prototype.format = function() {&#13;
var args = arguments;&#13;
&#13;
return this.replace(/{(\d+)}/g, function(match, number) {&#13;
return number in args&#13;
? args[number]&#13;
: match&#13;
;&#13;
});&#13;
};&#13;
}&#13;
&#13;
function isEventProblem(params) {&#13;
return params.event_value == 1&#13;
&amp;&amp; params.event_update_status == 0&#13;
;&#13;
}&#13;
&#13;
function isEventUpdate(params) {&#13;
return params.event_value == 1&#13;
&amp;&amp; params.event_update_status == 1&#13;
;&#13;
}&#13;
&#13;
function isEventResolve(params) {&#13;
return params.event_value == 0;&#13;
}&#13;
&#13;
function getPermalink(channelId, messageTimestamp) {&#13;
var req = new CurlHttpRequest();&#13;
&#13;
req.AddHeader('Content-Type: application/x-www-form-urlencoded; charset=utf-8');&#13;
&#13;
var resp = JSON.parse(req.Get(&#13;
'{0}?token={1}&amp;channel={2}&amp;message_ts={3}'.format(&#13;
Slack.getPermalink,&#13;
params.bot_token,&#13;
channelId,&#13;
messageTimestamp&#13;
)&#13;
));&#13;
&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
&#13;
return resp.permalink;&#13;
}&#13;
&#13;
function createProblemURL(zabbix_url, triggerid, eventid, event_source) {&#13;
var problem_url = '';&#13;
if (event_source === '0') {&#13;
problem_url = '{0}/tr_events.php?triggerid={1}&amp;eventid={2}'&#13;
.format(&#13;
zabbix_url,&#13;
triggerid,&#13;
eventid&#13;
);&#13;
}&#13;
else {&#13;
problem_url = zabbix_url;&#13;
}&#13;
&#13;
return problem_url;&#13;
}&#13;
&#13;
function getTagValue(event_tags, key) {&#13;
var pattern = new RegExp('(' + key + ':.+)');&#13;
var tag_value = event_tags&#13;
.split(',')&#13;
.filter(function (v) {&#13;
return v.match(pattern);&#13;
})&#13;
.map(function (v) {&#13;
return v.split(':')[1];&#13;
})[0]&#13;
|| 0;&#13;
&#13;
return tag_value;&#13;
}&#13;
&#13;
function handlerAlarm(params) {&#13;
var fields = {&#13;
channel: params.channel,&#13;
as_user: params.slack_as_user,&#13;
};&#13;
&#13;
if (isEventProblem(params)) {&#13;
fields.attachments = [&#13;
createMessage(&#13;
SEVERITY_COLORS[params.event_nseverity] || 0,&#13;
params.event_date,&#13;
params.event_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&#13;
)&#13;
];&#13;
&#13;
var resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&#13;
&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
&#13;
result.tags.__message_ts = resp.ts;&#13;
result.tags.__channel_id = resp.channel;&#13;
result.tags.__channel_name = params.channel;&#13;
result.tags.__message_link = getPermalink(resp.channel, resp.ts);&#13;
}&#13;
else if (isEventUpdate(params)) {&#13;
fields.thread_ts = getTagValue(params.event_tags, 'message_ts');&#13;
fields.attachments = [&#13;
createMessage(&#13;
SEVERITY_COLORS[params.event_nseverity] || 0,&#13;
params.event_update_date,&#13;
params.event_update_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&#13;
true&#13;
)&#13;
];&#13;
&#13;
resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
&#13;
}&#13;
else if (isEventResolve(params)) {&#13;
fields.channel = getTagValue(params.event_tags, 'channel_id');&#13;
fields.text = '';&#13;
fields.ts = getTagValue(params.event_tags, 'message_ts');&#13;
fields.attachments = [&#13;
createMessage(&#13;
RESOLVE_COLOR,&#13;
params.event_date,&#13;
params.event_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&#13;
)&#13;
];&#13;
&#13;
resp = JSON.parse(req.Post(Slack.chatUpdate, JSON.stringify(fields)));&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
}&#13;
}&#13;
&#13;
function handlerEvent(params) {&#13;
var fields = {&#13;
channel: params.channel,&#13;
as_user: params.slack_as_user&#13;
};&#13;
&#13;
if (isEventProblem(params)) {&#13;
fields.attachments = [&#13;
createMessage(&#13;
SEVERITY_COLORS[params.event_nseverity] || 0,&#13;
params.event_date,&#13;
params.event_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&#13;
)&#13;
];&#13;
&#13;
var resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&#13;
&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
&#13;
result.tags.__channel_name = params.channel;&#13;
result.tags.__message_link = getPermalink(resp.channel, resp.ts);&#13;
&#13;
}&#13;
else if (isEventUpdate(params)) {&#13;
fields.attachments = [&#13;
createMessage(&#13;
SEVERITY_COLORS[params.event_nseverity] || 0,&#13;
params.event_update_date,&#13;
params.event_update_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&#13;
false&#13;
)&#13;
];&#13;
&#13;
resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&#13;
&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
&#13;
}&#13;
else if (isEventResolve(params)) {&#13;
fields.attachments = [&#13;
createMessage(&#13;
RESOLVE_COLOR,&#13;
params.event_recovery_date,&#13;
params.event_recovery_time,&#13;
createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&#13;
)&#13;
];&#13;
&#13;
resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&#13;
&#13;
if (req.Status != 200 &amp;&amp; !resp.ok) {&#13;
throw resp.error;&#13;
}&#13;
}&#13;
}&#13;
&#13;
function createMessage(&#13;
event_severity_color,&#13;
event_date,&#13;
event_time,&#13;
problem_url,&#13;
isShort,&#13;
messageText&#13;
) {&#13;
var message = {&#13;
fallback: params.alert_subject,&#13;
title: params.alert_subject,&#13;
color: event_severity_color,&#13;
title_link: problem_url,&#13;
pretext: messageText || '',&#13;
&#13;
fields: [&#13;
{&#13;
title: 'Host',&#13;
value: '{0} [{1}]'.format(params.host_name, params.host_conn),&#13;
short: true&#13;
},&#13;
{&#13;
title: 'Event time',&#13;
value: '{0} {1}'.format(event_date, event_time),&#13;
short: true&#13;
}&#13;
],&#13;
};&#13;
&#13;
if (params.event_source === '0') {&#13;
message.fields.push(&#13;
{&#13;
title: 'Severity',&#13;
value: params.event_severity,&#13;
short: true&#13;
},&#13;
{&#13;
title: 'Opdata',&#13;
value: params.event_opdata,&#13;
short: true&#13;
}&#13;
);&#13;
}&#13;
&#13;
if (!isShort &amp;&amp; params.event_source === '0') {&#13;
message['actions'] = [&#13;
{&#13;
type: 'button',&#13;
text: 'Open in Zabbix',&#13;
url: problem_url&#13;
}&#13;
];&#13;
&#13;
message.fields.push(&#13;
{&#13;
title: 'Event tags',&#13;
value: params.event_tags.replace(/__.+?:(.+?,|.+)/g, '') || 'None',&#13;
short: true&#13;
},&#13;
{&#13;
title: 'Trigger description',&#13;
value: params.trigger_description,&#13;
short: true&#13;
}&#13;
);&#13;
}&#13;
&#13;
if (params.event_source !== '0' || params.event_update_status === '1') {&#13;
message.fields.push(&#13;
{&#13;
title: 'Details',&#13;
value: params.alert_message,&#13;
short: false&#13;
}&#13;
);&#13;
}&#13;
&#13;
return message;&#13;
}&#13;
&#13;
function validateParams(params) {&#13;
if (typeof params.bot_token !== 'string' || params.bot_token.trim() === '') {&#13;
throw 'Field &quot;bot_token&quot; cannot be empty';&#13;
}&#13;
&#13;
if (typeof params.channel !== 'string' || params.channel.trim() === '') {&#13;
throw 'Field &quot;channel&quot; cannot be empty';&#13;
}&#13;
&#13;
if (isNaN(params.event_id)) {&#13;
throw 'Field &quot;event_id&quot; is not a number';&#13;
}&#13;
&#13;
if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&#13;
throw 'Incorrect &quot;event_source&quot; parameter given: &quot;' + params.event_source + '&quot;.\nMust be 0-3.';&#13;
}&#13;
&#13;
if (params.event_source !== '0') {&#13;
params.event_nseverity = '0';&#13;
params.event_severity = 'Not classified';&#13;
params.event_update_status = '0';&#13;
params.slack_mode = 'event';&#13;
}&#13;
&#13;
if (params.event_source === '1' || params.event_source === '2') {&#13;
params.event_value = '1';&#13;
}&#13;
&#13;
if (params.event_source === '1') {&#13;
params.host_name = params.discovery_host_dns;&#13;
params.host_ip = params.discovery_host_ip;&#13;
}&#13;
&#13;
if (!~[0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity))) {&#13;
throw 'Incorrect &quot;event_nseverity&quot; parameter given: ' + params.event_nseverity + '\nMust be 0-5.';&#13;
}&#13;
&#13;
if (typeof params.event_severity !== 'string' || params.event_severity.trim() === '') {&#13;
throw 'Field &quot;event_severity&quot; cannot be empty';&#13;
}&#13;
&#13;
if (params.event_update_status !== '0' &amp;&amp; params.event_update_status !== '1') {&#13;
throw 'Incorrect &quot;event_update_status&quot; parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';&#13;
}&#13;
&#13;
if (params.event_value !== '0' &amp;&amp; params.event_value !== '1') {&#13;
throw 'Incorrect &quot;event_value&quot; parameter given: ' + params.event_value + '\nMust be 0 or 1.';&#13;
}&#13;
&#13;
if (typeof params.host_conn !== 'string' || params.host_conn.trim() === '') {&#13;
throw 'Field &quot;host_conn&quot; cannot be empty';&#13;
}&#13;
&#13;
if (typeof params.host_name !== 'string' || params.host_name.trim() === '') {&#13;
throw 'Field &quot;host_name&quot; cannot be empty';&#13;
}&#13;
&#13;
if (!~['true', 'false'].indexOf(params.slack_as_user.toLowerCase())) {&#13;
throw 'Incorrect &quot;slack_as_user&quot; parameter given: ' + params.slack_as_user + '\nMust be &quot;true&quot; or &quot;false&quot;.';&#13;
}&#13;
&#13;
if (!~['alarm', 'event'].indexOf(params.slack_mode)) {&#13;
throw 'Incorrect &quot;slack_mode&quot; parameter given: ' + params.slack_mode + '\nMust be &quot;alarm&quot; or &quot;event&quot;.';&#13;
}&#13;
&#13;
if (isNaN(params.trigger_id) &amp;&amp; params.event_source === '0') {&#13;
throw 'field &quot;trigger_id&quot; is not a number';&#13;
}&#13;
&#13;
if (typeof params.zabbix_url !== 'string' || params.zabbix_url.trim() === '') {&#13;
throw 'Field &quot;zabbix_url&quot; cannot be empty';&#13;
}&#13;
&#13;
if (!/^(http|https):\/\/.+/.test(params.zabbix_url)) {&#13;
throw 'Field &quot;zabbix_url&quot; must contain a schema';&#13;
}&#13;
}&#13;
&#13;
try {&#13;
var params = JSON.parse(value);&#13;
&#13;
validateParams(params);&#13;
&#13;
var req = new CurlHttpRequest(),&#13;
result = {tags: {}};&#13;
&#13;
if (typeof params.HTTPProxy === 'string' &amp;&amp; params.HTTPProxy.trim() !== '') {&#13;
req.SetProxy(params.HTTPProxy);&#13;
}&#13;
&#13;
req.AddHeader('Content-Type: application/json; charset=utf-8');&#13;
req.AddHeader('Authorization: Bearer ' + params.bot_token);&#13;
&#13;
var slack_endpoint = 'https://slack.com/api/';&#13;
&#13;
var Slack = {&#13;
postMessage: slack_endpoint + 'chat.postMessage',&#13;
getPermalink: slack_endpoint + 'chat.getPermalink',&#13;
chatUpdate: slack_endpoint + 'chat.update'&#13;
};&#13;
&#13;
params.slack_mode = params.slack_mode.toLowerCase();&#13;
params.slack_mode = params.slack_mode in SLACK_MODE_HANDLERS&#13;
? params.slack_mode&#13;
: 'alarm';&#13;
&#13;
SLACK_MODE_HANDLERS[params.slack_mode](params);&#13;
&#13;
if (params.event_source === '0') {&#13;
return JSON.stringify(result);&#13;
}&#13;
else {&#13;
return 'OK';&#13;
}&#13;
}&#13;
catch (error) {&#13;
Zabbix.Log(4, '[ Slack Webhook ] Slack notification failed : ' + error);&#13;
throw 'Slack notification failed : ' + error;&#13;
}</script>
<process_tags>YES</process_tags>
<show_event_menu>YES</show_event_menu>
<event_menu_url>{EVENT.TAGS.__message_link}</event_menu_url>
<event_menu_name>Open in Slack: {EVENT.TAGS.__channel_name}</event_menu_name>
<message_templates>
<message_template>
<event_source>TRIGGERS</event_source>
<operation_mode>PROBLEM</operation_mode>
<subject>Problem: {EVENT.NAME}</subject>
<message>Problem started at {EVENT.TIME} on {EVENT.DATE}&#13;
Problem name: {EVENT.NAME}&#13;
Host: {HOST.NAME}&#13;
Severity: {EVENT.SEVERITY}&#13;
Operational data: {EVENT.OPDATA}&#13;
Original problem ID: {EVENT.ID}&#13;
{TRIGGER.URL}</message>
</message_template>
<message_template>
<event_source>TRIGGERS</event_source>
<operation_mode>RECOVERY</operation_mode>
<subject>Resolved in {EVENT.DURATION}: {EVENT.NAME}</subject>
<message>Problem has been resolved at {EVENT.RECOVERY.TIME} on {EVENT.RECOVERY.DATE}&#13;
Problem name: {EVENT.NAME}&#13;
Problem duration: {EVENT.DURATION}&#13;
Host: {HOST.NAME}&#13;
Severity: {EVENT.SEVERITY}&#13;
Original problem ID: {EVENT.ID}&#13;
{TRIGGER.URL}</message>
</message_template>
<message_template>
<event_source>TRIGGERS</event_source>
<operation_mode>UPDATE</operation_mode>
<subject>Updated problem in {EVENT.AGE}: {EVENT.NAME}</subject>
<message>{USER.FULLNAME} {EVENT.UPDATE.ACTION} problem at {EVENT.UPDATE.DATE} {EVENT.UPDATE.TIME}.&#13;
{EVENT.UPDATE.MESSAGE}&#13;
&#13;
Current problem status is {EVENT.STATUS}, age is {EVENT.AGE}, acknowledged: {EVENT.ACK.STATUS}.</message>
</message_template>
<message_template>
<event_source>DISCOVERY</event_source>
<operation_mode>PROBLEM</operation_mode>
<subject>Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}</subject>
<message>Discovery rule: {DISCOVERY.RULE.NAME}&#13;
&#13;
Device IP: {DISCOVERY.DEVICE.IPADDRESS}&#13;
Device DNS: {DISCOVERY.DEVICE.DNS}&#13;
Device status: {DISCOVERY.DEVICE.STATUS}&#13;
Device uptime: {DISCOVERY.DEVICE.UPTIME}&#13;
&#13;
Device service name: {DISCOVERY.SERVICE.NAME}&#13;
Device service port: {DISCOVERY.SERVICE.PORT}&#13;
Device service status: {DISCOVERY.SERVICE.STATUS}&#13;
Device service uptime: {DISCOVERY.SERVICE.UPTIME}</message>
</message_template>
<message_template>
<event_source>AUTOREGISTRATION</event_source>
<operation_mode>PROBLEM</operation_mode>
<subject>Autoregistration: {HOST.HOST}</subject>
<message>Host name: {HOST.HOST}&#13;
Host IP: {HOST.IP}&#13;
Agent port: {HOST.PORT}</message>
</message_template>
</message_templates>
</media_type>
</media_types>
</zabbix_export>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment