diff --git a/app/models/pager_tree/integrations/echoes_hq/v3.rb b/app/models/pager_tree/integrations/echoes_hq/v3.rb new file mode 100644 index 0000000..2592d9f --- /dev/null +++ b/app/models/pager_tree/integrations/echoes_hq/v3.rb @@ -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 diff --git a/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb b/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb new file mode 100644 index 0000000..541af9f --- /dev/null +++ b/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb @@ -0,0 +1,10 @@ +
+
+ <%= 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"} %> +
+

<%== t(".option_api_key_hint_html") %>

+ <%= render partial: "shared/password_visibility_button" %> +
+
+
\ No newline at end of file diff --git a/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb b/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb new file mode 100644 index 0000000..9047ca7 --- /dev/null +++ b/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb @@ -0,0 +1,12 @@ +
+
+ <%= t("activerecord.attributes.pager_tree/integrations/echoes_hq/v3.option_api_key") %> +
+
+
+

+ <%= mask integration.option_api_key %> +

+
+
+
diff --git a/config/locales/en.yml b/config/locales/en.yml index 804118a..7561aef 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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 API Key" email: v3: form_options: @@ -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" diff --git a/test/fixtures/pager_tree/integrations/integrations.yml b/test/fixtures/pager_tree/integrations/integrations.yml index cb73ce1..c5473e2 100644 --- a/test/fixtures/pager_tree/integrations/integrations.yml +++ b/test/fixtures/pager_tree/integrations/integrations.yml @@ -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 diff --git a/test/models/pager_tree/integrations/echoes_hq/v3_test.rb b/test/models/pager_tree/integrations/echoes_hq/v3_test.rb new file mode 100644 index 0000000..d5d22d7 --- /dev/null +++ b/test/models/pager_tree/integrations/echoes_hq/v3_test.rb @@ -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