Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Echoes HQ integration #130

Merged
merged 2 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions app/models/pager_tree/integrations/echoes_hq/v3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
module PagerTree::Integrations
class EchoesHq::V3 < Integration
OPTIONS = [
{key: :api_key, type: :string, default: nil}
]
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"

validates :option_api_key, presence: true

after_initialize do
self.option_api_key ||= nil
end

def adapter_supports_incoming?
false
end

def adapter_supports_outgoing?
true
end

def adapter_show_outgoing_webhook_delivery?
false
end

def adapter_supports_title_template?
false
end

def adapter_supports_description_template?
false
end

def adapter_supports_auto_aggregate?
false
end

def adapter_supports_auto_resolve?
false
end

def adapter_outgoing_interest?(event_name)
["alert_open", "alert_acknowledged", "alert_resolved"].include?(event_name.to_s)
end

def adapter_process_outgoing
@pager_tree_alert = adapter_outgoing_event.alert

create_or_update_echoes_hq_incident
end

private

def echoes_hq_incident_id
"PAGERTREE_#{@pager_tree_alert.tiny_id}"
end

def echoes_hq_status
case @pager_tree_alert.status.to_s
when "acknowledged" then "acknowledged"
when "resolved" then "resolved"
else
"triggered"
end
end

def echoes_hq_headers
{
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer #{option_api_key}"
}
end

def get_echoes_hq_incident
result = nil
response = nil
url = "https://api.echoeshq.com/v1/signals/incidents/#{echoes_hq_incident_id}"
response = HTTParty.get(url, headers: echoes_hq_headers, timeout: 3)
result = response.code == 200 ? response.parsed_response : nil
rescue
result = nil
ensure
logs.create(level: :info, format: :json, message: {
message: "GET EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
url: url,
response: response
})

result
end

def create_echoes_hq_incident
result = nil
response = nil
url = "https://api.echoeshq.com/v1/signals/incidents"
body = {
id: echoes_hq_incident_id,
title: @pager_tree_alert.title,
service: {
name: @pager_tree_alert.source&.name || name
},
started_at: @pager_tree_alert.created_at.iso8601
}

response = HTTParty.post(url, body: body.to_json, headers: echoes_hq_headers, timeout: 3)
result = response.code == 200 ? response.parsed_response : nil
rescue
result = nil
ensure
logs.create(level: :info, format: :json, message: {
message: "CREATE EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
url: url,
body: body,
reponse: response
})

result
end

def update_echoes_hq_incident
result = nil
response = nil
url = "https://api.echoeshq.com/v1/signals/incidents/#{echoes_hq_incident_id}"
body = {
title: @pager_tree_alert.title,
status: echoes_hq_status,
resolved_at: @pager_tree_alert.resolved_at&.iso8601
}
response = HTTParty.put(url, body: body.to_json, headers: echoes_hq_headers, timeout: 3)
result = response.code == 200 ? response.parsed_response : nil
rescue
result = nil
ensure
logs.create(level: :info, format: :json, message: {
message: "UPDATE EchoesHQ Incident for PagerTree alert ##{@pager_tree_alert.tiny_id}",
url: url,
body: body,
response: response
})

result
end

def create_or_update_echoes_hq_incident
create_echoes_hq_incident unless get_echoes_hq_incident.present?
update_echoes_hq_incident
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="form-group group" data-controller="password-visibility">
<%= form.label :option_api_key %>
<%= form.password_field :option_api_key, value: form.object.option_api_key, class: "form-control", data: { password_visibility_target: "input"} %>
<div class="flex justify-between">
<p class="form-hint"><%== t(".option_api_key_hint_html") %></p>
<%= render partial: "shared/password_visibility_button" %>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="sm:col-span-2">
<dt class="text-sm font-medium text-gray-500">
<%= t("activerecord.attributes.pager_tree/integrations/echoes_hq/v3.option_api_key") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<div class="flex items-center gap-2">
<p class="text-sm truncate">
<%= mask integration.option_api_key %>
</p>
</div>
</dd>
</div>
6 changes: 6 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ en:
v3:
form_options:
option_support_retriggered_event_hint_html: "Create a new alert when the 'Re-Triggered' event is sent by Datadog"
echoes_hq:
v3:
form_options:
option_api_key_hint_html: "EchoesHQ <a href='https://docs.echoeshq.com/api-authentication#ZB9nc' target='_blank'>API Key</a>"
email:
v3:
form_options:
Expand Down Expand Up @@ -171,6 +175,8 @@ en:
option_webhook_secret: "Webhook Secret"
"pager_tree/integrations/datadog/v3":
option_support_retriggered_event: "Retriggered Event"
"pager_tree/integrations/echoes_hq/v3":
option_api_key: "Echoes HQ API Key"
"pager_tree/integrations/email/v3":
option_allow_spam: "Allow Spam"
option_dedup_threads: "Dedup Threads"
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/pager_tree/integrations/integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ dead_mans_snitch_v3:
type: "PagerTree::Integrations::DeadMansSnitch::V3"
# options: no_options

echoes_hq_v3:
type: "PagerTree::Integrations::EchoesHq::V3"
options:
api_key: "abc123"

elast_alert_v3:
type: "PagerTree::Integrations::ElastAlert::V3"
# options: no_options
Expand Down
69 changes: 69 additions & 0 deletions test/models/pager_tree/integrations/echoes_hq/v3_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require "test_helper"

module PagerTree::Integrations
class EchoesHq::V3Test < ActiveSupport::TestCase
include Integrateable

setup do
@integration = pager_tree_integrations_integrations(:echoes_hq_v3)

@alert = JSON.parse({
id: "01G9ZET2HZSTA9B0YDAB9G7XPZ",
account_id: "01G9ZDGQ0NYAF6E1M3C6FAYDV5",
prefix_id: "alt_K22OuvPYNmCyvJ",
tiny_id: 22,
source: {
name: "Joe Bob"
},
title: "new alert",
status: "acknowledged",
urgency: "medium",
created_at: "2022-08-08T19:27:20.127Z",
updated_at: "2022-08-08T19:27:49.256Z",
incident: false,
incident_severity: "sev_1",
incident_message: "",
alert_destinations: [
{
destination: {
name: "Team Bobcats"
}
}
]
}.to_json, object_class: OpenStruct)

@data = {
event_name: :alert_acknowledged,
alert: @alert,
changes: [{
before: {
status: "open"
},
after: {
foo: "ackowledged"
}
}],
outgoing_rules_data: {}
}

@alert.created_at = @alert.created_at.to_datetime
@alert.updated_at = @alert.updated_at.to_datetime
end

test "sanity" do
assert_not @integration.adapter_supports_incoming?
assert @integration.adapter_incoming_can_defer?
assert @integration.adapter_supports_outgoing?
assert_not @integration.adapter_show_alerts?
assert @integration.adapter_show_logs?
assert_not @integration.adapter_show_outgoing_webhook_delivery?
end

test "outgoing_interest" do
assert @integration.adapter_outgoing_interest?(:alert_open)
assert @integration.adapter_outgoing_interest?(:alert_acknowledged)
assert @integration.adapter_outgoing_interest?(:alert_resolved)
assert_not @integration.adapter_outgoing_interest?(:alert_dropped)
end
end
end