flapjack 0.6.43 → 0.6.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/bin/flapjack +4 -2
  2. data/bin/flapjack-nagios-receiver +4 -1
  3. data/bin/flapjack-populator +4 -1
  4. data/etc/flapjack_config.yaml.example +111 -106
  5. data/features/steps/notifications_steps.rb +6 -6
  6. data/lib/flapjack/configuration.rb +76 -24
  7. data/lib/flapjack/coordinator.rb +27 -44
  8. data/lib/flapjack/data/entity.rb +28 -7
  9. data/lib/flapjack/data/entity_check.rb +18 -20
  10. data/lib/flapjack/executive.rb +5 -4
  11. data/lib/flapjack/gateways/api.rb +391 -0
  12. data/lib/flapjack/gateways/api/entity_check_presenter.rb +185 -0
  13. data/lib/flapjack/gateways/api/entity_presenter.rb +70 -0
  14. data/lib/flapjack/gateways/base.rb +38 -0
  15. data/lib/flapjack/{notification → gateways}/email.rb +4 -5
  16. data/lib/flapjack/{notification → gateways}/email/alert.html.haml +0 -0
  17. data/lib/flapjack/{notification → gateways}/email/alert.text.erb +0 -0
  18. data/lib/flapjack/gateways/jabber.rb +387 -0
  19. data/lib/flapjack/gateways/oobetet.rb +241 -0
  20. data/lib/flapjack/gateways/pagerduty.rb +247 -0
  21. data/lib/flapjack/{notification → gateways}/sms.rb +5 -6
  22. data/lib/flapjack/{notification → gateways}/sms/messagenet.rb +1 -1
  23. data/lib/flapjack/gateways/web.rb +293 -0
  24. data/lib/flapjack/{web → gateways/web}/views/_css.haml +0 -0
  25. data/lib/flapjack/{web → gateways/web}/views/_nav.haml +0 -0
  26. data/lib/flapjack/{web → gateways/web}/views/check.haml +0 -0
  27. data/lib/flapjack/{web → gateways/web}/views/contact.haml +0 -0
  28. data/lib/flapjack/{web → gateways/web}/views/contacts.haml +0 -0
  29. data/lib/flapjack/{web → gateways/web}/views/index.haml +0 -0
  30. data/lib/flapjack/{web → gateways/web}/views/self_stats.haml +0 -0
  31. data/lib/flapjack/pikelet.rb +0 -23
  32. data/lib/flapjack/version.rb +1 -1
  33. data/spec/lib/flapjack/coordinator_spec.rb +56 -36
  34. data/spec/lib/flapjack/data/entity_spec.rb +53 -4
  35. data/spec/lib/flapjack/{api → gateways/api}/entity_check_presenter_spec.rb +10 -13
  36. data/spec/lib/flapjack/{api → gateways/api}/entity_presenter_spec.rb +10 -10
  37. data/spec/lib/flapjack/{api_spec.rb → gateways/api_spec.rb} +14 -14
  38. data/spec/lib/flapjack/gateways/email_spec.rb +6 -0
  39. data/spec/lib/flapjack/{jabber_spec.rb → gateways/jabber_spec.rb} +9 -9
  40. data/spec/lib/flapjack/{oobetet_spec.rb → gateways/oobetet_spec.rb} +10 -10
  41. data/spec/lib/flapjack/{pagerduty_spec.rb → gateways/pagerduty_spec.rb} +11 -11
  42. data/spec/lib/flapjack/gateways/sms_spec.rb +6 -0
  43. data/spec/lib/flapjack/{web_spec.rb → gateways/web_spec.rb} +4 -4
  44. metadata +46 -79
  45. data/bin/install-flapjack-systemwide +0 -58
  46. data/features/steps/flapjack-importer_steps.rb +0 -109
  47. data/features/steps/flapjack-worker_steps.rb +0 -68
  48. data/lib/flapjack/api.rb +0 -388
  49. data/lib/flapjack/api/entity_check_presenter.rb +0 -181
  50. data/lib/flapjack/api/entity_presenter.rb +0 -66
  51. data/lib/flapjack/cli/worker_manager.rb +0 -46
  52. data/lib/flapjack/inifile.rb +0 -44
  53. data/lib/flapjack/jabber.rb +0 -383
  54. data/lib/flapjack/notifier_engine.rb +0 -40
  55. data/lib/flapjack/notifiers/mailer/init.rb +0 -3
  56. data/lib/flapjack/notifiers/mailer/mailer.rb +0 -51
  57. data/lib/flapjack/notifiers/xmpp/init.rb +0 -3
  58. data/lib/flapjack/notifiers/xmpp/xmpp.rb +0 -46
  59. data/lib/flapjack/oobetet.rb +0 -240
  60. data/lib/flapjack/pagerduty.rb +0 -242
  61. data/lib/flapjack/web.rb +0 -286
  62. data/spec.old/check_sandbox/echo +0 -3
  63. data/spec.old/check_sandbox/sandboxed_check +0 -5
  64. data/spec.old/configs/flapjack-notifier-couchdb.ini +0 -25
  65. data/spec.old/configs/flapjack-notifier.ini +0 -39
  66. data/spec.old/configs/recipients.ini +0 -14
  67. data/spec.old/helpers.rb +0 -15
  68. data/spec.old/inifile_spec.rb +0 -66
  69. data/spec.old/mock-notifiers/mock/init.rb +0 -3
  70. data/spec.old/mock-notifiers/mock/mock.rb +0 -19
  71. data/spec.old/notifier-directories/spoons/testmailer/init.rb +0 -20
  72. data/spec.old/notifier_application_spec.rb +0 -222
  73. data/spec.old/notifier_filters_spec.rb +0 -52
  74. data/spec.old/notifier_options_multiplexer_spec.rb +0 -71
  75. data/spec.old/notifier_options_spec.rb +0 -115
  76. data/spec.old/notifier_spec.rb +0 -57
  77. data/spec.old/notifiers/mailer_spec.rb +0 -36
  78. data/spec.old/notifiers/xmpp_spec.rb +0 -36
  79. data/spec.old/persistence/datamapper_spec.rb +0 -74
  80. data/spec.old/persistence/mock_persistence_backend.rb +0 -26
  81. data/spec.old/simple.ini +0 -6
  82. data/spec.old/spec.opts +0 -4
  83. data/spec.old/test-filters/blocker.rb +0 -13
  84. data/spec.old/test-filters/mock.rb +0 -13
  85. data/spec.old/transports/beanstalkd_spec.rb +0 -44
  86. data/spec.old/transports/mock_transport.rb +0 -58
  87. data/spec.old/worker_application_spec.rb +0 -62
  88. data/spec.old/worker_options_spec.rb +0 -83
  89. data/spec/lib/flapjack/notification/email_spec.rb +0 -6
  90. data/spec/lib/flapjack/notification/sms_spec.rb +0 -6
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require 'eventmachine'
5
+ require 'em-synchrony'
6
+ require 'blather/client/client'
7
+ require 'em-synchrony/fiber_iterator'
8
+ require 'yajl/json_gem'
9
+
10
+ require 'flapjack/utility'
11
+ require 'flapjack/gateways/base'
12
+
13
+ module Flapjack
14
+
15
+ module Gateways
16
+
17
+ class Oobetet < Blather::Client
18
+
19
+ include Flapjack::Gateways::Generic
20
+ include Flapjack::Utility
21
+
22
+ log = Logger.new(STDOUT)
23
+ # log.level = Logger::DEBUG
24
+ log.level = Logger::INFO
25
+ Blather.logger = log
26
+
27
+ def setup
28
+ @hostname = Socket.gethostname
29
+ @flapjacktest_jid = Blather::JID.new((@config['jabberid'] || 'flapjacktest') + "/#{@hostname}:#{Process.pid}")
30
+
31
+ super(@flapjacktest_jid, @config['password'], @config['server'], @config['port'].to_i)
32
+
33
+ logger.debug("Building jabber connection with jabberid: " +
34
+ @flapjacktest_jid.to_s + ", port: " + @config['port'].to_s +
35
+ ", server: " + @config['server'].to_s + ", password: " +
36
+ @config['password'].to_s)
37
+
38
+ @pagerduty_events_api_url = 'https://events.pagerduty.com/generic/2010-04-15/create_event.json'
39
+
40
+ if !@config['watched_check'] or !@config['watched_entity']
41
+ raise RuntimeError, 'Flapjack::Oobetet: watched_check and watched_entity must be defined in the config'
42
+ end
43
+
44
+ @check_matcher = '"' + @config['watched_check'] + '" on ' + @config['watched_entity']
45
+ @max_latency = @config['max_latency'] || 300
46
+ @flapjack_ok = true
47
+
48
+ t = Time.now.to_i
49
+ @times = { :last_problem => t,
50
+ :last_recovery => t,
51
+ :last_ack => t,
52
+ :last_ack_sent => t }
53
+
54
+ @last_alert = nil
55
+ end
56
+
57
+ # split out to ease testing
58
+ def register_handlers
59
+ register_handler :ready do |stanza|
60
+ EventMachine::Synchrony.next_tick do
61
+ on_ready(stanza)
62
+ end
63
+ end
64
+
65
+ register_handler :message, :groupchat? do |stanza|
66
+ EventMachine::Synchrony.next_tick do
67
+ on_groupchat(stanza)
68
+ end
69
+ end
70
+
71
+ register_handler :disconnected do |stanza|
72
+ ret = true
73
+ EventMachine::Synchrony.next_tick do
74
+ ret = on_disconnect(stanza)
75
+ end
76
+ ret
77
+ end
78
+ end
79
+
80
+
81
+ # Join the MUC Chat room after connecting.
82
+ def on_ready(stanza)
83
+ return if should_quit?
84
+ @connected_at = Time.now.to_i
85
+ logger.info("Jabber Connected")
86
+ if @config['rooms'] && @config['rooms'].length > 0
87
+ @config['rooms'].each do |room|
88
+ logger.info("Joining room #{room}")
89
+ presence = Blather::Stanza::Presence.new
90
+ presence.from = @flapjacktest_jid
91
+ presence.to = Blather::JID.new("#{room}/#{@config['alias']}")
92
+ presence << "<x xmlns='http://jabber.org/protocol/muc'/>"
93
+ write presence
94
+ say(room, "flapjack self monitoring (oobetet) started at #{Time.now}, g'day!", :groupchat)
95
+ end
96
+ end
97
+ end
98
+
99
+ # returning true to prevent the reactor loop from stopping
100
+ def on_disconnect(stanza)
101
+ return true if should_quit?
102
+ logger.warn("jabbers disconnected! reconnecting in 1 second ...")
103
+ EventMachine::Timer.new(1) do
104
+ connect # Blather::Client.connect
105
+ end
106
+ true
107
+ end
108
+
109
+ def on_groupchat(stanza)
110
+ return if should_quit?
111
+
112
+ stanza_body = stanza.body
113
+
114
+ logger.debug("groupchat stanza body: " + stanza_body)
115
+ logger.debug("groupchat message received: #{stanza.inspect}")
116
+
117
+ if (stanza_body =~ /^(?:problem|recovery|acknowledgement)/i) &&
118
+ (stanza_body =~ /^(\w+).*#{Regexp.escape(@check_matcher)}/)
119
+
120
+ # got something interesting
121
+ status = $1.downcase
122
+ t = Time.now.to_i
123
+ logger.debug("groupchat found the following state for #{@check_matcher}: #{status}")
124
+
125
+ case status
126
+ when 'problem'
127
+ logger.debug("updating @times last_problem")
128
+ @times[:last_problem] = t
129
+ when 'recovery'
130
+ logger.debug("updating @times last_recovery")
131
+ @times[:last_recovery] = t
132
+ when 'acknowledgement'
133
+ logger.debug("updating @times last_ack")
134
+ @times[:last_ack] = t
135
+ end
136
+ end
137
+ logger.debug("@times: #{@times.inspect}")
138
+ end
139
+
140
+ def check_timers
141
+ t = Time.now.to_i
142
+ breach = nil
143
+ @logger.debug("check_timers: inspecting @times #{@times.inspect}")
144
+ case
145
+ when @times[:last_problem] < (t - @max_latency)
146
+ breach = "haven't seen a test problem notification in the last #{@max_latency} seconds"
147
+ when @times[:last_recovery] < (t - @max_latency)
148
+ breach = "haven't seen a test recovery notification in the last #{@max_latency} seconds"
149
+ end
150
+
151
+ unless @flapjack_ok || breach
152
+ emit_jabber("Flapjack Self Monitoring is OK")
153
+ emit_pagerduty("Flapjack Self Monitoring is OK", 'resolve')
154
+ end
155
+
156
+ @flapjack_ok = !breach
157
+
158
+ return unless breach
159
+ @logger.error("Self monitoring has detected the following breach: #{breach}")
160
+ summary = "Flapjack Self Monitoring is Critical: #{breach} for #{@check_matcher}, "
161
+ summary += "from #{@hostname} at #{Time.now}"
162
+
163
+ if !@last_alert or @last_alert < (t - 55)
164
+
165
+ emit_jabber(summary)
166
+ emit_pagerduty(summary, 'trigger')
167
+
168
+ if !@last_alert or @last_alert < (t - 55)
169
+ msg = "NOTICE: Self monitoring has detected a failure and is unable to tell "
170
+ msg += "anyone about it. DON'T PANIC."
171
+ @logger.error msg
172
+ end
173
+
174
+ end
175
+ end
176
+
177
+ def emit_jabber(summary)
178
+ if @config['rooms'] && @config['rooms'].length > 0
179
+ @config['rooms'].each do |room|
180
+ say(room, summary, :groupchat)
181
+ end
182
+ @last_alert = Time.now.to_i
183
+ end
184
+ end
185
+
186
+ def emit_pagerduty(summary, event_type = 'trigger')
187
+ if @config['pagerduty_contact']
188
+ pagerduty_event = { :service_key => @config['pagerduty_contact'],
189
+ :incident_key => "Flapjack Self Monitoring from #{@hostname}",
190
+ :event_type => event_type,
191
+ :description => summary }
192
+ status, response = send_pagerduty_event(pagerduty_event)
193
+ if status == 200
194
+ @logger.debug("successfully sent pagerduty event")
195
+ @last_alert = Time.now.to_i
196
+ else
197
+ @logger.error("pagerduty returned #{status} #{response.inspect}")
198
+ end
199
+ end
200
+ end
201
+
202
+ def say(to, msg, using = :chat)
203
+ @logger.debug("Sending a jabber message to: #{to.to_s}, using: #{using.to_s}, message: #{msg}")
204
+ write Blather::Stanza::Message.new(to, msg, using)
205
+ end
206
+
207
+ def send_pagerduty_event(event)
208
+ options = { :body => Yajl::Encoder.encode(event) }
209
+ http = EM::HttpRequest.new(@pagerduty_events_api_url).post(options)
210
+ response = Yajl::Parser.parse(http.response)
211
+ status = http.response_header.status
212
+ logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
213
+ [status, response]
214
+ end
215
+
216
+ def main
217
+ logger.debug("New oobetet pikelet with the following options: #{@config.inspect}")
218
+
219
+ keepalive_timer = EM::Synchrony.add_periodic_timer(60) do
220
+ logger.debug("calling keepalive on the jabber connection")
221
+ write(' ') if connected?
222
+ end
223
+
224
+ setup
225
+ register_handlers
226
+ connect # Blather::Client.connect
227
+
228
+ until should_quit?
229
+ EM::Synchrony.sleep(10)
230
+ check_timers
231
+ end
232
+
233
+ keepalive_timer.cancel
234
+ end
235
+
236
+ end
237
+ end
238
+ end
239
+
240
+
241
+
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'em-synchrony'
4
+ require 'em-synchrony/em-http'
5
+
6
+ require 'yajl/json_gem'
7
+
8
+ require 'flapjack/data/entity_check'
9
+ require 'flapjack/data/global'
10
+ require 'flapjack/redis_pool'
11
+
12
+ require 'flapjack/gateways/base'
13
+
14
+ module Flapjack
15
+
16
+ module Gateways
17
+
18
+ class Pagerduty
19
+ include Flapjack::Gateways::Generic
20
+
21
+ PAGERDUTY_EVENTS_API_URL = 'https://events.pagerduty.com/generic/2010-04-15/create_event.json'
22
+ SEM_PAGERDUTY_ACKS_RUNNING = 'sem_pagerduty_acks_running'
23
+
24
+ alias_method :generic_bootstrap, :bootstrap
25
+ alias_method :generic_cleanup, :cleanup
26
+
27
+ def bootstrap(opts = {})
28
+ generic_bootstrap(opts)
29
+
30
+ @redis_config = opts[:redis_config]
31
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1)
32
+
33
+ logger.debug("New Pagerduty pikelet with the following options: #{@config.inspect}")
34
+
35
+ @pagerduty_acks_started = nil
36
+ end
37
+
38
+ def cleanup
39
+ @redis.empty! if @redis
40
+ @redis_timer.empty! if @redis_timer
41
+ generic_cleanup
42
+ end
43
+
44
+ def add_shutdown_event(opts = {})
45
+ return unless redis = opts[:redis]
46
+ redis.rpush(@config['queue'], JSON.generate('notification_type' => 'shutdown'))
47
+ end
48
+
49
+ def main
50
+ logger.debug("pagerduty gateway - commencing main method")
51
+ raise "Can't connect to the pagerduty API" unless test_pagerduty_connection
52
+
53
+ # TODO: only clear this if there isn't another pagerduty gateway instance running
54
+ # or better, include an instance ID in the semaphore key name
55
+ @redis.del(SEM_PAGERDUTY_ACKS_RUNNING)
56
+
57
+ acknowledgement_timer = EM::Synchrony.add_periodic_timer(10) do
58
+ @redis_timer ||= Flapjack::RedisPool.new(:config => @redis_config, :size => 1)
59
+ find_pagerduty_acknowledgements_if_safe
60
+ end
61
+
62
+ queue = @config['queue']
63
+ events = {}
64
+
65
+ until should_quit?
66
+ logger.debug("pagerduty gateway is going into blpop mode on #{queue}")
67
+ events[queue] = @redis.blpop(queue, 0)
68
+ event = Yajl::Parser.parse(events[queue][1])
69
+ type = event['notification_type']
70
+ logger.debug("pagerduty notification event popped off the queue: " + event.inspect)
71
+ unless 'shutdown'.eql?(type)
72
+ event_id = event['event_id']
73
+ entity, check = event_id.split(':')
74
+ state = event['state']
75
+ summary = event['summary']
76
+ address = event['address']
77
+
78
+ headline = type.upcase
79
+
80
+ case type.downcase
81
+ when 'acknowledgement'
82
+ maint_str = "has been acknowledged"
83
+ pagerduty_type = 'acknowledge'
84
+ when 'problem'
85
+ maint_str = "is #{state.upcase}"
86
+ pagerduty_type = "trigger"
87
+ when 'recovery'
88
+ maint_str = "is #{state.upcase}"
89
+ pagerduty_type = "resolve"
90
+ when 'test'
91
+ maint_str = ""
92
+ pagerduty_type = "trigger"
93
+ headline = "TEST NOTIFICATION"
94
+ end
95
+
96
+ message = "#{type.upcase} - \"#{check}\" on #{entity} #{maint_str} - #{summary}"
97
+
98
+ pagerduty_event = { :service_key => address,
99
+ :incident_key => event_id,
100
+ :event_type => pagerduty_type,
101
+ :description => message }
102
+
103
+ send_pagerduty_event(pagerduty_event)
104
+ end
105
+ end
106
+
107
+ acknowledgement_timer.cancel
108
+ end
109
+
110
+ # considering this as part of the public API -- exposes it for testing.
111
+ def find_pagerduty_acknowledgements_if_safe
112
+
113
+ # ensure we're the only instance of the pagerduty acknowledgement check running (with a naive
114
+ # timeout of five minutes to guard against stale locks caused by crashing code) either in this
115
+ # process or in other processes
116
+ if (@pagerduty_acks_started and @pagerduty_acks_started > (Time.now.to_i - 300)) or
117
+ @redis_timer.get(SEM_PAGERDUTY_ACKS_RUNNING) == 'true'
118
+ logger.debug("skipping looking for acks in pagerduty as this is already happening")
119
+ return
120
+ end
121
+
122
+ @pagerduty_acks_started = Time.now.to_i
123
+ @redis_timer.set(SEM_PAGERDUTY_ACKS_RUNNING, 'true')
124
+ @redis_timer.expire(SEM_PAGERDUTY_ACKS_RUNNING, 300)
125
+
126
+ find_pagerduty_acknowledgements
127
+
128
+ @redis_timer.del(SEM_PAGERDUTY_ACKS_RUNNING)
129
+ @pagerduty_acks_started = nil
130
+ end
131
+
132
+ private
133
+
134
+ def test_pagerduty_connection
135
+ noop = { "service_key" => "11111111111111111111111111111111",
136
+ "incident_key" => "Flapjack is running a NOOP",
137
+ "event_type" => "nop",
138
+ "description" => "I love APIs with noops." }
139
+ code, results = send_pagerduty_event(noop)
140
+ return true if code == 200 && results['status'] =~ /success/i
141
+ logger.error "Error: test_pagerduty_connection: API returned #{code.to_s} #{results.inspect}"
142
+ false
143
+ end
144
+
145
+ def send_pagerduty_event(event)
146
+ options = { :body => Yajl::Encoder.encode(event) }
147
+ http = EM::HttpRequest.new(PAGERDUTY_EVENTS_API_URL).post(options)
148
+ response = Yajl::Parser.parse(http.response)
149
+ status = http.response_header.status
150
+ logger.debug "send_pagerduty_event got a return code of #{status.to_s} - #{response.inspect}"
151
+ [status, response]
152
+ end
153
+
154
+ def find_pagerduty_acknowledgements
155
+
156
+ logger.debug("looking for acks in pagerduty for unack'd problems")
157
+
158
+ unacknowledged_failing_checks = Flapjack::Data::Global.unacknowledged_failing_checks(:redis => @redis_timer)
159
+
160
+ @logger.debug "found unacknowledged failing checks as follows: " + unacknowledged_failing_checks.join(', ')
161
+
162
+ unacknowledged_failing_checks.each do |entity_check|
163
+ pagerduty_credentials = entity_check.pagerduty_credentials(:redis => @redis_timer)
164
+ check = entity_check.check
165
+
166
+ if pagerduty_credentials.empty?
167
+ @logger.debug("No pagerduty credentials found for #{entity_check.entity_name}:#{check}, skipping")
168
+ next
169
+ end
170
+
171
+ # FIXME: try each set of credentials until one works (may have stale contacts turning up)
172
+ options = pagerduty_credentials.first.merge('check' => check)
173
+
174
+ acknowledged = pagerduty_acknowledged?(options)
175
+ if acknowledged.nil?
176
+ @logger.debug "#{check} is not acknowledged in pagerduty, skipping"
177
+ next
178
+ end
179
+
180
+ pg_acknowledged_by = acknowledged[:pg_acknowledged_by]
181
+ @logger.debug "#{check} is acknowledged in pagerduty, creating flapjack acknowledgement... "
182
+ who_text = ""
183
+ if !pg_acknowledged_by.nil? && !pg_acknowledged_by['name'].nil?
184
+ who_text = " by #{pg_acknowledged_by['name']}"
185
+ end
186
+ entity_check.create_acknowledgement('summary' => "Acknowledged on PagerDuty" + who_text)
187
+ end
188
+
189
+ end
190
+
191
+ def pagerduty_acknowledged?(opts)
192
+ subdomain = opts['subdomain']
193
+ username = opts['username']
194
+ password = opts['password']
195
+ check = opts['check']
196
+
197
+ t = Time.now.utc
198
+
199
+ url = 'https://' + subdomain + '.pagerduty.com/api/v1/incidents'
200
+ query = { 'fields' => 'incident_number,status,last_status_change_by',
201
+ 'since' => (t - (60*60*24*7)).iso8601, # the last week
202
+ 'until' => (t + (60*60*24)).iso8601, # 1 day in the future
203
+ 'incident_key' => check,
204
+ 'status' => 'acknowledged' }
205
+
206
+ options = { :head => { 'authorization' => [username, password] },
207
+ :query => query }
208
+
209
+ http = EM::HttpRequest.new(url).get(options)
210
+ # DEBUG flapjack-pagerduty: pagerduty_acknowledged?: decoded response as:
211
+ # {"incidents"=>[{"incident_number"=>40, "status"=>"acknowledged",
212
+ # "last_status_change_by"=>{"id"=>"PO1NWPS", "name"=>"Jesse Reynolds",
213
+ # "email"=>"jesse@bulletproof.net",
214
+ # "html_url"=>"http://bltprf.pagerduty.com/users/PO1NWPS"}}], "limit"=>100, "offset"=>0,
215
+ # "total"=>1}
216
+ begin
217
+ response = Yajl::Parser.parse(http.response)
218
+ rescue Yajl::ParseError
219
+ @logger.error("failed to parse json from a post to #{url} ... response headers and body follows...")
220
+ @logger.error(http.response_header.inspect)
221
+ @logger.error(http.response)
222
+ return nil
223
+ end
224
+ status = http.response_header.status
225
+
226
+ @logger.debug("pagerduty_acknowledged?: decoded response as: #{response.inspect}")
227
+ if response.nil?
228
+ @logger.error('no valid response received from pagerduty!')
229
+ return nil
230
+ end
231
+
232
+ if response['incidents'].nil?
233
+ @logger.error('no incidents found in response')
234
+ return nil
235
+ end
236
+
237
+ return nil if response['incidents'].empty?
238
+
239
+ {:pg_acknowledged_by => response['incidents'].first['last_status_change_by']}
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+