-
Notifications
You must be signed in to change notification settings - Fork 2
/
zbx_mediatype_cwpsa-6.4.yaml
461 lines (410 loc) · 19.7 KB
/
zbx_mediatype_cwpsa-6.4.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
zabbix_export:
version: '6.4'
media_types:
- name: 'ConnectWise Manage PSA'
type: WEBHOOK
parameters:
- name: alert_message
value: '{ALERT.MESSAGE}'
- name: alert_subject
value: '{ALERT.SUBJECT}'
- name: cwpsa_api_clientid
value: '<your cw developer clientid>'
- name: cwpsa_api_password
value: '<your apimember privateKey>'
- name: cwpsa_api_url
value: 'https://<YOUR CW FQDN>/v4_6_release/apis/3.0/service/tickets/'
- name: cwpsa_api_user
value: '<your apimember company+publicKey>'
- name: cwpsa_cmpy_DEFAULT
value: '<default company client id>'
- name: cwpsa_cmpy_XXX
value: '<company xxx client id>'
- name: cwpsa_priority_for_average
value: '<cw priority-average sev prob (2?)>'
- name: cwpsa_priority_for_disaster
value: '<cw priority-disaster sev prob (1?)>'
- name: cwpsa_priority_for_high
value: '<cw priority-high sev prob (1?)>'
- name: cwpsa_priority_for_information
value: '<cw priority-info sev prob (4?)>'
- name: cwpsa_priority_for_not_classified
value: '<cw priority-not classified sev prob (3?)>'
- name: cwpsa_priority_for_warning
value: '<cw priority-warning sev prob (2?)>'
- name: cwpsa_priority_is_used
value: 'true'
- name: cwpsa_resolution_flag
value: 'true'
- name: cwpsa_serviceboard_name
value: '<your cw board name>'
- name: cwpsa_status_new
value: '<your cw status for new tickets>'
- name: cwpsa_status_resolved
value: '<your cw status for resolved tickets>'
- name: cwpsa_ticket_id
value: '{EVENT.TAGS.cwpsa_ticket_id}'
- name: cwpsa_type
value: '<your cw ticket type>'
- name: event_nseverity
value: '{EVENT.NSEVERITY}'
- name: event_recovery_value
value: '{EVENT.RECOVERY.VALUE}'
- name: event_source
value: '{EVENT.SOURCE}'
- name: event_status
value: '{EVENT.STATUS}'
- name: event_update_status
value: '{EVENT.UPDATE.STATUS}'
- name: event_value
value: '{EVENT.VALUE}'
status: DISABLED
script: |
var CWPSA = {
params: {},
setParams: function (params) {
if (typeof params !== 'object') {
return;
}
CWPSA.params = params;
// Ensure API url ends with /
if (typeof CWPSA.params.cwpsa_api_url === 'string') {
if (!CWPSA.params.cwpsa_api_url.endsWith('/')) {
CWPSA.params.cwpsa_api_url += '/';
}
}
},
setProxy: function (HTTPProxy) {
CWPSA.HTTPProxy = HTTPProxy;
},
// Fix dates to use hyphens
setFields: function (data, fields) {
if (typeof fields === 'object' && Object.keys(fields).length) {
Object.keys(fields)
.forEach(function(field) {
data[field] = (fields[field].match(/^\d{4}\.\d{2}\.\d{2}$/) !== null)
? fields[field].replace(/\./g, '-')
: fields[field];
});
}
},
request: function (method, data) {
// Make sure we have the connection parameters
['clientid', 'password', 'user', 'url'].forEach(function (field) {
if (typeof CWPSA.params !== 'object' || typeof CWPSA.params[field] === 'undefined'
|| CWPSA.params[field] === '' ) {
throw 'Required ConnectWise PSA parameter is not set: "' + field + '".';
}
});
var response,
url = CWPSA.params.url,
request = new HttpRequest();
// Build header with clientId and base64 encoded authentication parameters
request.addHeader('Content-Type: application/json');
request.addHeader('clientId: ' + CWPSA.params.clientid);
request.addHeader('Authorization: Basic ' + btoa(CWPSA.params.user + ':' + CWPSA.params.password));
if (typeof CWPSA.HTTPProxy !== 'undefined' && CWPSA.HTTPProxy !== '') {
request.setProxy(CWPSA.HTTPProxy);
}
if (typeof data !== 'undefined') {
data = JSON.stringify(data);
}
Zabbix.log(4, '[ ConnectWise Manage PSA Webhook 1 ] Sending request: ' + url + ((typeof data === 'string')
? ('\n' + data)
: ''));
switch (method) {
case 'post':
response = request.post(url, data);
break;
case 'patch':
data = '[' + data + ']';
response = request.patch(url, data);
break;
default:
throw 'Unsupported HTTP request method: ' + method;
}
Zabbix.log(4, '[ ConnectWise Manage PSA Webhook 2 ] Received response with status code ' +
request.getStatus() + '\n' + response);
if (response !== null) {
try {
response = JSON.parse(response);
}
catch (error) {
Zabbix.log(4, '[ ConnectWise Manage PSA Webhook 3 ] Failed to parse response received from ConnectWise Manage PSA');
response = null;
}
}
if (request.getStatus() < 200 || request.getStatus() >= 300) {
var message = 'Request failed with status code ' + request.getStatus();
if (response !== null && typeof response.error.message !== 'undefined'
&& Object.keys(response.error).length > 0) {
message += ': ' + JSON.stringify(response.error.message);
}
throw message + ' Check debug log for more information.';
}
else if (typeof response !== 'object') {
throw 'Cannot create/update ConnectWise Manage PSA ticket. Response result is not an object. Check debug log for more information.';
}
else if (typeof response.id === 'undefined') {
throw 'Cannot create/update ConnectWise Manage PSA ticket. Response result ID is undefined. Check debug log for more information.';
}
return response;
}
};
try {
var params = JSON.parse(value),
fields = {},
cwpsa = {},
data = {},
patchdata = {},
notedata = {},
result = {tags: {}},
required_params = [
'alert_subject', 'alert_message', 'event_source', 'event_value',
'event_update_status', 'event_recovery_value', 'event_nseverity',
'cwpsa_cmpy_DEFAULT', 'cwpsa_resolution_flag', 'cwpsa_serviceboard_name',
'cwpsa_status_resolved'
],
severities = [
{name: 'not_classified', color: '#97AAB3'},
{name: 'information', color: '#7499FF'},
{name: 'warning', color: '#FFC859'},
{name: 'average', color: '#FFA059'},
{name: 'high', color: '#E97659'},
{name: 'disaster', color: '#E45959'},
{name: 'resolved', color: '#009900'},
{name: 'default', color: '#000000'}
],
priorities = [
'Priority 1 - Critical',
'Priority 2 - High',
'Priority 3 - Medium',
'Priority 4 - Low'
],
process_tags = true;
cmpy_tla = '_CA';
// Process parameters
Object.keys(params)
.forEach(function (key) {
// Prepare API connection parameters
if (key.startsWith('cwpsa_api_')) {
cwpsa[key.substring(10)] = params[key];
}
// Prepare CW company three letter acronyms and check company Client ID exists
else if (key.startsWith('cwpsa_cmpy_')) {
if (params[key] !== '') {
cwpsa['cmpy_tla_' + key.substring(11)] = params[key];
} else {
throw 'Parameter "' + key + '" can\'t be empty and must contain the CW company Client ID.';
}
}
// Prepare CW priority mapping
else if (params.cwpsa_priority_is_used === 'true') {
if (key.startsWith('cwpsa_priority_for_')) {
if (params[key] !== '' && [1, 2, 3, 4].indexOf(parseInt(params[key])) !== -1) {
cwpsa['priority_' + key.substring(19)] = params[key];
} else {
throw 'If parameter priority_is_used is true, "' + key + '" can\'t be empty and must exist in the range 1 to 4.';
}
}
}
// Check required fields present
else if (required_params.indexOf(key) !== -1 && params[key] === '') {
throw 'Parameter "' + key + '" can\'t be empty.';
}
});
// Check event_source sanity
if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {
throw 'Incorrect "event_source" parameter given: ' + params.event_source + '\nMust be 0-3.';
}
// Use default nseverity if not specified
if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {
params.event_nseverity = '0';
}
// Check {EVENT.VALUE} for trigger-based and internal events.
if (params.event_value !== '0' && params.event_value !== '1'
&& (params.event_source === '0' || params.event_source === '3')) {
throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';
}
// Check {EVENT.UPDATE.STATUS} only for trigger-based events.
if (params.event_update_status !== '0' && params.event_update_status !== '1' && params.event_source === '0') {
throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';
}
// No recovery for non-trigger based events
if (params.event_source !== '0' && params.event_recovery_value === '0') {
throw 'Recovery operations are supported only for trigger-based actions.';
}
// Get correct company id parameter from first three characters of subject else use default
cmpy_tla = params.alert_subject.substring(0,3);
if (typeof cwpsa['cmpy_tla_' + cmpy_tla] !== 'undefined' ) {
company_id = cwpsa['cmpy_tla_' + cmpy_tla];
} else {
company_id = params.cwpsa_cmpy_DEFAULT;
}
// Set data for new ticket post
data = {
summary: params.alert_subject,
recordType: 'ServiceTicket',
board: {
name: params.cwpsa_serviceboard_name
},
status: {
name: params.cwpsa_status_new
},
type: {
name: params.cwpsa_type
},
company: {
identifier: company_id
},
initialDescription: params.alert_message
};
// Add CW priority info to data object if priorities are being used
if (params.cwpsa_priority_is_used === 'true') {
if (typeof cwpsa['priority_' + severities[params.event_nseverity].name] !== 'undefined') {
data.priority = { name: priorities[cwpsa['priority_' + severities[params.event_nseverity].name] - 1] };
} else {
data.initialDescription += ' | priority_' + priorities[cwpsa['priority_' + severities[params.event_nseverity].name] - 1] + ' is undefined';
throw 'Attempting to use CW priorities but ' + 'priority_' + severities[params.event_nseverity].name + ' is undefined';
}
}
// If this is an update, patch existing CWPSA ticket and/or add a note
if (params.event_source === '0' && (params.event_value === '0' || params.event_update_status === '1')) {
process_tags = false;
// If update is status "Resolved", set new ticket status and add note
if (params.event_status === "RESOLVED") {
// Set patch data
method = 'patch';
patchdata.op = "replace";
patchdata.path = "status/name";
patchdata.value = params.cwpsa_status_resolved;
// Make request
CWPSA.setParams(cwpsa);
CWPSA.setProxy(params.HTTPProxy);
CWPSA.setFields(patchdata, fields);
CWPSA.params.url += params.cwpsa_ticket_id;
var response = CWPSA.request(method, patchdata);
// Create ticket note data
method = 'post';
notedata.text = params.alert_message;
notedata.detailDescriptionFlag = true;
if (params.cwpsa_resolution_flag === 'true') {
notedata.resolutionFlag = true;
}
// Make request
CWPSA.setParams(cwpsa);
CWPSA.setProxy(params.HTTPProxy);
CWPSA.setFields(notedata, fields);
CWPSA.params.url += '/notes';
var response = CWPSA.request(method, notedata);
} else {
// Add an update note only
method = 'post';
notedata.text = params.alert_message;
notedata.detailDescriptionFlag = true;
notedata.resolutionFlag = false;
// Make request
CWPSA.setParams(cwpsa);
CWPSA.setProxy(params.HTTPProxy);
CWPSA.setFields(notedata, fields);
CWPSA.params.url += params.cwpsa_ticket_id + '/notes';
var response = CWPSA.request(method, notedata);
}
} else {
// Standard ticket creation request
method = 'post';
CWPSA.setParams(cwpsa);
CWPSA.setProxy(params.HTTPProxy);
CWPSA.setFields(data, fields);
var response = CWPSA.request(method, data);
}
// Get CW ticket ID into problem tag if enabled
if (process_tags) {
result.tags.cwpsa_ticket_id = response.id;
}
return JSON.stringify(result);
}
catch (error) {
Zabbix.log(3, '[ ConnectWise Manage PSA Webhook 4 ] ERROR: ' + error);
throw 'Sending failed: ' + error;
}
process_tags: 'YES'
show_event_menu: 'YES'
event_menu_url: 'https://<YOUR CW FQDN>/v4_6_release/services/system_io/Service/fv_sr100_request.rails?service_recid={EVENT.TAGS.cwpsa_link}'
event_menu_name: 'ConnectWise Ticket: {EVENT.TAGS.cwpsa_ticket_id}'
description: 'Hosted at https://github.com/slartimitvar/zabbix-connectwise-webhook'
message_templates:
- event_source: TRIGGERS
operation_mode: PROBLEM
subject: 'Problem: Sev {TRIGGER.SEVERITY} : {EVENT.NAME}'
message: |
**::: {EVENT.NAME} :::**
Severity: {TRIGGER.SEVERITY}
Host name: {HOST.NAME}
Problem name: {TRIGGER.NAME}
IP address: {HOST.IP}
Problem:
Event ID: {EVENT.ID}
Event value: {EVENT.VALUE}
Event status: {EVENT.STATUS}
Event time: {EVENT.TIME}
Event date: {EVENT.DATE}
Event age: {EVENT.AGE}
Event acknowledgment: {EVENT.ACK.STATUS}
Event update history: {EVENT.UPDATE.HISTORY}
- event_source: TRIGGERS
operation_mode: RECOVERY
subject: 'Resolved: Sev {TRIGGER.SEVERITY} : {EVENT.NAME}'
message: |
**::: {EVENT.NAME} :::**
Severity: {TRIGGER.SEVERITY}
Host name: {HOST.NAME}
Problem name: {TRIGGER.NAME}
IP address: {HOST.IP}
Problem:
Event ID: {EVENT.ID}
Event value: {EVENT.VALUE}
Event status: {EVENT.STATUS}
Event time: {EVENT.TIME}
Event date: {EVENT.DATE}
Event age: {EVENT.AGE}
Event acknowledgment: {EVENT.ACK.STATUS}
Event update history: {EVENT.UPDATE.HISTORY}
Recovery:
Event ID: {EVENT.RECOVERY.ID}
Event value: {EVENT.RECOVERY.VALUE}
Event status: {EVENT.RECOVERY.STATUS}
Event time: {EVENT.RECOVERY.TIME}
Event date: {EVENT.RECOVERY.DATE}
Operational data: {EVENT.OPDATA}
- event_source: TRIGGERS
operation_mode: UPDATE
subject: 'Updated problem in {EVENT.AGE}: {EVENT.NAME}'
message: |
**Update**
{EVENT.UPDATE.MESSAGE}
Update made by : {USER.FULLNAME} {EVENT.UPDATE.ACTION}
At : {EVENT.UPDATE.DATE} {EVENT.UPDATE.TIME}.
Current status : {EVENT.STATUS}
Age : {EVENT.AGE}
Acknowledged : {EVENT.ACK.STATUS}
- event_source: DISCOVERY
operation_mode: PROBLEM
subject: 'Discovery: {DISCOVERY.DEVICE.STATUS} {DISCOVERY.DEVICE.IPADDRESS}'
message: |
Discovery rule: {DISCOVERY.RULE.NAME}
Device IP: {DISCOVERY.DEVICE.IPADDRESS}
Device DNS: {DISCOVERY.DEVICE.DNS}
Device status: {DISCOVERY.DEVICE.STATUS}
Device uptime: {DISCOVERY.DEVICE.UPTIME}
Device service name: {DISCOVERY.SERVICE.NAME}
Device service port: {DISCOVERY.SERVICE.PORT}
Device service status: {DISCOVERY.SERVICE.STATUS}
Device service uptime: {DISCOVERY.SERVICE.UPTIME}
- event_source: AUTOREGISTRATION
operation_mode: PROBLEM
subject: 'Autoregistration: {HOST.HOST}'
message: |
Host name: {HOST.HOST}
Host IP: {HOST.IP}
Agent port: {HOST.PORT}