[ZBX-18673] Slack Webhook from Templates - Throws Errors Created: 2020 Nov 18 Updated: 2024 Apr 10 Resolved: 2021 May 31 |
|
Status: | Closed |
Project: | ZABBIX BUGS AND ISSUES |
Component/s: | Packages (C), Server (S), Templates (T) |
Affects Version/s: | 5.2.0 |
Fix Version/s: | 5.0.11rc1, 5.2.7rc1, 5.4.0beta3, 5.4 (plan) |
Type: | Documentation task | Priority: | Trivial |
Reporter: | Cory White | Assignee: | Tikhon Uskov (Inactive) |
Resolution: | Fixed | Votes: | 3 |
Labels: | None | ||
Remaining Estimate: | Not Specified | ||
Time Spent: | Not Specified | ||
Original Estimate: | Not Specified | ||
Environment: |
Ubuntu 18, Zabbix Server 5.2.0 |
Attachments: | Screen Shot 2020-11-18 at 2.42.18 PM.png Screen Shot 2020-11-18 at 2.44.40 PM.png Screen Shot 2020-11-18 at 2.48.06 PM.png Screen Shot 2020-11-20 at 11.58.43 AM.png debian20_5.2.1_Slack_YAML_Download.PNG debian20_5.2.1_Slack_YAML_Uploaded.PNG image-2020-11-20-16-18-13-023.png image-2020-11-30-14-41-52-950.png image-2020-11-30-14-43-06-318.png image-2020-11-30-14-47-56-674.png slack_app.PNG | ||||||||||||||||||||||||||||
Issue Links: |
|
||||||||||||||||||||||||||||
Team: | Team INT | ||||||||||||||||||||||||||||
Sprint: | Sprint 74 (Mar 2021), Sprint 75 (Apr 2021), Sprint 76 (May 2021) | ||||||||||||||||||||||||||||
Story Points: | 1 |
Description |
Steps to reproduce:
Result: See Zabbix.Log modified error......
Expected: |
Comments |
Comment by Aleksandrs Pahomovs [ 2020 Nov 19 ] |
Hello, Which template for zabbix do you use? https://github.com/ericoc/zabbix-slack-alertscript ? https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/media/slack ? |
Comment by Cory White [ 2020 Nov 19 ] |
This is the webhook git template, not the scripted one... https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/media/slack |
Comment by Jaroslav Safranek [ 2020 Nov 20 ] |
Hi, we have same problems with Zabbix 5.2.1 and Mattermost 5.29.0 over webhooks. Mattermost notification failed: ReferenceError: identifier 'HttpRequest' undefined |
Comment by Aleksandrs Pahomovs [ 2020 Nov 20 ] |
Hello Cory, I just tested slack notifications for Zabbix 5.2.0 . All working fine. Yes, some logic in Slack has been changed. But zabbix side still works fine. I hope documentation will be updated soon. As I understand slack changed logic from bind with Bot IDs to bind with Tokens. You just have to go to "add features and functionality section" in Slack API. _> Choose Bots -> Review Scopes to Add -> Add an OAuth Scope and chose Chat:Write. -> Install App to the Workspace and you will get it.
|
Comment by Cory White [ 2020 Nov 20 ] |
I understand to documentation changes in Slack, I do not have an issue with the token creation was just making you aware. The issue is a clean installation of the git webhook and testing fails. It fails in 5.0 (production) and 5.2 (dev lab) servers running Ubuntu 18. We do have a string in the forums running that was started by another user so this is not a (one and done) situation? I've submitted a few bugs since 5.0 was released and am a little concerned at how quickly this is being dismissed? If you look at the forum post it is obvious there is a script issue with the installed packages as you can never even get to slack to run a test notification. |
Comment by Jaroslav Safranek [ 2020 Nov 20 ] |
Hi, please reopen this ticket. Can you say us why Zabbix this write?: ReferenceError: identifier 'HttpRequest' undefined It seems as problem in Zabbix because in Media template I can't found this error described.
|
Comment by Aleksandrs Pahomovs [ 2020 Nov 20 ] |
Hello Jaroslav, Which OS version do you have? |
Comment by Jaroslav Safranek [ 2020 Nov 20 ] |
Hi, It's debian 10.6 with 4.19.0-12-amd64 kernel. zabbix-agent2/neznámá,now 1:5.2.1-1+debian10 amd64 [instalovaný]
|
Comment by Cory White [ 2020 Nov 20 ] |
Not sure if this is same instance for Mattermost but I suspect it is - the issue is importing from git templates versus what is installed in a fresh server schema import. I just verified with a new instance in my lab - Slack works as expected - a diff between the import template for Slack versus the schema import had 18 differences mainly related to capitalization and CurlHttpRequest v HttpRequest. "camelCase instances that need updating in git template import : all req.X (Status, Get, Post, etc should be capital, not lowercase), Zabbix.Log, not 'log', HttpRequest ->CurlHttpRequest *found 18 diff in script comparison from git import to schema import."
|
Comment by Ervins Reinverts [ 2020 Nov 21 ] |
I can confirm that replacing the webhook Javascript code from git with the one from schema import helps and it then works. So the content in the git.zabbix.com needs to be updated. |
Comment by Jaroslav Safranek [ 2020 Nov 21 ] |
Yes, we must update all req.X too. erv : Can you write which Javascript code you replace? And who adn when git.zabbix.com will be updated? Thanks and best regards |
Comment by Jaroslav Safranek [ 2020 Nov 21 ] |
Hi, MatterMost git YAML is totally unusable. Main changes: HttpRequest ->CurlHttpRequest Zabbix.log -> Zabbix.Log req.* -> uppercase req.* as Get, Post etc... req.getStatus -> req.Status This is functional version for US: var SEVERITY_COLORS = [ '#97AAB3', '#7499FF', '#FFC859', '#FFA059', '#E97659', '#E45959' ]; var RESOLVE_COLOR = '#009900'; var SEND_MODE_HANDLERS = { alarm: handlerAlarm, event: handlerEvent }; if (!String.prototype.format) { String.prototype.format = function() { var args = arguments; return this.replace(/\{(\d+)}/g, function(match, number) { return number in args ? args[number] : match ; }); }; } function isEventProblem(params) { return params.event_value == 1 && params.event_update_status == 0 ; } function isEventUpdate(params) { return params.event_value == 1 && params.event_update_status == 1 ; } function isEventResolve(params) { return params.event_value == 0; } function getPermalink(mattermost_url, team_name, postid) { return '\{0}/\{1}/pl/\{2}'.format( mattermost_url.replace(/\/+$/, ''), team_name, postid ); } function getChannel(send_to) { switch (true) { case /.+\/#.+/.test(send_to): return getChannelByName(send_to); case /@.+/.test(send_to): return getDirectChannel(send_to); default: return getChannelByID(send_to); } } function getChannelByName(send_to) { var team_chan = send_to .trim() .split('/#'); var resp = JSON.parse(req.Get( Mattermost.channel_byname.format(team_chan[0], team_chan[1]), JSON.stringify(fields) ) ); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } return resp; } function getDirectChannel(send_to) { Zabbix.Log(5, '[ Mattermost Webhook ] Call \{0}(\{1})'.format( arguments.callee.name, JSON.stringify(arguments) )); var teamUser = send_to .trim() .split('/@'), bot = getBotUser(), user = getUserByName(teamUser[1]); var resp = JSON.parse(req.Post( Mattermost.direct_channel, JSON.stringify([bot.id, user.id]) ) ); Zabbix.Log(5, '[ Mattermost Webhook ] Result \{0}: \{1}'.format( arguments.callee.name, JSON.stringify(resp) )); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } resp.team_name = teamUser[0]; return resp; } function getChannelByID(channelID) { Zabbix.Log(5, '[ Mattermost Webhook ] Call \{0}(\{1})'.format( arguments.callee.name, JSON.stringify(arguments) )); var resp = JSON.parse(req.Get( Mattermost.get_channel.format(channelID), JSON.stringify(fields) ) ); Zabbix.Log(5, '[ Mattermost Webhook ] Result \{0}: \{1}'.format( arguments.callee.name, JSON.stringify(resp) )); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } return resp; } function getBotUser() { Zabbix.Log(5, '[ Mattermost Webhook ] Call \{0}(\{1})'.format( arguments.callee.name, JSON.stringify(arguments) )); var resp = JSON.parse(req.Get( Mattermost.bot_user, JSON.stringify(fields) ) ); Zabbix.Log(5, '[ Mattermost Webhook ] Result \{0}: \{1}'.format( arguments.callee.name, JSON.stringify(resp) )); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } return resp; } function getUserByName(userName) { Zabbix.Log(5, '[ Mattermost Webhook ] Call \{0}(\{1})'.format( arguments.callee.name, JSON.stringify(arguments) )); var resp = JSON.parse(req.Get( Mattermost.user_byname.format(userName), JSON.stringify(fields) ) ); Zabbix.Log(5, '[ Mattermost Webhook ] Result \{0}: \{1}'.format( arguments.callee.name, JSON.stringify(resp) )); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } return resp; } function getTeamByID(teamID) { Zabbix.Log(5, '[ Mattermost Webhook ] Call \{0}(\{1})'.format( arguments.callee.name, JSON.stringify(arguments) )); var resp = JSON.parse(req.Get( Mattermost.get_team.format(teamID), JSON.stringify(fields) ) ); Zabbix.Log(5, '[ Mattermost Webhook ] Result \{0}: \{1}'.format( arguments.callee.name, JSON.stringify(resp) )); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } return resp; } function createProblemURL(zabbix_url, triggerid, eventid, event_source) { var problem_url = ''; if (event_source === '0') { problem_url = '\{0}/tr_events.php?triggerid=\{1}&eventid=\{2}' .format( zabbix_url, triggerid, eventid ); } else { problem_url = zabbix_url; } return problem_url; } function getTagValue(event_tags, key) { var pattern = new RegExp('(' + key + ':.+)'); var tagValue = event_tags .split(',') .filter(function (v) { return v.match(pattern); }) .map(function (v) { return v.split(':')[1]; })[0] || 0; return tagValue; } function handlerAlarm(req, params) { var channel = getChannel(params.send_to); var fields = { channel_id: channel.id, props: {} }; if (isEventProblem(params)) { var team_name = channel.team_name ? channel.team_name : getTeamByID(channel.team_id).name; fields.props.attachments = [ createMessage( SEVERITY_COLORS[params.event_nseverity] || 0, params.event_date, params.event_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source) ) ]; var resp = JSON.parse(req.Post( Mattermost.post_message, JSON.stringify(fields) ) ); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } result.tags.__mattermost_post_id = resp.id; result.tags.__mattermost_channel_id = channel.id; result.tags.__mattermost_channel_name = channel.name; result.tags.__mattermost_message_link = getPermalink( params.mattermost_url, team_name, resp.id ); } else if (isEventUpdate(params)) { fields.root_id = getTagValue(params.event_tags, 'mattermost_post_id'); if (params.event_source === '0') {} fields.props.attachments = [ createMessage( SEVERITY_COLORS[params.event_nseverity] || 0, params.event_update_date, params.event_update_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source), true ) ]; resp = JSON.parse(req.Post( Mattermost.post_message, JSON.stringify(fields) ) ); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } } else if (isEventResolve(params)) { fields.channel_id = getTagValue(params.event_tags, 'mattermost_channel_id'); fields.id = getTagValue(params.event_tags, 'mattermost_post_id'); fields.props.attachments = [ createMessage( RESOLVE_COLOR, params.event_date, params.event_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source) ) ]; var post_id = getTagValue(params.event_tags, 'mattermost_post_id'); resp = JSON.parse(req.Put( Mattermost.chat_update.format(post_id), JSON.stringify(fields) ) ); if (req.Status() != 200) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } } } function handlerEvent(req, params) { var channel = getChannel(params.send_to); var fields = { channel_id: channel.id, props: {} }; if (isEventProblem(params)) { var team_name = channel.team_name ? channel.team_name : getTeamByID(channel.team_id).name; fields.props.attachments = [ createMessage( SEVERITY_COLORS[params.event_nseverity] || 0, params.event_date, params.event_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source) ) ]; var resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields))); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } result.tags.__mattermost_channel_name = channel.name; result.tags.__mattermost_message_link = getPermalink( params.mattermost_url, team_name, resp.id ); } else if (isEventUpdate(params)) { fields.props.attachments = [ createMessage( SEVERITY_COLORS[params.event_nseverity] || 0, params.event_update_date, params.event_update_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source), false ) ]; resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields))); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } } else if (isEventResolve(params)) { fields.props.attachments = [ createMessage( RESOLVE_COLOR, params.event_recovery_date, params.event_recovery_time, createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source) ) ]; resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields))); if (req.Status() != 201) { throw '[\{0}] \{1}'.format(resp.status_code, resp.message); } } } function createMessage( event_severity_color, event_date, event_time, problem_url, isShort ) { var message = { fallbac: params.alert_subject, title: params.alert_subject, color: event_severity_color, title_link: problem_url, footer: problem_url, fields: [ { title: 'Host', value: '\{0} [\{1}]'.format(params.host_name, params.host_ip), short: true }, { title: 'Event time', value: '\{0} \{1}'.format(event_date, event_time), short: true } ], }; if (params.event_source === '0') { message.fields.push( { title: 'Severity', value: params.event_severity, short: true }, { title: 'Opdata', value: params.event_opdata, short: true } ); } if (!isShort && params.event_source === '0') { message.fields.push( { title: 'Event tags', value: '`\{0}`'.format(params.event_tags.replace(/__.+?:(.+?,|.+)/g, '') || 'None'), short: true }, { title: 'Trigger description', value: params.trigger_description, short: true } ); } if (params.event_source !== '0' || params.event_update_status === '1') { message.fields.push( { title: 'Details', value: params.alert_message, short: false } ); } return message; } function validateParams(params) { if (typeof params.bot_token !== 'string' || params.bot_token.trim() === '') { throw 'Field "bot_token" cannot be empty'; } if (isNaN(params.event_id)) { throw 'Field "event_id" is not a number'; } if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) { throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.'; } if (params.event_source !== '0') { params.event_nseverity = '0'; params.event_severity = 'Not classified'; params.event_update_status = '0'; params.send_mode = 'event'; } if (params.event_source === '1' || params.event_source === '2') { params.event_value = '1'; } if (params.event_source === '1') { params.host_name = params.discovery_host_dns; params.host_ip = params.discovery_host_ip; } if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) { throw 'Incorrect "event_nseverity" parameter given: ' + params.event_nseverity + '\nMust be 0-5.'; } if (typeof params.event_severity !== 'string' || params.event_severity.trim() === '') { throw 'Field "event_severity" cannot be empty'; } if (params.event_update_status !== '0' && params.event_update_status !== '1') { throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.'; } if (params.event_value !== '0' && params.event_value !== '1') { throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.'; } if (typeof params.host_ip !== 'string' || params.host_ip.trim() === '') { throw 'Field "host_ip" cannot be empty'; } if (typeof params.host_name !== 'string' || params.host_name.trim() === '') { throw 'Field "host_name" cannot be empty'; } if (typeof params.mattermost_url !== 'string' || params.mattermost_url.trim() === '') { throw 'Field "mattermost_url" cannot be empty'; } if (!/^(http|https):\/\/.+/.test(params.mattermost_url)) { throw 'Field "mattermost_url" must contain a schema'; } if (['alarm', 'event'].indexOf(params.send_mode) === -1) { throw 'Incorrect "send_mode" parameter given: ' + params.send_mode + '\nMust be "alarm" or "event".'; } if (typeof params.send_to !== 'string' || params.send_to.trim() === '') { throw 'Field "send_to" cannot be empty'; } if (isNaN(params.trigger_id) && params.event_source === '0') { throw 'field "trigger_id" is not a number'; } if (typeof params.zabbix_url !== 'string' || params.zabbix_url.trim() === '') { throw 'Field "zabbix_url" cannot be empty'; } if (!/^(http|https):\/\/.+/.test(params.zabbix_url)) { throw 'Field "zabbix_url" must contain a schema'; } } try { var params = JSON.parse(value); validateParams(params); var req = new CurlHttpRequest(), fields = {}, result = \{tags: {}}; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') { req.SetProxy(params.HTTPProxy); } req.AddHeader('Content-Type: application/json; charset=utf-8'); req.AddHeader('Authorization: Bearer ' + params.bot_token); params.mattermost_url = params.mattermost_url.replace(/\/+$/, ''); params.zabbix_url = params.zabbix_url.replace(/\/+$/, ''); var APIEndpoint = params.mattermost_url + '/api/v4/'; var Mattermost = { post_message: APIEndpoint + 'posts', get_channel: APIEndpoint + 'channels/\{0}', get_team: APIEndpoint + 'teams/\{0}', chat_update: APIEndpoint + 'posts/\{0}', direct_channel: APIEndpoint + 'channels/direct', channel_byname: APIEndpoint + 'teams/name/\{0}/channels/name/\{1}', user_byname: APIEndpoint + 'users/username/\{0}', bot_user: APIEndpoint + 'users/me' }; params.send_mode = params.send_mode.toLowerCase(); params.send_mode = params.send_mode in SEND_MODE_HANDLERS ? params.send_mode : 'alarm'; SEND_MODE_HANDLERS[params.send_mode](req, params); if (params.event_source === '0') { return JSON.stringify(result); } else { return 'OK'; } } catch (error) { Zabbix.Log(4, '[ Mattermost Webhook ] Mattermost notification failed: ' + error); throw 'Mattermost notification failed: ' + error; }
|
Comment by Jaroslav Safranek [ 2020 Nov 21 ] |
Hi, Next trouble, when zabbix try send revocery message it's failed with this output: Mattermost notification failed: [400] Invalid or missing post_id parameter in request URL Can somebody help use with it? |
Comment by Jaroslav Safranek [ 2020 Nov 24 ] |
For recovery message I open ticket |
Comment by Aleksandrs Pahomovs [ 2020 Nov 30 ] |
Hello, I can't reproduse this issue. My installation on Debian 20, 5.0 is working fine.
After monor upgrade all still working fine:
For testing puproses I replased common template to the new from git this one: Old one has been delited and new uploded.
Please provide more information for reprodusing this issue.
|
Comment by Aleksandrs Pahomovs [ 2020 Nov 30 ] |
Probably it's because from 5.2.0 Zabbix is more tag based more than before. Please enable Process tags in webhooks media definitions. |
Comment by Ervins Reinverts [ 2020 Dec 02 ] |
@Jaroslav Safranek Sorry for late reply. If it is still needed, the one that gets installed when you do database schema install as per the manual, is the correct one. The one here: https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/media/slack You can get the correct script from @Cory White post in the forum: Or if the question was where do the script go, it is Administration -> Media types -> Slack and scroll down to the "Script" and edit. |
Comment by Aleksandrs Pahomovs [ 2020 Dec 04 ] |
It works if zabbix version is as same as template version. |
Comment by Cory White [ 2020 Dec 04 ] |
I 'm concerned this is marked as 'won't fix' when it does need a document update to actually be fixed. If you install a fresh instance of zabbix server and import the schema then the webhooks work as expected. If you are an actual production environment and delete everything not needed on new instances (like most) - then try to add these webhooks from the Zabbix Git templates after the fact - the Git Templates are not correct, there are all kinds of syntax errors in the scripts - I personally verified this on Slack and Zendesk templates with a diff (posted to forums). Regardless of which 5.x version - there is an issue downloading the Zabbix Git Templates. |
Comment by Tikhon Uskov (Inactive) [ 2021 Apr 12 ] |
Available in:
Documentation updated: |