Skip to content

Commit

Permalink
Issue #34: Use the Sensu check output as the OpsGenie alert descripti… (
Browse files Browse the repository at this point in the history
#35)

* Issue #34: Use the Sensu check output as the OpsGenie alert description field.

* Updating Changelog.

* Addressing review comments.

* Added requested Changelog entry for added command-line option, too.

* Updating tests to match changed OpsGenie API response behavior.  Sigh.

* Missed correcting/updating one of the suite-specific tests.
  • Loading branch information
Castaglia authored and majormoses committed Feb 21, 2018
1 parent d7bda76 commit c5f909c
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/tmp/
*.bundle
*.so
*.sw?
*.o
*.a
mkmf.log
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
This CHANGELOG follows the format listed [here](https://github.com/sensu-plugins/community/blob/master/HOW_WE_CHANGELOG.md)

## [Unreleased]
### Changed
- Providing better alert description field using Sensu check output (@Castaglia)

### Added
- `handler-opsgenie.rb`: Added flag of `--verbose` to enable verbose/debugging output (@Castaglia)

## [4.1.2] - 2018-02-05
### Fixed
Expand Down
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,54 @@ To get this to work you need to specify a few different things. For a list of fi
}
```

## Notes
## OpsGenie Alerts

How does the handler map the various Sensu values into the OpsGenie
[alerts and alert fields](https://docs.opsgenie.com/docs/alerts-and-alert-fields) created?

### Message

The OpsGenie _message_ alert field is comprised of the Sensu client name, and
the Sensu check name, _e.g._:
```
web01 : check_mysql_access
```

### Teams

The OpsGenie _team_ alert field uses the values in the Sensu check configuration
if any, otherwise it uses the value from the handler configuration.

### Recipients

The OpsGenie _recipients_ alert field uses the values in the Sensu check
configuration if any, otherwise it uses the value from the handler
configuration.

### Alias

The OpsGenie _alias_ alert is field is comprised of the Sensu client name,
and the Sensu check name to create a unique key, _e.g._:
```
web01:check_mysql_access
```
Note that this can be changed via configuration; see notes below.

### Entity

The OpsGenie _entity_ alert field uses the Sensu client name.

### Description

The OpsGenie _description_ alert field is populated with the Sensu check output.

### Priority

The OpsGenie _priority_ alert field is not explicitly set; OpsGenie will thus
assign the default priority of "P3" to the alert.


## Configuration Notes

If the check definition uses the custom `alias` attribute, _e.g._:
```
Expand Down
30 changes: 27 additions & 3 deletions bin/handler-opsgenie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
require 'erb'

class Opsgenie < Sensu::Handler
attr_reader :json_config, :message_template
attr_reader :json_config, :message_template, :verbose

OPSGENIE_URL = 'https://api.opsgenie.com/v2/alerts'.freeze

Expand All @@ -27,6 +27,12 @@ class Opsgenie < Sensu::Handler
long: '--template <file_path>',
default: nil

option :verbose,
description: 'Enable verbose/debugging output',
short: '-v',
long: '--verbose',
default: false

def handle
init
process
Expand Down Expand Up @@ -66,6 +72,11 @@ def process
puts "opsgenie -- timed out while attempting to #{@event['action']} a incident -- #{event_id}"
end

def description
return json_config['description'] unless json_config['description'].nil?
@event['check']['output'].chomp
end

def message
return @event['notification'] unless @event['notification'].nil?
return default_message if message_template.nil? || !File.exist?(message_template)
Expand All @@ -79,7 +90,7 @@ def custom_message
end

def default_message
[@event['client']['name'], @event['check']['name'], @event['check']['output'].chomp].join(' : ')
[@event['client']['name'], @event['check']['name']].join(' : ')
end

def event_id
Expand Down Expand Up @@ -111,7 +122,7 @@ def create_alert
post_to_opsgenie(:create,
alias: event_id,
message: message,
description: json_config['description'],
description: description,
entity: client_name,
tags: tags,
recipients: json_config['recipients'],
Expand Down Expand Up @@ -145,6 +156,19 @@ def post_to_opsgenie(action = :create, params = {})
"#{encoded_alias}/close?identifierType=alias"
end
uri = URI.parse("#{OPSGENIE_URL}/#{uripath}")

if config[:verbose]
# Note that the ordering of these lines roughly follows the order
# alert fields are displayed in the OpsGenie web UI.
puts "URL: #{uri}"
puts "Message: #{params[:message]}"
puts "Tags: #{params[:tags]}"
puts "Entity: #{params[:entity]}"
puts "Teams: #{params[:teams]}"
puts "Alias: #{params[:alias]}"
puts "Description: #{params[:description]}"
end

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/create-alert-with-description.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"client":{"name":"test01","address":"127.0.0.1","subscriptions":["all"],"timestamp":1326390159},"check":{"name":"some.fake.check.name","issued":1326390169,"output":"CRITICAL: text\n","status":2,"notification":"check failed","command":"/path/to/some/stuff/here -A do_smoke","subscribers":["all"],"interval":60,"handlers":["default","opsgenie"],"history":["0","0","2"],"flapping":false,"opsgenie":{"description":"MY_CUSTOM_DESCRIPTION"}},"occurrences":1,"action":"create"}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
describe 'check-opsgenie-heartbeat' do
describe command("#{check} --key #{key} --name #{name}") do
its(:exit_status) { should eq 3 }
its(:stdout) { should match(/UNKNOWN: unexpected response code 401/) }
its(:stdout) { should match(/UNKNOWN: unexpected response code (401|422)/) }
end
end
17 changes: 13 additions & 4 deletions test/integration/helpers/serverspec/handler-shared_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,35 @@
create_alert_with_alias_file = '/tmp/kitchen/data/test/fixtures/create-alert-with-alias.json'
resolve_alert_with_alias_file = '/tmp/kitchen/data/test/fixtures/resolve-alert-with-alias.json'

create_alert_with_description_file = '/tmp/kitchen/data/test/fixtures/create-alert-with-description.json'

# These tests would require a valid OpsGenie API key and heartbeat name
# configured in order to succeed. Thus for now, we limit ourselves to the
# expected failure cases.

describe 'handler-opsgenie' do
default_event_id_pattern = 'test01:some\.fake\.check\.name'
describe command("#{handler} < #{create_alert_file}") do
describe command("#{handler} -v < #{create_alert_file}") do
its(:stdout) { should match(/Description:.*CRITICAL.*text/) }
its(:stdout) { should match(/failed to create incident.*#{default_event_id_pattern}.*not authorized/) }
end

describe command("#{handler} < #{resolve_alert_file}") do
describe command("#{handler} -v < #{resolve_alert_file}") do
its(:stdout) { should match(/failed to resolve incident.*#{default_event_id_pattern}.*not authorized/) }
end

custom_event_id_pattern = 'MY_CUSTOM_ALIAS'
describe command("#{handler} < #{create_alert_with_alias_file}") do
describe command("#{handler} -v < #{create_alert_with_alias_file}") do
its(:stdout) { should match(/failed to create incident.*#{custom_event_id_pattern}.*not authorized/) }
end

describe command("#{handler} < #{resolve_alert_with_alias_file}") do
describe command("#{handler} -v < #{resolve_alert_with_alias_file}") do
its(:stdout) { should match(/failed to resolve incident.*#{custom_event_id_pattern}.*not authorized/) }
end

custom_description_pattern = 'MY_CUSTOM_DESCRIPTION'
describe command("#{handler} -v < #{create_alert_with_description_file}") do
its(:stdout) { should_not match(/Description:.*CRITICAL.*text/) }
its(:stdout) { should match(/Description:.*#{custom_description_pattern}/) }
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
describe 'check-opsgenie-heartbeat' do
describe command("#{check} --key #{key} --name #{name}") do
its(:exit_status) { should eq 3 }
its(:stdout) { should match(/UNKNOWN: unexpected response code 401/) }
its(:stdout) { should match(/UNKNOWN: unexpected response code (401|422)/) }
end
end

0 comments on commit c5f909c

Please sign in to comment.