Skip to content

Commit 7afa467

Browse files
authored
Adds Echoes HQ integration (#130)
* Adds Echoes HQ integration * Add the password field instead to the API Key
1 parent bf7b24b commit 7afa467

File tree

6 files changed

+252
-0
lines changed

6 files changed

+252
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
module PagerTree::Integrations
2+
class EchoesHq::V3 < Integration
3+
OPTIONS = [
4+
{key: :api_key, type: :string, default: nil}
5+
]
6+
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
7+
8+
validates :option_api_key, presence: true
9+
10+
after_initialize do
11+
self.option_api_key ||= nil
12+
end
13+
14+
def adapter_supports_incoming?
15+
false
16+
end
17+
18+
def adapter_supports_outgoing?
19+
true
20+
end
21+
22+
def adapter_show_outgoing_webhook_delivery?
23+
false
24+
end
25+
26+
def adapter_supports_title_template?
27+
false
28+
end
29+
30+
def adapter_supports_description_template?
31+
false
32+
end
33+
34+
def adapter_supports_auto_aggregate?
35+
false
36+
end
37+
38+
def adapter_supports_auto_resolve?
39+
false
40+
end
41+
42+
def adapter_outgoing_interest?(event_name)
43+
["alert_open", "alert_acknowledged", "alert_resolved"].include?(event_name.to_s)
44+
end
45+
46+
def adapter_process_outgoing
47+
@pager_tree_alert = adapter_outgoing_event.alert
48+
49+
create_or_update_echoes_hq_incident
50+
end
51+
52+
private
53+
54+
def echoes_hq_incident_id
55+
"PAGERTREE_#{@pager_tree_alert.tiny_id}"
56+
end
57+
58+
def echoes_hq_status
59+
case @pager_tree_alert.status.to_s
60+
when "acknowledged" then "acknowledged"
61+
when "resolved" then "resolved"
62+
else
63+
"triggered"
64+
end
65+
end
66+
67+
def echoes_hq_headers
68+
{
69+
Accept: "application/json",
70+
"Content-Type": "application/json",
71+
Authorization: "Bearer #{option_api_key}"
72+
}
73+
end
74+
75+
def get_echoes_hq_incident
76+
result = nil
77+
response = nil
78+
url = "https://api.echoeshq.com/v1/signals/incidents/#{echoes_hq_incident_id}"
79+
response = HTTParty.get(url, headers: echoes_hq_headers, timeout: 3)
80+
result = response.code == 200 ? response.parsed_response : nil
81+
rescue
82+
result = nil
83+
ensure
84+
logs.create(level: :info, format: :json, message: {
85+
message: "GET EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
86+
url: url,
87+
response: response
88+
})
89+
90+
result
91+
end
92+
93+
def create_echoes_hq_incident
94+
result = nil
95+
response = nil
96+
url = "https://api.echoeshq.com/v1/signals/incidents"
97+
body = {
98+
id: echoes_hq_incident_id,
99+
title: @pager_tree_alert.title,
100+
service: {
101+
name: @pager_tree_alert.source&.name || name
102+
},
103+
started_at: @pager_tree_alert.created_at.iso8601
104+
}
105+
106+
response = HTTParty.post(url, body: body.to_json, headers: echoes_hq_headers, timeout: 3)
107+
result = response.code == 200 ? response.parsed_response : nil
108+
rescue
109+
result = nil
110+
ensure
111+
logs.create(level: :info, format: :json, message: {
112+
message: "CREATE EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
113+
url: url,
114+
body: body,
115+
reponse: response
116+
})
117+
118+
result
119+
end
120+
121+
def update_echoes_hq_incident
122+
result = nil
123+
response = nil
124+
url = "https://api.echoeshq.com/v1/signals/incidents/#{echoes_hq_incident_id}"
125+
body = {
126+
title: @pager_tree_alert.title,
127+
status: echoes_hq_status,
128+
resolved_at: @pager_tree_alert.resolved_at&.iso8601
129+
}
130+
response = HTTParty.put(url, body: body.to_json, headers: echoes_hq_headers, timeout: 3)
131+
result = response.code == 200 ? response.parsed_response : nil
132+
rescue
133+
result = nil
134+
ensure
135+
logs.create(level: :info, format: :json, message: {
136+
message: "UPDATE EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
137+
url: url,
138+
body: body,
139+
response: response
140+
})
141+
142+
result
143+
end
144+
145+
def create_or_update_echoes_hq_incident
146+
create_echoes_hq_incident unless get_echoes_hq_incident.present?
147+
update_echoes_hq_incident
148+
end
149+
end
150+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
2+
<div class="form-group group" data-controller="password-visibility">
3+
<%= form.label :option_api_key %>
4+
<%= form.password_field :option_api_key, value: form.object.option_api_key, class: "form-control", data: { password_visibility_target: "input"} %>
5+
<div class="flex justify-between">
6+
<p class="form-hint"><%== t(".option_api_key_hint_html") %></p>
7+
<%= render partial: "shared/password_visibility_button" %>
8+
</div>
9+
</div>
10+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<div class="sm:col-span-2">
2+
<dt class="text-sm font-medium text-gray-500">
3+
<%= t("activerecord.attributes.pager_tree/integrations/echoes_hq/v3.option_api_key") %>
4+
</dt>
5+
<dd class="mt-1 text-sm text-gray-900">
6+
<div class="flex items-center gap-2">
7+
<p class="text-sm truncate">
8+
<%= mask integration.option_api_key %>
9+
</p>
10+
</div>
11+
</dd>
12+
</div>

config/locales/en.yml

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ en:
4040
v3:
4141
form_options:
4242
option_support_retriggered_event_hint_html: "Create a new alert when the 'Re-Triggered' event is sent by Datadog"
43+
echoes_hq:
44+
v3:
45+
form_options:
46+
option_api_key_hint_html: "EchoesHQ <a href='https://docs.echoeshq.com/api-authentication#ZB9nc' target='_blank'>API Key</a>"
4347
email:
4448
v3:
4549
form_options:
@@ -171,6 +175,8 @@ en:
171175
option_webhook_secret: "Webhook Secret"
172176
"pager_tree/integrations/datadog/v3":
173177
option_support_retriggered_event: "Retriggered Event"
178+
"pager_tree/integrations/echoes_hq/v3":
179+
option_api_key: "Echoes HQ API Key"
174180
"pager_tree/integrations/email/v3":
175181
option_allow_spam: "Allow Spam"
176182
option_dedup_threads: "Dedup Threads"

test/fixtures/pager_tree/integrations/integrations.yml

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ dead_mans_snitch_v3:
3737
type: "PagerTree::Integrations::DeadMansSnitch::V3"
3838
# options: no_options
3939

40+
echoes_hq_v3:
41+
type: "PagerTree::Integrations::EchoesHq::V3"
42+
options:
43+
api_key: "abc123"
44+
4045
elast_alert_v3:
4146
type: "PagerTree::Integrations::ElastAlert::V3"
4247
# options: no_options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
require "test_helper"
2+
3+
module PagerTree::Integrations
4+
class EchoesHq::V3Test < ActiveSupport::TestCase
5+
include Integrateable
6+
7+
setup do
8+
@integration = pager_tree_integrations_integrations(:echoes_hq_v3)
9+
10+
@alert = JSON.parse({
11+
id: "01G9ZET2HZSTA9B0YDAB9G7XPZ",
12+
account_id: "01G9ZDGQ0NYAF6E1M3C6FAYDV5",
13+
prefix_id: "alt_K22OuvPYNmCyvJ",
14+
tiny_id: 22,
15+
source: {
16+
name: "Joe Bob"
17+
},
18+
title: "new alert",
19+
status: "acknowledged",
20+
urgency: "medium",
21+
created_at: "2022-08-08T19:27:20.127Z",
22+
updated_at: "2022-08-08T19:27:49.256Z",
23+
incident: false,
24+
incident_severity: "sev_1",
25+
incident_message: "",
26+
alert_destinations: [
27+
{
28+
destination: {
29+
name: "Team Bobcats"
30+
}
31+
}
32+
]
33+
}.to_json, object_class: OpenStruct)
34+
35+
@data = {
36+
event_name: :alert_acknowledged,
37+
alert: @alert,
38+
changes: [{
39+
before: {
40+
status: "open"
41+
},
42+
after: {
43+
foo: "ackowledged"
44+
}
45+
}],
46+
outgoing_rules_data: {}
47+
}
48+
49+
@alert.created_at = @alert.created_at.to_datetime
50+
@alert.updated_at = @alert.updated_at.to_datetime
51+
end
52+
53+
test "sanity" do
54+
assert_not @integration.adapter_supports_incoming?
55+
assert @integration.adapter_incoming_can_defer?
56+
assert @integration.adapter_supports_outgoing?
57+
assert_not @integration.adapter_show_alerts?
58+
assert @integration.adapter_show_logs?
59+
assert_not @integration.adapter_show_outgoing_webhook_delivery?
60+
end
61+
62+
test "outgoing_interest" do
63+
assert @integration.adapter_outgoing_interest?(:alert_open)
64+
assert @integration.adapter_outgoing_interest?(:alert_acknowledged)
65+
assert @integration.adapter_outgoing_interest?(:alert_resolved)
66+
assert_not @integration.adapter_outgoing_interest?(:alert_dropped)
67+
end
68+
end
69+
end

0 commit comments

Comments
 (0)