flapjack 0.6.43 → 0.6.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,181 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Formats entity/check data for presentation by the API methods in Flapjack::API.
4
-
5
- require 'sinatra/base'
6
-
7
- require 'flapjack/data/entity_check'
8
-
9
- module Flapjack
10
-
11
- class API < Sinatra::Base
12
-
13
- class EntityCheckPresenter
14
-
15
- def initialize(entity_check)
16
- @entity_check = entity_check
17
- end
18
-
19
- def outages(start_time, end_time, options = {})
20
- # hist_states is an array of hashes, with [state, timestamp, summary] keys
21
- hist_states = @entity_check.historical_states(start_time, end_time)
22
- return hist_states if hist_states.empty?
23
-
24
- initial = @entity_check.historical_state_before(hist_states.first[:timestamp])
25
- hist_states.unshift(initial) if initial
26
-
27
- num_states = hist_states.size
28
-
29
- hist_states.each_with_index do |obj, index|
30
- ts = obj.delete(:timestamp)
31
- if index == (num_states - 1)
32
- # last (even if the only one)
33
- obj[:start_time] = start_time ? [ts, start_time].max : ts
34
- obj[:end_time] = end_time
35
- elsif (index == 0)
36
- # initial
37
- obj[:start_time] = start_time ? [ts, start_time].max : ts
38
- obj[:end_time] = hist_states[index + 1][:timestamp]
39
- else
40
- # except for first and last
41
- obj[:start_time] = ts
42
- obj[:end_time] = hist_states[index + 1][:timestamp]
43
- end
44
- obj[:duration] = obj[:end_time] ? (obj[:end_time] - obj[:start_time]) : nil
45
- end
46
-
47
- # p hist_states
48
-
49
- hist_states.reject {|obj| obj[:state] == 'ok'}
50
- end
51
-
52
- def unscheduled_maintenance(start_time, end_time)
53
- # unsched_maintenance is an array of hashes, with [duration, timestamp, summary] keys
54
- unsched_maintenance = @entity_check.maintenances(start_time, end_time,
55
- :scheduled => false)
56
-
57
- # to see if we start in an unscheduled maintenance period, we must check all unscheduled
58
- # maintenances before the period and their durations
59
- start_in_unsched = start_time.nil? ? [] :
60
- @entity_check.maintenances(nil, start_time, :scheduled => false).select {|pu|
61
- pu[:end_time] >= start_time
62
- }
63
-
64
- start_in_unsched + unsched_maintenance
65
- end
66
-
67
- def scheduled_maintenance(start_time, end_time)
68
- # sched_maintenance is an array of hashes, with [duration, timestamp, summary] keys
69
- sched_maintenance = @entity_check.maintenances(start_time, end_time,
70
- :scheduled => true)
71
-
72
- # to see if we start in a scheduled maintenance period, we must check all scheduled
73
- # maintenances before the period and their durations
74
- start_in_sched = start_time.nil? ? [] :
75
- @entity_check.maintenances(nil, start_time, :scheduled => true).select {|ps|
76
- ps[:end_time] >= start_time
77
- }
78
-
79
- start_in_sched + sched_maintenance
80
- end
81
-
82
- # TODO test whether the below overlapping logic is prone to off-by-one
83
- # errors; the numbers may line up more neatly if we consider outages to
84
- # start one second after the maintenance period ends.
85
- #
86
- # TODO test performance with larger data sets
87
- def downtime(start_time, end_time)
88
- sched_maintenances = scheduled_maintenance(start_time, end_time)
89
-
90
- outs = outages(start_time, end_time)
91
-
92
- total_secs = {}
93
- percentages = {}
94
-
95
- outs.collect {|obj| obj[:state]}.uniq.each do |st|
96
- total_secs[st] = 0
97
- percentages[st] = (start_time.nil? || end_time.nil?) ? nil : 0
98
- end
99
-
100
- unless outs.empty?
101
-
102
- # Initially we need to check for cases where a scheduled
103
- # maintenance period is fully covered by an outage period.
104
- # We then create two new outage periods to cover the time around
105
- # the scheduled maintenance period, and remove the original.
106
-
107
- sched_maintenances.each do |sm|
108
-
109
- split_outs = []
110
-
111
- outs.each { |o|
112
- next unless o[:end_time] && (o[:start_time] < sm[:start_time]) &&
113
- (o[:end_time] > sm[:end_time])
114
- o[:delete] = true
115
- split_outs += [{:state => o[:state],
116
- :start_time => o[:start_time],
117
- :end_time => sm[:start_time],
118
- :duration => sm[:start_time] - o[:start_time],
119
- :summary => "#{o[:summary]} [split start]"},
120
- {:state => o[:state],
121
- :start_time => sm[:end_time],
122
- :end_time => o[:end_time],
123
- :duration => o[:end_time] - sm[:end_time],
124
- :summary => "#{o[:summary]} [split finish]"}]
125
- }
126
-
127
- outs.reject! {|o| o[:delete]}
128
- outs += split_outs
129
- # not strictly necessary to keep the data sorted, but
130
- # will make more sense while debgging
131
- outs.sort! {|a,b| a[:start_time] <=> b[:start_time]}
132
- end
133
-
134
- sched_maintenances.each do |sm|
135
-
136
- outs.each do |o|
137
- next unless o[:end_time] && (sm[:start_time] < o[:end_time]) &&
138
- (sm[:end_time] > o[:start_time])
139
-
140
- if sm[:start_time] <= o[:start_time] &&
141
- sm[:end_time] >= o[:end_time]
142
-
143
- # outage is fully overlapped by the scheduled maintenance
144
- o[:delete] = true
145
-
146
- elsif sm[:start_time] <= o[:start_time]
147
- # partially overlapping on the earlier side
148
- o[:start_time] = sm[:end_time]
149
- o[:duration] = o[:end_time] - o[:start_time]
150
- elsif sm[:end_time] >= o[:end_time]
151
- # partially overlapping on the later side
152
- o[:end_time] = sm[:start_time]
153
- o[:duration] = o[:end_time] - o[:start_time]
154
- end
155
- end
156
-
157
- outs.reject! {|o| o[:delete]}
158
- end
159
-
160
- total_secs = outs.inject(total_secs) {|ret, o|
161
- ret[o[:state]] += o[:duration] if o[:duration]
162
- ret
163
- }
164
-
165
- unless (start_time.nil? || end_time.nil?)
166
- total_secs.each_pair do |st, ts|
167
- percentages[st] = (total_secs[st] * 100.0) / (end_time.to_f - start_time.to_f)
168
- end
169
- total_secs['ok'] = (end_time - start_time) - total_secs.values.reduce(:+)
170
- percentages['ok'] = 100 - percentages.values.reduce(:+)
171
- end
172
- end
173
-
174
- {:total_seconds => total_secs, :percentages => percentages, :downtime => outs}
175
- end
176
-
177
- end
178
-
179
- end
180
-
181
- end
@@ -1,66 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Formats entity data for presentation by the API methods in Flapjack::API.
4
- # Currently this just aggregates all of the check data for an entity, leaving
5
- # clients to make any further calculations for themselves.
6
-
7
- require 'sinatra/base'
8
-
9
- require 'flapjack/api/entity_check_presenter'
10
- require 'flapjack/data/entity_check'
11
-
12
- module Flapjack
13
-
14
- class API < Sinatra::Base
15
-
16
- class EntityPresenter
17
-
18
- def initialize(entity, options = {})
19
- @entity = entity
20
- @redis = options[:redis]
21
- end
22
-
23
- def outages(start_time, end_time)
24
- checks.collect {|c|
25
- {:check => c, :outages => check_presenter(c).outages(start_time, end_time)}
26
- }
27
- end
28
-
29
- def unscheduled_maintenance(start_time, end_time)
30
- checks.collect {|c|
31
- {:check => c, :unscheduled_maintenance =>
32
- check_presenter(c).unscheduled_maintenance(start_time, end_time)}
33
- }
34
- end
35
-
36
- def scheduled_maintenance(start_time, end_time)
37
- checks.collect {|c|
38
- {:check => c, :scheduled_maintenance =>
39
- check_presenter(c).scheduled_maintenance(start_time, end_time)}
40
- }
41
- end
42
-
43
- def downtime(start_time, end_time)
44
- checks.collect {|c|
45
- {:check => c, :downtime =>
46
- check_presenter(c).downtime(start_time, end_time)}
47
- }
48
- end
49
-
50
- private
51
-
52
- def checks
53
- @check_list ||= @entity.check_list
54
- end
55
-
56
- def check_presenter(check)
57
- entity_check = Flapjack::Data::EntityCheck.for_entity(@entity, check,
58
- :redis => @redis)
59
- presenter = Flapjack::API::EntityCheckPresenter.new(entity_check)
60
- end
61
-
62
- end
63
-
64
- end
65
-
66
- end
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'ostruct'
4
- require 'optparse'
5
-
6
- class WorkerManagerOptions
7
- def self.parse(args)
8
- options = OpenStruct.new
9
- opts = OptionParser.new do |opts|
10
- opts.banner = "Usage: flapjack-worker-manager <command> [options]"
11
- opts.separator " "
12
- opts.separator " where <command> is one of:"
13
- opts.separator " start start a worker"
14
- opts.separator " stop stop all workers"
15
- opts.separator " restart restart workers"
16
- opts.separator " "
17
- opts.separator " and [options] are:"
18
-
19
- opts.on('-w', '--workers N', 'number of workers to spin up') do |workers|
20
- options.workers = workers.to_i
21
- end
22
- opts.on('-c', '--checks-directory DIR', 'sandboxed check directory') do |dir|
23
- options.check_directory = dir
24
- end
25
- end
26
-
27
- begin
28
- opts.parse!(args)
29
- rescue => e
30
- puts e.message.capitalize + "\n\n"
31
- puts opts
32
- exit 1
33
- end
34
-
35
- options.workers ||= 5
36
-
37
- unless %w(start stop restart).include?(args[0])
38
- puts opts
39
- exit 1
40
- end
41
-
42
- options
43
- end
44
- end
45
-
46
-
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Nothing Flapjack-specific here - feel free to reuse.
4
-
5
- module Flapjack
6
- class Inifile
7
-
8
- def initialize(string)
9
- @data = {}
10
-
11
- string.split("\n").each do |line|
12
- # sections
13
- if line =~ /^\s*\[(.+)\]\s*(;.+)*$/
14
- @current_section = $1
15
- @data[@current_section] ||= {}
16
- end
17
- # parameters
18
- if line =~ /^\s*(.+)\s*=\s*([^;]+)\s*(;.+)*$/ # after = captures up to ; then groups everything after ;
19
- key = $1.strip
20
- value = $2.strip
21
- @data[@current_section][key] = value
22
- end
23
- end
24
- end
25
-
26
- def [](key)
27
- @data[key]
28
- end
29
-
30
- def keys
31
- @data.keys
32
- end
33
-
34
- def self.read(filename)
35
- self.new(File.read(filename))
36
- end
37
-
38
- def all
39
- @data
40
- end
41
-
42
- end
43
- end
44
-
@@ -1,383 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'socket'
4
-
5
- require 'eventmachine'
6
- # the redis/synchrony gems need to be required in this particular order, see
7
- # the redis-rb README for details
8
- require 'hiredis'
9
- require 'em-synchrony'
10
- require 'redis/connection/synchrony'
11
- require 'redis'
12
-
13
- require 'chronic_duration'
14
-
15
- require 'blather/client/client'
16
- require 'em-synchrony/fiber_iterator'
17
- require 'yajl/json_gem'
18
-
19
- require 'flapjack/data/entity_check'
20
- require 'flapjack/pikelet'
21
- require 'flapjack/redis_pool'
22
- require 'flapjack/utility'
23
- require 'flapjack/version'
24
-
25
- module Flapjack
26
-
27
- class Jabber < Blather::Client
28
-
29
- include Flapjack::GenericPikelet
30
- include Flapjack::Utility
31
-
32
- log = Logger.new(STDOUT)
33
- # log.level = Logger::DEBUG
34
- log.level = Logger::INFO
35
- Blather.logger = log
36
-
37
- alias_method :generic_bootstrap, :bootstrap
38
- alias_method :generic_cleanup, :cleanup
39
-
40
- def bootstrap(opts = {})
41
- generic_bootstrap(opts)
42
-
43
- @redis_config = opts[:redis_config]
44
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1)
45
-
46
- @buffer = []
47
- @hostname = Socket.gethostname
48
- end
49
-
50
- def cleanup
51
- @redis.empty! if @redis
52
- @redis_handler.empty! if @redis_handler
53
- generic_cleanup
54
- end
55
-
56
- def setup
57
- @flapjack_jid = Blather::JID.new((@config['jabberid'] || 'flapjack') + '/' + @hostname)
58
-
59
- super(@flapjack_jid, @config['password'], @config['server'], @config['port'].to_i)
60
-
61
- logger.debug("Building jabber connection with jabberid: " +
62
- @flapjack_jid.to_s + ", port: " + @config['port'].to_s +
63
- ", server: " + @config['server'].to_s + ", password: " +
64
- @config['password'].to_s)
65
-
66
- register_handler :ready do |stanza|
67
- EventMachine::Synchrony.next_tick do
68
- on_ready(stanza)
69
- end
70
- end
71
-
72
- register_handler :message, :groupchat?, :body => /^flapjack:\s+/ do |stanza|
73
- EventMachine::Synchrony.next_tick do
74
- on_groupchat(stanza)
75
- end
76
- end
77
-
78
- register_handler :message, :chat? do |stanza|
79
- EventMachine::Synchrony.next_tick do
80
- on_chat(stanza)
81
- end
82
- end
83
-
84
- register_handler :disconnected do |stanza|
85
- ret = true
86
- EventMachine::Synchrony.next_tick do
87
- ret = on_disconnect(stanza)
88
- end
89
- ret
90
- end
91
- end
92
-
93
- # Join the MUC Chat room after connecting.
94
- def on_ready(stanza)
95
- return if should_quit? && @shutting_down
96
- @redis_handler ||= Flapjack::RedisPool.new(:config => @redis_config, :size => 1)
97
- @connected_at = Time.now.to_i
98
- logger.info("Jabber Connected")
99
- if @config['rooms'] && @config['rooms'].length > 0
100
- @config['rooms'].each do |room|
101
- logger.info("Joining room #{room}")
102
- presence = Blather::Stanza::Presence.new
103
- presence.from = @flapjack_jid
104
- presence.to = Blather::JID.new("#{room}/#{@config['alias']}")
105
- presence << "<x xmlns='http://jabber.org/protocol/muc'/>"
106
- write presence
107
- say(room, "flapjack jabber gateway started at #{Time.now}, hello!", :groupchat)
108
- end
109
- end
110
- return if @buffer.empty?
111
- while stanza = @buffer.shift
112
- @logger.debug("Sending a buffered jabber message to: #{stanza.to}, using: #{stanza.type}, message: #{stanza.body}")
113
- write(stanza)
114
- end
115
- end
116
-
117
- def interpreter(command)
118
- msg = nil
119
- action = nil
120
- entity_check = nil
121
- case
122
- when command =~ /^ACKID\s+(\d+)(?:\s*(.*?)(?:\s*duration.*?(\d+.*\w+.*))?)$/i;
123
- ackid = $1
124
- comment = $2
125
- duration_str = $3
126
-
127
- error = nil
128
- dur = nil
129
-
130
- if comment.nil? || (comment.length == 0)
131
- error = "please provide a comment, eg \"flapjack: ACKID #{$1} AL looking\""
132
- elsif duration_str
133
- # a fairly liberal match above, we'll let chronic_duration do the heavy lifting
134
- dur = ChronicDuration.parse(duration_str)
135
- end
136
-
137
- four_hours = 4 * 60 * 60
138
- duration = (dur.nil? || (dur <= 0)) ? four_hours : dur
139
-
140
- event_id = @redis_handler.hget('unacknowledged_failures', ackid)
141
-
142
- if event_id.nil?
143
- error = "not found"
144
- else
145
- entity_check = Flapjack::Data::EntityCheck.for_event_id(event_id, :redis => @redis_handler)
146
- error = "unknown entity" if entity_check.nil?
147
- end
148
-
149
- if entity_check && entity_check.in_unscheduled_maintenance?
150
- error = "#{event_id} is already acknowledged"
151
- end
152
-
153
- if error
154
- msg = "ERROR - couldn't ACK #{ackid} - #{error}"
155
- else
156
- msg = "ACKing #{entity_check.check} on #{entity_check.entity_name} (#{ackid})"
157
- action = Proc.new {
158
- entity_check.create_acknowledgement('summary' => (comment || ''),
159
- 'acknowledgement_id' => ackid, 'duration' => duration)
160
- }
161
- end
162
-
163
- when command =~ /^help$/
164
- msg = "commands: \n"
165
- msg += " ACKID <id> <comment> [duration: <time spec>] \n"
166
- msg += " find entities matching /pattern/ \n"
167
- msg += " test notifications for <entity>[:<check>] \n"
168
- msg += " identify \n"
169
- msg += " help \n"
170
-
171
- when command =~ /^identify$/
172
- t = Process.times
173
- boot_time = Time.at(@redis_handler.get('boot_time').to_i)
174
- msg = "Flapjack #{Flapjack::VERSION} process #{Process.pid} on #{`hostname -f`.chomp} \n"
175
- msg += "Boot time: #{boot_time}\n"
176
- msg += "User CPU Time: #{t.utime}\n"
177
- msg += "System CPU Time: #{t.stime}\n"
178
- msg += `uname -a`.chomp + "\n"
179
-
180
- when command =~ /^test notifications for\s+([a-z0-9\-\.]+)(:(.+))?$/i
181
- entity_name = $1
182
- check_name = $3 ? $3 : 'test'
183
-
184
- msg = "so you want me to test notifications for entity: #{entity_name}, check: #{check_name} eh? ... well OK!"
185
-
186
- entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => @redis_handler)
187
- if entity
188
- summary = "Testing notifications to all contacts interested in entity: #{entity.name}, check: #{check_name}"
189
-
190
- entity_check = Flapjack::Data::EntityCheck.for_entity(entity, check_name, :redis => @redis_handler)
191
- puts entity_check.inspect
192
- entity_check.test_notifications('summary' => summary)
193
-
194
- else
195
- msg = "yeah, no i can't see #{entity_name} in my systems"
196
- end
197
-
198
- when command =~ /^(find )?entities matching\s+\/(.*)\/.*$/i
199
- pattern = $2.chomp.strip
200
- entity_list = Flapjack::Data::Entity.find_all_name_matching(pattern, :redis => @redis_handler)
201
- max_showable = 30
202
- number_found = entity_list.length
203
- entity_list = entity_list[0..(max_showable - 1)] if number_found > max_showable
204
-
205
- case
206
- when number_found == 0
207
- msg = "found no entities matching /#{pattern}/"
208
- when number_found == 1
209
- msg = "found #{number_found} entity matching /#{pattern}/ ... \n"
210
- when number_found > max_showable
211
- msg = "showing first #{max_showable} of #{number_found} entities found matching /#{pattern}/\n"
212
- else
213
- msg = "found #{number_found} entities matching /#{pattern}/ ... \n"
214
- end
215
- msg += entity_list.join(', ') unless entity_list.empty?
216
-
217
- when command =~ /^(.*)/
218
- words = $1
219
- msg = "what do you mean, '#{words}'? Type 'help' for a list of acceptable commands."
220
-
221
- end
222
-
223
- {:msg => msg, :action => action}
224
- end
225
-
226
- def on_groupchat(stanza)
227
- return if should_quit? && @shutting_down
228
- logger.debug("groupchat message received: #{stanza.inspect}")
229
-
230
- if stanza.body =~ /^flapjack:\s+(.*)/
231
- command = $1
232
- end
233
-
234
- results = interpreter(command)
235
- msg = results[:msg]
236
- action = results[:action]
237
-
238
- if msg || action
239
- say(stanza.from.stripped, msg, :groupchat)
240
- logger.debug("Sent to group chat: #{msg}")
241
- action.call if action
242
- end
243
- end
244
-
245
- def on_chat(stanza)
246
- return if should_quit? && @shutting_down
247
- logger.debug("chat message received: #{stanza.inspect}")
248
-
249
- if stanza.body =~ /^flapjack:\s+(.*)/
250
- command = $1
251
- else
252
- command = stanza.body
253
- end
254
-
255
- results = interpreter(command)
256
- msg = results[:msg]
257
- action = results[:action]
258
-
259
- if msg || action
260
- say(stanza.from.stripped, msg, :chat)
261
- logger.debug("Sent to #{stanza.from.stripped}: #{msg}")
262
- action.call if action
263
- end
264
- end
265
-
266
- # returning true to prevent the reactor loop from stopping
267
- def on_disconnect(stanza)
268
- return true if should_quit? && @shutting_down
269
- logger.warn("jabbers disconnected! reconnecting in 1 second ...")
270
- EventMachine::Timer.new(1) do
271
- connect # Blather::Client.connect
272
- end
273
- true
274
- end
275
-
276
- def say(to, msg, using = :chat)
277
- stanza = Blather::Stanza::Message.new(to, msg, using)
278
- if connected?
279
- @logger.debug("Sending a jabber message to: #{to.to_s}, using: #{using.to_s}, message: #{msg}")
280
- write(stanza)
281
- else
282
- @logger.debug("Buffering a jabber message to: #{to.to_s}, using: #{using.to_s}, message: #{msg}")
283
- @buffer << stanza
284
- end
285
- end
286
-
287
- def add_shutdown_event(opts = {})
288
- return unless redis = opts[:redis]
289
- redis.rpush(@config['queue'], JSON.generate('notification_type' => 'shutdown'))
290
- end
291
-
292
- def main
293
- logger.debug("New Jabber pikelet with the following options: #{@config.inspect}")
294
-
295
- count_timer = EM::Synchrony.add_periodic_timer(30) do
296
- logger.debug("connection count: #{EM.connection_count} #{Time.now.to_s}.#{Time.now.usec.to_s}")
297
- end
298
-
299
- keepalive_timer = EM::Synchrony.add_periodic_timer(60) do
300
- logger.debug("calling keepalive on the jabber connection")
301
- write(' ') if connected?
302
- end
303
-
304
- setup
305
- connect # Blather::Client.connect
306
-
307
- # simplified to use a single queue only as it makes the shutdown logic easier
308
- queue = @config['queue']
309
- events = {}
310
-
311
- until should_quit? && @shutting_down
312
-
313
- # FIXME: should also check if presence has been established in any group chat rooms that are
314
- # configured before starting to process events, otherwise the first few may get lost (send
315
- # before joining the group chat rooms)
316
- if connected?
317
- logger.debug("jabber is connected so commencing blpop on #{queue}")
318
- events[queue] = @redis.blpop(queue, 0)
319
- event = Yajl::Parser.parse(events[queue][1])
320
- type = event['notification_type'] || 'unknown'
321
- logger.debug('jabber notification event received')
322
- logger.debug(event.inspect)
323
- if 'shutdown'.eql?(type)
324
- if should_quit?
325
- @shutting_down = true
326
- EventMachine::Synchrony.next_tick do
327
- # get delays without the next_tick
328
- close # Blather::Client.close
329
- end
330
- end
331
- else
332
- entity, check = event['event_id'].split(':')
333
- state = event['state']
334
- summary = event['summary']
335
- duration = event['duration'] ? time_period_in_words(event['duration']) : '4 hours'
336
- address = event['address']
337
-
338
- logger.debug("processing jabber notification address: #{address}, event: #{entity}:#{check}, state: #{state}, summary: #{summary}")
339
-
340
- ack_str =
341
- event['event_count'] &&
342
- !state.eql?('ok') &&
343
- !'acknowledgement'.eql?(type) &&
344
- !'test'.eql?(type) ?
345
- "::: flapjack: ACKID #{event['event_count']} " : ''
346
-
347
- type = 'unknown' unless type
348
-
349
- maint_str = case type
350
- when 'acknowledgement'
351
- "has been acknowledged, unscheduled maintenance created for #{duration}"
352
- when 'test'
353
- ''
354
- else
355
- "is #{state.upcase}"
356
- end
357
-
358
- # FIXME - should probably put all the message composition stuff in one place so
359
- # the logic isn't duplicated in each notification channel.
360
- # TODO - templatise the messages so they can be customised without changing core code
361
- headline = "test".eql?(type.downcase) ? "TEST NOTIFICATION" : type.upcase
362
-
363
- msg = "#{headline} #{ack_str}::: \"#{check}\" on #{entity} #{maint_str} ::: #{summary}"
364
-
365
- chat_type = :chat
366
- chat_type = :groupchat if @config['rooms'] && @config['rooms'].include?(address)
367
- EventMachine::Synchrony.next_tick do
368
- say(Blather::JID.new(address), msg, chat_type)
369
- end
370
- end
371
- else
372
- logger.debug("not connected, sleep 1 before retry")
373
- EM::Synchrony.sleep(1)
374
- end
375
- end
376
-
377
- count_timer.cancel
378
- keepalive_timer.cancel
379
- end
380
-
381
- end
382
- end
383
-