Skip to content

Commit

Permalink
Support a Sensu check custom attribute of alias, so that Sensu chec… (
Browse files Browse the repository at this point in the history
#24)

* Support a Sensu check custom attribute of `alias`, so that Sensu checks can
specify the OpsGenie event ID value to use.

This is necessary for supporting de-duplication of multiple Sensu alerts,
based on a shared/common OpsGenie event ID.

* Move the `alias` attribute into an `opsgenie` section.

This helps indicate that this functionality is specific to this OpsGenie
handler.  It is also in line with the supported -j JSON config command-line
option, which merges into a "check.opsgenie" namespace/object.

* Nits for rubyists, per review feedback.
  • Loading branch information
Castaglia authored and majormoses committed Jan 14, 2018
1 parent 4714256 commit 12170f5
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachangelog.com/)

## [Unreleased]
### Added
- Added possibility to specify custom alias for event ID (@Castaglia)

## [4.0.1] - 2018-01-06
### Fixed
Expand Down
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,56 @@ To get this to work you need to specify a few different things. For a list of fi
```

## Notes

If the check definition uses the custom `alias` attribute, _e.g._:
```
{
"checks": {
"check_mysql_access": {
"opsgenie": {
"alias": "MyCustomAlias",
```
then the `handler-opsgenie.rb` handler will use that attribute value as the
OpsGenie event ID. This can be useful for alert deduplication; checks on
different clients for the same downstream resource can specify the same
`alias` attribute, so that multiple alerts for the same resource are
de-duplicated.

By default, `handler-opsgenie.rb` creates an event ID from the client name
and the check name. Thus:
```
{
"checks": {
"check_mysql_access": {
"command": "/opt/sensu/embedded/bin/check-database.rb -h mysqldb",
"interval": 60,
"handlers": [ "opsgenie" ],
"standalone": true
}
}
```
running on a client named `web01` will create an alert using an event ID of
`web01:check_mysql_access`. And on a client named `web02`, it would create an
alert with a _different_ event ID of `web02:check_mysql_access`, even though
the `mysqldb` server being checked is the same for these clients.

We can define a custom `alias` attribute in this check:
```
{
"checks": {
"check_mysql_access": {
"command": "/opt/sensu/embedded/bin/check-database.rb -h mysqldb",
"interval": 60,
"handlers": [ "opsgenie" ],
"standalone": true,
"opsgenie": {
"alias": "mysqldb"
}
}
}
```
And with this, running on multiple clients, any alerts would be generated
with the same event ID of `mysqldb`, by using that `alias` attribute as the
event ID.
12 changes: 7 additions & 5 deletions bin/handler-opsgenie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,18 @@ def process
end
case response.code.to_s
when '200', '202'
puts 'opsgenie -- ' + @event['action'].capitalize + 'd incident -- ' + event_id
puts "opsgenie -- #{@event['action'].capitalize}d incident -- #{event_id}"
when '401'
puts 'opsgenie -- failed to ' + @event['action'] + ' incident -- not authorized'
puts "opsgenie -- failed to #{@event['action']} incident -- #{event_id}: not authorized"
when '404'
puts 'opsgenie -- failed to ' + @event['action'] + ' incident -- ' + event_id + ' not found'
puts "opsgenie -- failed to #{@event['action']} incident -- #{event_id} not found"
else
puts 'opsgenie -- failed to ' + @event['action'] + ' incident -- ' + event_id
puts "opsgenie -- failed to #{@event['action']} incident -- #{event_id}"
puts "HTTP #{response.code} #{response.message}: #{response.body}"
end
end
rescue Timeout::Error
puts 'opsgenie -- timed out while attempting to ' + @event['action'] + ' a incident -- ' + event_id
puts "opsgenie -- timed out while attempting to #{@event['action']} a incident -- #{event_id}"
end

def message
Expand All @@ -83,6 +83,8 @@ def default_message
end

def event_id
return @event['check']['opsgenie']['alias'] unless @event['check']['opsgenie'].nil? || @event['check']['opsgenie']['alias'].nil?

# Do not use slashes in the event ID, as this alias becomes part of the URI
# in the RESTful interactions with OpsGenie; use characters which can be
# easily embedded into a URI.
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/create-alert-with-alias.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":{"alias":"MY_CUSTOM_ALIAS"}},"occurrences":1,"action":"create"}
1 change: 1 addition & 0 deletions test/fixtures/resolve-alert-with-alias.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":{"alias":"MY_CUSTOM_ALIAS"}},"occurrences":1,"action":"resolve"}
17 changes: 15 additions & 2 deletions test/integration/helpers/serverspec/handler-shared_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@
create_alert_file = '/tmp/kitchen/data/test/fixtures/create-alert.json'
resolve_alert_file = '/tmp/kitchen/data/test/fixtures/resolve-alert.json'

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'

# 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
its(:stdout) { should match(/failed to create incident.*not authorized/) }
its(:stdout) { should match(/failed to create incident.*#{default_event_id_pattern}.*not authorized/) }
end

describe command("#{handler} < #{resolve_alert_file}") do
its(:stdout) { should match(/failed to resolve incident.*not authorized/) }
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
its(:stdout) { should match(/failed to create incident.*#{custom_event_id_pattern}.*not authorized/) }
end

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

0 comments on commit 12170f5

Please sign in to comment.