pager_tree-integrations 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/pager_tree/integrations/live_call_routing/twilio/v3_controller.rb +20 -0
  3. data/app/jobs/pager_tree/integrations/live_call_routing/twilio/v3/max_wait_time_job.rb +13 -0
  4. data/app/models/pager_tree/integrations/additional_datum.rb +2 -2
  5. data/app/models/pager_tree/integrations/alert.rb +2 -2
  6. data/app/models/pager_tree/integrations/aws_cloudwatch/v3.rb +15 -5
  7. data/app/models/pager_tree/integrations/boolean_store_accessor.rb +2 -2
  8. data/app/models/pager_tree/integrations/channel/hangouts/v3.rb +23 -2
  9. data/app/models/pager_tree/integrations/channel/mattermost/v3.rb +4 -0
  10. data/app/models/pager_tree/integrations/channel/microsoft_teams/v3.rb +74 -29
  11. data/app/models/pager_tree/integrations/channel/microsoft_teams/v4.rb +261 -0
  12. data/app/models/pager_tree/integrations/channel/slack/v3.rb +30 -3
  13. data/app/models/pager_tree/integrations/cloudflare/v3.rb +75 -0
  14. data/app/models/pager_tree/integrations/custom_webhook/v3.rb +206 -0
  15. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.json +12 -0
  16. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.yaml +30 -0
  17. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_definition.json +9 -0
  18. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_example.yaml +27 -0
  19. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.json +25 -0
  20. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.yaml +33 -0
  21. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.json +40 -0
  22. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.yaml +32 -0
  23. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.json +30 -0
  24. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.yaml +23 -0
  25. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.json +12 -0
  26. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.yaml +48 -0
  27. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.json +21 -0
  28. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.yaml +43 -0
  29. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.json +31 -0
  30. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.yaml +24 -0
  31. data/app/models/pager_tree/integrations/datadog/v3.rb +10 -3
  32. data/app/models/pager_tree/integrations/dynatrace/v3.rb +67 -0
  33. data/app/models/pager_tree/integrations/echoes_hq/v3.rb +138 -0
  34. data/app/models/pager_tree/integrations/elast_alert/v3.rb +24 -0
  35. data/app/models/pager_tree/integrations/email/v3.rb +272 -22
  36. data/app/models/pager_tree/integrations/email/v3_examples/example.yml +24 -0
  37. data/app/models/pager_tree/integrations/form/v3.rb +15 -3
  38. data/app/models/pager_tree/integrations/freshdesk/v3.rb +7 -5
  39. data/app/models/pager_tree/integrations/freshservice/v3.rb +7 -5
  40. data/app/models/pager_tree/integrations/grafana/v3.rb +2 -2
  41. data/app/models/pager_tree/integrations/hetrix_tools/v3.rb +160 -0
  42. data/app/models/pager_tree/integrations/honeybadger/v3.rb +1 -1
  43. data/app/models/pager_tree/integrations/hydrozen/v3.rb +6 -0
  44. data/app/models/pager_tree/integrations/integration.rb +52 -9
  45. data/app/models/pager_tree/integrations/jira_server/v3.rb +12 -2
  46. data/app/models/pager_tree/integrations/kapacitor/v3.rb +1 -1
  47. data/app/models/pager_tree/integrations/live_call_routing/twilio/v3.rb +257 -22
  48. data/app/models/pager_tree/integrations/logic_monitor/v3.rb +193 -3
  49. data/app/models/pager_tree/integrations/mattermost/outgoing_webhook/v3.rb +1 -1
  50. data/app/models/pager_tree/integrations/meta/workplace/v3.rb +230 -0
  51. data/app/models/pager_tree/integrations/new_relic/v3.rb +9 -5
  52. data/app/models/pager_tree/integrations/outgoing_event.rb +8 -0
  53. data/app/models/pager_tree/integrations/outgoing_webhook/v3.rb +108 -13
  54. data/app/models/pager_tree/integrations/outgoing_webhook_delivery/hook_relay.rb +43 -33
  55. data/app/models/pager_tree/integrations/outgoing_webhook_delivery.rb +6 -5
  56. data/app/models/pager_tree/integrations/prtg/v3.rb +2 -1
  57. data/app/models/pager_tree/integrations/pulsetic/v3.rb +70 -0
  58. data/app/models/pager_tree/integrations/scom/pagertree.ps1 +153 -0
  59. data/app/models/pager_tree/integrations/scom/v3.rb +58 -0
  60. data/app/models/pager_tree/integrations/sentry/v3.rb +477 -0
  61. data/app/models/pager_tree/integrations/server_guard24/v3.rb +1 -1
  62. data/app/models/pager_tree/integrations/sixty_six_uptime/v3.rb +118 -0
  63. data/app/models/pager_tree/integrations/slack/webhook/v3.rb +1 -1
  64. data/app/models/pager_tree/integrations/solar_winds/v3.rb +66 -2
  65. data/app/models/pager_tree/integrations/status_gator/v3.rb +69 -0
  66. data/app/models/pager_tree/integrations/uptime_kuma/v3.rb +76 -0
  67. data/app/models/pager_tree/integrations/uptime_robot/v3.rb +6 -0
  68. data/app/models/pager_tree/integrations/webhook/v3.rb +25 -7
  69. data/app/models/pager_tree/integrations/zabbix/v3.rb +95 -0
  70. data/app/models/pager_tree/integrations/zendesk/v3.rb +2 -0
  71. data/app/views/pager_tree/integrations/channel/hangouts/v3/_form_options.html.erb +7 -0
  72. data/app/views/pager_tree/integrations/channel/hangouts/v3/_show_options.html.erb +10 -0
  73. data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_form_options.html.erb +7 -0
  74. data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_show_options.html.erb +14 -0
  75. data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_form_options.html.erb +41 -0
  76. data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_show_options.html.erb +54 -0
  77. data/app/views/pager_tree/integrations/channel/slack/v3/_form_options.html.erb +6 -3
  78. data/app/views/pager_tree/integrations/channel/slack/v3/_show_options.html.erb +1 -1
  79. data/app/views/pager_tree/integrations/cloudflare/v3/_form_options.html.erb +7 -0
  80. data/app/views/pager_tree/integrations/cloudflare/v3/_show_options.html.erb +12 -0
  81. data/app/views/pager_tree/integrations/custom_webhook/v3/_form_options.html.erb +8 -0
  82. data/app/views/pager_tree/integrations/custom_webhook/v3/_show_options.html.erb +0 -0
  83. data/app/views/pager_tree/integrations/datadog/v3/_form_options.html.erb +7 -0
  84. data/app/views/pager_tree/integrations/datadog/v3/_show_options.html.erb +12 -0
  85. data/app/views/pager_tree/integrations/dynatrace/v3/_form_options.html.erb +0 -0
  86. data/app/views/pager_tree/integrations/dynatrace/v3/_show_options.html.erb +0 -0
  87. data/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb +10 -0
  88. data/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb +12 -0
  89. data/app/views/pager_tree/integrations/email/v3/_form_options.html.erb +41 -11
  90. data/app/views/pager_tree/integrations/email/v3/_show_options.html.erb +18 -0
  91. data/app/views/pager_tree/integrations/form/v3/_form_options.html.erb +1 -5
  92. data/app/views/pager_tree/integrations/hetrix_tools/v3/_form_options.html.erb +7 -0
  93. data/app/views/pager_tree/integrations/hetrix_tools/v3/_show_options.html.erb +12 -0
  94. data/app/views/pager_tree/integrations/hydrozen/v3/_form_options.html.erb +0 -0
  95. data/app/views/pager_tree/integrations/hydrozen/v3/_show_options.html.erb +0 -0
  96. data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_form_options.html.erb +44 -31
  97. data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_show_options.html.erb +93 -8
  98. data/app/views/pager_tree/integrations/logic_monitor/v3/_form_options.html.erb +31 -0
  99. data/app/views/pager_tree/integrations/logic_monitor/v3/_show_options.html.erb +60 -0
  100. data/app/views/pager_tree/integrations/meta/workplace/v3/_form_options.html.erb +44 -0
  101. data/app/views/pager_tree/integrations/meta/workplace/v3/_show_options.html.erb +68 -0
  102. data/app/views/pager_tree/integrations/outgoing_webhook/v3/_form_options.html.erb +17 -3
  103. data/app/views/pager_tree/integrations/outgoing_webhook/v3/_show_options.html.erb +20 -0
  104. data/app/views/pager_tree/integrations/pulsetic/v3/_form_options.html.erb +0 -0
  105. data/app/views/pager_tree/integrations/pulsetic/v3/_show_options.html.erb +0 -0
  106. data/app/views/pager_tree/integrations/scom/v3/_form_options.html.erb +0 -0
  107. data/app/views/pager_tree/integrations/scom/v3/_show_options.html.erb +0 -0
  108. data/app/views/pager_tree/integrations/sentry/v3/_form_options.html.erb +9 -0
  109. data/app/views/pager_tree/integrations/sentry/v3/_show_options.html.erb +15 -0
  110. data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_form_options.html.erb +0 -0
  111. data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_show_options.html.erb +0 -0
  112. data/app/views/pager_tree/integrations/solar_winds/v3/_form_options.html.erb +40 -0
  113. data/app/views/pager_tree/integrations/solar_winds/v3/_show_options.html.erb +66 -0
  114. data/app/views/pager_tree/integrations/status_gator/v3/_form_options.html.erb +13 -0
  115. data/app/views/pager_tree/integrations/status_gator/v3/_show_options.html.erb +24 -0
  116. data/app/views/pager_tree/integrations/uptime_kuma/v3/_form_options.html.erb +0 -0
  117. data/app/views/pager_tree/integrations/uptime_kuma/v3/_show_options.html.erb +0 -0
  118. data/app/views/pager_tree/integrations/webhook/v3/_form_options.html.erb +8 -0
  119. data/app/views/pager_tree/integrations/webhook/v3/_show_options.html.erb +15 -0
  120. data/app/views/pager_tree/integrations/zabbix/v3/_form_options.html.erb +7 -0
  121. data/app/views/pager_tree/integrations/zabbix/v3/_show_options.html.erb +12 -0
  122. data/config/locales/en.yml +158 -10
  123. data/config/routes.rb +1 -0
  124. data/lib/pager_tree/integrations/format_converters/yaml_json_converter.rb +67 -0
  125. data/lib/pager_tree/integrations/version.rb +1 -1
  126. data/lib/pager_tree/integrations.rb +11 -3
  127. metadata +84 -8
@@ -0,0 +1,477 @@
1
+ module PagerTree::Integrations
2
+ class Sentry::V3 < Integration
3
+ OPTIONS = [
4
+ {key: :client_secret, type: :string, default: nil},
5
+ {key: :authorization_token, type: :string, default: nil},
6
+ {key: :authorization_token_expires_at, type: :string, default: nil},
7
+ {key: :authorization_refresh_token, type: :string, default: nil},
8
+ {key: :code, type: :string, default: nil}
9
+ ]
10
+ store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
11
+
12
+ after_initialize do
13
+ end
14
+
15
+ after_create_commit do
16
+ verify_installation if initialize_authorization_token!
17
+ end
18
+
19
+ def adapter_should_block_incoming?(request)
20
+ should_block = false
21
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/#sentry-hook-signature
22
+ client_secret = option_client_secret.presence || PagerTree::Integrations.integration_sentry_v3_client_secret
23
+ if client_secret.present? && request.headers["sentry-hook-signature"].present?
24
+ sentry_signature = request.headers["sentry-hook-signature"]
25
+ data = request.body.read
26
+ digest = OpenSSL::HMAC.hexdigest("SHA256", client_secret, data)
27
+ should_block = sentry_signature != digest
28
+ end
29
+
30
+ should_block
31
+ end
32
+
33
+ def adapter_supports_incoming?
34
+ true
35
+ end
36
+
37
+ def adapter_supports_outgoing?
38
+ false
39
+ end
40
+
41
+ def adapter_incoming_can_defer?
42
+ true
43
+ end
44
+
45
+ def adapter_thirdparty_id
46
+ send("_#{hook_resource}_adapter_thirdparty_id")
47
+ end
48
+
49
+ def adapter_action
50
+ return :other unless should_process?
51
+
52
+ send("_#{hook_resource}_adapter_action")
53
+ end
54
+
55
+ def adapter_process_create
56
+ Alert.new(
57
+ title: _title,
58
+ description: _description,
59
+ thirdparty_id: adapter_thirdparty_id,
60
+ dedup_keys: _dedup_keys,
61
+ additional_data: _additional_datums
62
+ )
63
+ end
64
+
65
+ def adapter_process_other
66
+ _installation_process_other if installation?
67
+ end
68
+
69
+ def verify_installation
70
+ if thirdparty_id.present?
71
+ HTTParty.put("https://sentry.io/api/0/sentry-app-installations/#{thirdparty_id}/",
72
+ headers: {
73
+ "Content-Type" => "application/json",
74
+ "Authorization" => "Bearer #{option_authorization_token}"
75
+ }, body: {
76
+ status: "installed"
77
+ }.to_json)
78
+
79
+ return true
80
+ end
81
+
82
+ false
83
+ rescue => e
84
+ Rails.logger.error("Error sending Sentry App Installation Confirmation: #{e.message}")
85
+ false
86
+ end
87
+
88
+ def initialize_authorization_token!
89
+ if thirdparty_id.present? && option_code.present?
90
+ response = HTTParty.post("https://sentry.io/api/0/sentry-app-installations/#{thirdparty_id}/authorizations/",
91
+ headers: {
92
+ "Content-Type" => "application/json"
93
+ }, body: {
94
+ grant_type: "authorization_code",
95
+ code: option_code,
96
+ client_id: PagerTree::Integrations.integration_sentry_v3_client_id,
97
+ client_secret: PagerTree::Integrations.integration_sentry_v3_client_secret
98
+ }.to_json)
99
+
100
+ if response.code == 201
101
+ json = JSON.parse(response.body)
102
+ self.option_authorization_token = json.dig("token")
103
+ self.option_authorization_refresh_token = json.dig("refreshToken")
104
+ self.option_authorization_token_expires_at = json.dig("expiresAt")
105
+ save!
106
+
107
+ return true
108
+ end
109
+ end
110
+
111
+ false
112
+ rescue => e
113
+ Rails.logger.error("Error initializing Sentry App Authorization Token: #{e.message}")
114
+ false
115
+ end
116
+
117
+ def refresh_authorization_token!
118
+ if thirdparty_id.present? && option_authorization_refresh_token.present?
119
+ response = HTTParty.post("https://sentry.io/api/0/sentry-app-installations/#{thirdparty_id}/authorizations/",
120
+ headers: {
121
+ "Content-Type" => "application/json"
122
+ }, body: {
123
+ grant_type: "refresh_token",
124
+ refresh_token: option_authorization_refresh_token,
125
+ client_id: PagerTree::Integrations.integration_sentry_v3_client_id,
126
+ client_secret: PagerTree::Integrations.integration_sentry_v3_client_secret
127
+ }.to_json)
128
+
129
+ if response.code == 201
130
+ json = JSON.parse(response.body)
131
+ self.option_authorization_token = json.dig("token")
132
+ self.option_authorization_refresh_token = json.dig("refreshToken")
133
+ self.option_authorization_token_expires_at = json.dig("expiresAt")
134
+ save!
135
+
136
+ return true
137
+ end
138
+ end
139
+
140
+ false
141
+ rescue => e
142
+ Rails.logger.error("Error refreshing Sentry App Authorization Token: #{e.message}")
143
+ false
144
+ end
145
+
146
+ private
147
+
148
+ ############################
149
+ # START INSTALLATION
150
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/installation/
151
+ ############################
152
+
153
+ def _installation_adapter_thirdparty_id
154
+ incoming_json.dig("id")
155
+ end
156
+
157
+ def _installation_adapter_action
158
+ :other
159
+ end
160
+
161
+ def _installation_title
162
+ ""
163
+ end
164
+
165
+ def _installation_description
166
+ ""
167
+ end
168
+
169
+ def _installation_additional_datums
170
+ []
171
+ end
172
+
173
+ def _installation_dedup_keys
174
+ []
175
+ end
176
+
177
+ def _installation_process_other
178
+ action = incoming_json.dig("action")
179
+ if action == "created"
180
+ # intentionally left blank
181
+ elsif action == "deleted"
182
+ # clear the thirdparty id off this integration and save
183
+ self.thirdparty_id = nil
184
+ save!
185
+ end
186
+ end
187
+
188
+ ############################
189
+ # END Installation
190
+ ############################
191
+
192
+ ############################
193
+ # START WEBHOOK
194
+ # Undocumented webhook format (this is what you get when you just signup for a trial)
195
+ ############################
196
+
197
+ def _webhook_adapter_thirdparty_id
198
+ incoming_json.dig("id")
199
+ end
200
+
201
+ def _webhook_adapter_action
202
+ :create
203
+ end
204
+
205
+ def _webhook_title
206
+ incoming_json.dig("event", "title")
207
+ end
208
+
209
+ def _webhook_description
210
+ web_url = incoming_json.dig("url")
211
+ "Please see <a href='#{web_url}' target='_blank'>Sentry issue</a> for full details." if web_url.present?
212
+ end
213
+
214
+ def _webhook_additional_datums
215
+ [
216
+ AdditionalDatum.new(format: "link", label: "Web URL", value: incoming_json.dig("url")),
217
+ AdditionalDatum.new(format: "text", label: "Project", value: incoming_json.dig("project_name"))
218
+ ]
219
+ end
220
+
221
+ def _webhook_dedup_keys
222
+ []
223
+ end
224
+
225
+ ############################
226
+ # END WEBHOOK
227
+ ############################
228
+
229
+ ############################
230
+ # START ISSUE
231
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/issues/
232
+ ############################
233
+
234
+ def _issue_adapter_thirdparty_id
235
+ incoming_json.dig("data", "issue", "id")
236
+ end
237
+
238
+ def _issue_adapter_action
239
+ case action
240
+ when "created"
241
+ :create
242
+ when "resolved", "archived"
243
+ :resolve
244
+ when "assigned"
245
+ :acknowledge
246
+ else
247
+ :other
248
+ end
249
+ end
250
+
251
+ def _issue_title
252
+ incoming_json.dig("data", "issue", "title")
253
+ end
254
+
255
+ def _issue_description
256
+ web_url = incoming_json.dig("data", "issue", "web_url")
257
+ "Please see <a href='#{web_url}' target='_blank'>Sentry issue</a> for full details." if web_url.present?
258
+ end
259
+
260
+ def _issue_additional_datums
261
+ [
262
+ AdditionalDatum.new(format: "link", label: "Web URL", value: incoming_json.dig("data", "issue", "web_url"))
263
+ ]
264
+ end
265
+
266
+ def _issue_dedup_keys
267
+ []
268
+ end
269
+
270
+ ############################
271
+ # END ISSUE
272
+ ############################
273
+
274
+ ############################
275
+ # START EVENT ALERTS (ISSUE ALERTS)
276
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/issue-alerts/
277
+ ############################
278
+
279
+ def _event_alert_adapter_thirdparty_id
280
+ incoming_json.dig("data", "event", "issue_id")
281
+ end
282
+
283
+ def _event_alert_adapter_action
284
+ case action
285
+ when "triggered"
286
+ :create
287
+ else
288
+ :other
289
+ end
290
+ end
291
+
292
+ def _event_alert_title
293
+ incoming_json.dig("data", "event", "title")
294
+ end
295
+
296
+ def _event_alert_description
297
+ web_url = incoming_json.dig("data", "event", "web_url")
298
+ "Please see <a href='#{web_url}' target='_blank'>Sentry event</a> for full details." if web_url.present?
299
+ end
300
+
301
+ def _event_alert_additional_datums
302
+ [
303
+ AdditionalDatum.new(format: "link", label: "Web URL", value: incoming_json.dig("data", "event", "web_url"))
304
+ ]
305
+ end
306
+
307
+ def _event_alert_dedup_keys
308
+ []
309
+ end
310
+
311
+ ############################
312
+ # END EVENT ALERTS
313
+ ############################
314
+
315
+ ############################
316
+ # START METRIC ALERTS
317
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/metric-alerts/
318
+ ############################
319
+
320
+ def _metric_alert_adapter_thirdparty_id
321
+ incoming_json.dig("data", "metric_alert", "id")
322
+ end
323
+
324
+ def _metric_alert_adapter_action
325
+ case action
326
+ when "resolved"
327
+ :resolve
328
+ when "critical", "warning"
329
+ :create
330
+ else
331
+ :other
332
+ end
333
+ end
334
+
335
+ def _metric_alert_title
336
+ incoming_json.dig("data", "description_title")
337
+ end
338
+
339
+ def _metric_alert_description
340
+ incoming_json.dig("data", "description_text")
341
+ end
342
+
343
+ def _metric_alert_additional_datums
344
+ [
345
+ AdditionalDatum.new(format: "link", label: "Web URL", value: incoming_json.dig("data", "metric_alert", "web_url"))
346
+ ]
347
+ end
348
+
349
+ def _metric_alert_dedup_keys
350
+ []
351
+ end
352
+
353
+ ############################
354
+ # END METRIC ALERTS
355
+ ############################
356
+
357
+ ############################
358
+ # START ERRORS
359
+ # https://docs.sentry.io/product/integrations/integration-platform/webhooks/errors/
360
+ ############################
361
+
362
+ def _error_adapter_thirdparty_id
363
+ incoming_json.dig("data", "error", "issue_id")
364
+ end
365
+
366
+ def _error_adapter_action
367
+ case action
368
+ when "created"
369
+ :create
370
+ else
371
+ :other
372
+ end
373
+ end
374
+
375
+ def _error_title
376
+ incoming_json.dig("data", "error", "title")
377
+ end
378
+
379
+ def _error_description
380
+ web_url = incoming_json.dig("data", "error", "web_url")
381
+ "Please see <a href='#{web_url}' target='_blank'>Sentry event</a> for full details." if web_url.present?
382
+ end
383
+
384
+ def _error_additional_datums
385
+ [
386
+ AdditionalDatum.new(format: "link", label: "Web URL", value: incoming_json.dig("data", "error", "web_url"))
387
+ ]
388
+ end
389
+
390
+ def _error_dedup_keys
391
+ []
392
+ end
393
+
394
+ ############################
395
+ # END ERRORS
396
+ ############################
397
+
398
+ ############################
399
+ # START COMMON
400
+ ############################
401
+
402
+ def _title
403
+ send("_#{hook_resource}_title")
404
+ end
405
+
406
+ def _description
407
+ send("_#{hook_resource}_description")
408
+ end
409
+
410
+ def _additional_datums
411
+ send("_#{hook_resource}_additional_datums")
412
+ end
413
+
414
+ def _dedup_keys
415
+ send("_#{hook_resource}_dedup_keys")
416
+ end
417
+
418
+ ############################
419
+ # END COMMON
420
+ ############################
421
+
422
+ ############################
423
+ # START DATA ACCESS
424
+ ############################
425
+ def incoming_headers
426
+ adapter_incoming_deferred_request.headers
427
+ end
428
+
429
+ def incoming_body
430
+ adapter_incoming_deferred_request.body
431
+ end
432
+
433
+ def incoming_json
434
+ @_json ||= JSON.parse(incoming_body)
435
+ end
436
+
437
+ def hook_resource
438
+ incoming_headers["HTTP_SENTRY_HOOK_RESOURCE"] || "webhook"
439
+ end
440
+
441
+ def issue?
442
+ hook_resource == "issue"
443
+ end
444
+
445
+ def event_alert?
446
+ hook_resource == "event_alert"
447
+ end
448
+
449
+ def metric_alert?
450
+ hook_resource == "metric_alert"
451
+ end
452
+
453
+ def error?
454
+ hook_resource == "error"
455
+ end
456
+
457
+ def installation?
458
+ hook_resource == "installation"
459
+ end
460
+
461
+ def webhook?
462
+ incoming_headers["HTTP_SENTRY_HOOK_RESOURCE"].blank? && (hook_resource == "webhook")
463
+ end
464
+
465
+ def should_process?
466
+ issue? || event_alert? || metric_alert? || error? || installation? || webhook?
467
+ end
468
+
469
+ def action
470
+ incoming_json.dig("action")
471
+ end
472
+
473
+ ############################
474
+ # END DATA ACCESS
475
+ ############################
476
+ end
477
+ end
@@ -32,7 +32,7 @@ module PagerTree::Integrations
32
32
 
33
33
  if check_result == "CRITICAL"
34
34
  :create
35
- elsif check_result == "OK" || (check_result == "WARNING" && self.option_resolve_warn == true)
35
+ elsif check_result == "OK" || (check_result == "WARNING" && option_resolve_warn == true)
36
36
  :resolve
37
37
  else
38
38
  :other
@@ -0,0 +1,118 @@
1
+ module PagerTree::Integrations
2
+ class SixtySixUptime::V3 < Integration
3
+ OPTIONS = []
4
+ store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
5
+
6
+ after_initialize do
7
+ end
8
+
9
+ def adapter_supports_incoming?
10
+ true
11
+ end
12
+
13
+ def adapter_supports_outgoing?
14
+ false
15
+ end
16
+
17
+ def adapter_incoming_can_defer?
18
+ true
19
+ end
20
+
21
+ def adapter_thirdparty_id
22
+ id_part = case _webhoook_type
23
+ when "website", "ping", "port" then adapter_incoming_request_params.dig("monitor_id")
24
+ when "heartbeat" then adapter_incoming_request_params.dig("heartbeat_id")
25
+ when "domain-expiry", "ssl-expiry" then adapter_incoming_request_params.dig("domain_name_id")
26
+ else
27
+ SecureRandom.uuid
28
+ end
29
+ "#{_webhoook_type}-#{id_part}"
30
+ end
31
+
32
+ def adapter_action
33
+ case _webhoook_type
34
+ when "website", "ping", "port", "heartbeat"
35
+ (adapter_incoming_request_params.dig("is_ok") == 1) ? :resolve : :create
36
+ when "domain-expiry", "ssl-expiry"
37
+ :create
38
+ else
39
+ :other
40
+ end
41
+ end
42
+
43
+ def adapter_process_create
44
+ Alert.new(
45
+ title: _title,
46
+ description: _description,
47
+ thirdparty_id: adapter_thirdparty_id,
48
+ dedup_keys: [],
49
+ additional_data: _additional_datums
50
+ )
51
+ end
52
+
53
+ private
54
+
55
+ def _title
56
+ case _webhoook_type
57
+ when "website", "ping", "port" then "#{_webhoook_type.capitalize} monitor #{adapter_incoming_request_params.dig("name")} is DOWN"
58
+ when "heartbeat" then "Heartbeat monitor #{adapter_incoming_request_params.dig("name")} has not checked in"
59
+ when "domain-expiry" then "Domain monitor #{adapter_incoming_request_params.dig("name")} is expiring soon"
60
+ when "ssl-expiry" then "SSL Certificate monitor #{adapter_incoming_request_params.dig("name")} is expiring soon"
61
+ else
62
+ "Unknown Webhook Type"
63
+ end
64
+ end
65
+
66
+ def _description
67
+ case _webhoook_type
68
+ when "website", "ping", "port" then "#{_webhoook_type.capitalize} monitor #{adapter_incoming_request_params.dig("name")} (#{adapter_incoming_request_params.dig("target")}) is DOWN"
69
+ when "heartbeat" then "Heartbeat monitor #{adapter_incoming_request_params.dig("name")} has not checked in"
70
+ when "domain-expiry" then "Domain monitor #{adapter_incoming_request_params.dig("name")} (#{adapter_incoming_request_params.dig("target")}) is expiring soon (#{adapter_incoming_request_params.dig("whois_end_datetime")} #{adapter_incoming_request_params.dig("timezone")})"
71
+ when "ssl-expiry" then "SSL Certificate monitor #{adapter_incoming_request_params.dig("name")} (#{adapter_incoming_request_params.dig("target")}) is expiring soon (#{adapter_incoming_request_params.dig("ssl_end_datetime")} #{adapter_incoming_request_params.dig("timezone")})"
72
+ else
73
+ "Unknown Webhook Type"
74
+ end
75
+ end
76
+
77
+ def _additional_datums
78
+ case _webhoook_type
79
+ when "website", "ping", "port"
80
+ [
81
+ AdditionalDatum.new(format: "link", label: "URL", value: adapter_incoming_request_params.dig("url")),
82
+ AdditionalDatum.new(format: "text", label: "Name", value: adapter_incoming_request_params.dig("name")),
83
+ AdditionalDatum.new(format: "text", label: "Type", value: adapter_incoming_request_params.dig("type")),
84
+ AdditionalDatum.new(format: "link", label: "Target", value: adapter_incoming_request_params.dig("target")),
85
+ AdditionalDatum.new(format: "text", label: "port", value: adapter_incoming_request_params.dig("port"))
86
+ ]
87
+ when "heartbeat"
88
+ [
89
+ AdditionalDatum.new(format: "link", label: "URL", value: adapter_incoming_request_params.dig("url")),
90
+ AdditionalDatum.new(format: "text", label: "Name", value: adapter_incoming_request_params.dig("name")),
91
+ AdditionalDatum.new(format: "text", label: "Type", value: adapter_incoming_request_params.dig("type"))
92
+ ]
93
+ when "domain-expiry"
94
+ [
95
+ AdditionalDatum.new(format: "link", label: "URL", value: adapter_incoming_request_params.dig("url")),
96
+ AdditionalDatum.new(format: "text", label: "Name", value: adapter_incoming_request_params.dig("name")),
97
+ AdditionalDatum.new(format: "text", label: "Type", value: adapter_incoming_request_params.dig("type")),
98
+ AdditionalDatum.new(format: "link", label: "Target", value: adapter_incoming_request_params.dig("target")),
99
+ AdditionalDatum.new(format: "text", label: "WHOIS End DateTime", value: "#{adapter_incoming_request_params.dig("whois_end_datetime")} #{adapter_incoming_request_params.dig("timezone")}")
100
+ ]
101
+ when "ssl-expiry"
102
+ [
103
+ AdditionalDatum.new(format: "link", label: "URL", value: adapter_incoming_request_params.dig("url")),
104
+ AdditionalDatum.new(format: "text", label: "Name", value: adapter_incoming_request_params.dig("name")),
105
+ AdditionalDatum.new(format: "text", label: "Type", value: adapter_incoming_request_params.dig("type")),
106
+ AdditionalDatum.new(format: "link", label: "Target", value: adapter_incoming_request_params.dig("target")),
107
+ AdditionalDatum.new(format: "text", label: "SSL End DateTime", value: "#{adapter_incoming_request_params.dig("ssl_end_datetime")} #{adapter_incoming_request_params.dig("timezone")}")
108
+ ]
109
+ else
110
+ []
111
+ end
112
+ end
113
+
114
+ def _webhoook_type
115
+ adapter_incoming_request_params.dig("type")
116
+ end
117
+ end
118
+ end
@@ -51,7 +51,7 @@ module PagerTree::Integrations
51
51
  def _urgency
52
52
  text = adapter_incoming_request_params.dig("text")&.downcase
53
53
  matches = /(?<urgency>low|medium|high|critical)/.match(text)
54
- matches ? matches[:urgency].to_sym : urgency
54
+ matches ? matches[:urgency].to_s : nil
55
55
  end
56
56
 
57
57
  def _additional_datums
@@ -1,9 +1,25 @@
1
1
  module PagerTree::Integrations
2
2
  class SolarWinds::V3 < Integration
3
- OPTIONS = []
3
+ OPTIONS = [
4
+ {key: :alert_acknowledged, type: :boolean, default: false},
5
+ {key: :server_url, type: :string, default: nil},
6
+ {key: :server_username, type: :string, default: nil},
7
+ {key: :server_password, type: :string, default: nil},
8
+ {key: :proxy_url, type: :string, default: nil}
9
+ ]
4
10
  store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
5
11
 
12
+ validates :option_alert_acknowledged, inclusion: {in: [true, false]}
13
+ validates :option_server_username, presence: true, if: -> { option_alert_acknowledged == true }
14
+ validates :option_server_password, presence: true, if: -> { option_alert_acknowledged == true }
15
+ validates :option_server_url, presence: true, url: {no_local: true}, if: -> { option_alert_acknowledged == true }
16
+
6
17
  after_initialize do
18
+ self.option_alert_acknowledged ||= false
19
+ self.option_server_url ||= nil
20
+ self.option_server_username ||= nil
21
+ self.option_server_password ||= nil
22
+ self.option_proxy_url ||= nil
7
23
  end
8
24
 
9
25
  def adapter_supports_incoming?
@@ -11,13 +27,61 @@ module PagerTree::Integrations
11
27
  end
12
28
 
13
29
  def adapter_supports_outgoing?
14
- false
30
+ true
31
+ end
32
+
33
+ def adapter_show_outgoing_webhook_delivery?
34
+ true
15
35
  end
16
36
 
17
37
  def adapter_incoming_can_defer?
18
38
  true
19
39
  end
20
40
 
41
+ def adapter_outgoing_interest?(event_name)
42
+ try("option_#{event_name}") || false
43
+ end
44
+
45
+ def adapter_process_outgoing
46
+ try("adapter_process_outgoing_#{adapter_outgoing_event.event_name}")
47
+ end
48
+
49
+ def adapter_process_outgoing_alert_acknowledged
50
+ return unless adapter_outgoing_event.alert.source == self
51
+
52
+ ack_url = adapter_outgoing_event.alert&.source_log&.message&.dig("params", "AcknowledgeUrl")
53
+ ack_uri = URI.parse(ack_url)
54
+ server_uri = URI.parse(option_server_url)
55
+ object_id = Rack::Utils.parse_query(ack_uri.query).dig("ObjID")
56
+ url = "#{server_uri.origin}/SolarWinds/InformationService/v3/Json/Invoke/Orion.AlertActive/Acknowledge"
57
+ body = {
58
+ alertObjectIds: [object_id],
59
+ notes: "Acknowledged by #{adapter_outgoing_event.alert&.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.user&.name}"
60
+ }
61
+
62
+ auth = {}
63
+
64
+ if option_server_username.present? && option_server_password.present?
65
+ auth = {
66
+ username: option_server_username,
67
+ password: option_server_password
68
+ }
69
+ end
70
+
71
+ outgoing_webhook_delivery = OutgoingWebhookDelivery.factory(
72
+ resource: self,
73
+ url: url,
74
+ body: body,
75
+ auth: auth,
76
+ proxy_url: option_proxy_url.presence
77
+ )
78
+ outgoing_webhook_delivery.save!
79
+ outgoing_webhook_delivery.deliver_later
80
+
81
+ outgoing_webhook_delivery
82
+ rescue
83
+ end
84
+
21
85
  def adapter_thirdparty_id
22
86
  adapter_incoming_request_params.dig("AlertID")
23
87
  end