flapjack 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +11 -12
  4. data/CHANGELOG.md +10 -0
  5. data/Gemfile +0 -7
  6. data/Rakefile +0 -1
  7. data/bin/flapjack +2 -0
  8. data/etc/flapjack_config.yaml.example +20 -0
  9. data/features/ack_after_sched_maint.feature +1 -1
  10. data/features/cli.feature +1 -1
  11. data/features/notification_rules.feature +1 -1
  12. data/features/notifications.feature +0 -9
  13. data/features/rollup.feature +1 -1
  14. data/features/steps/events_steps.rb +20 -8
  15. data/features/steps/notifications_steps.rb +62 -75
  16. data/features/support/env.rb +17 -8
  17. data/flapjack.gemspec +4 -4
  18. data/lib/flapjack.rb +3 -0
  19. data/lib/flapjack/cli/import.rb +1 -0
  20. data/lib/flapjack/cli/maintenance.rb +1 -0
  21. data/lib/flapjack/cli/purge.rb +2 -0
  22. data/lib/flapjack/cli/receiver.rb +1 -0
  23. data/lib/flapjack/cli/simulate.rb +1 -0
  24. data/lib/flapjack/data/alert.rb +28 -1
  25. data/lib/flapjack/data/contact.rb +1 -1
  26. data/lib/flapjack/data/entity.rb +18 -8
  27. data/lib/flapjack/data/entity_check.rb +17 -0
  28. data/lib/flapjack/data/event.rb +33 -15
  29. data/lib/flapjack/data/migration.rb +46 -23
  30. data/lib/flapjack/filters/delays.rb +13 -6
  31. data/lib/flapjack/gateways/aws_sns.rb +115 -88
  32. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -1
  33. data/lib/flapjack/gateways/email.rb +145 -135
  34. data/lib/flapjack/gateways/email/alert.html.erb +6 -4
  35. data/lib/flapjack/gateways/email/alert.text.erb +2 -0
  36. data/lib/flapjack/gateways/jabber.rb +61 -1
  37. data/lib/flapjack/gateways/jabber/alert.text.erb +1 -1
  38. data/lib/flapjack/gateways/pagerduty/alert.text.erb +1 -1
  39. data/lib/flapjack/gateways/sms_gammu.rb +119 -0
  40. data/lib/flapjack/gateways/sms_messagenet.rb +95 -67
  41. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +2 -1
  42. data/lib/flapjack/gateways/sms_twilio.rb +102 -74
  43. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +2 -1
  44. data/lib/flapjack/logger.rb +1 -1
  45. data/lib/flapjack/notifier.rb +5 -14
  46. data/lib/flapjack/patches.rb +0 -58
  47. data/lib/flapjack/pikelet.rb +8 -78
  48. data/lib/flapjack/processor.rb +3 -1
  49. data/lib/flapjack/redis_pool.rb +2 -0
  50. data/lib/flapjack/version.rb +1 -1
  51. data/spec/lib/flapjack/data/contact_spec.rb +2 -2
  52. data/spec/lib/flapjack/data/entity_spec.rb +15 -0
  53. data/spec/lib/flapjack/data/event_spec.rb +2 -2
  54. data/spec/lib/flapjack/data/migration_spec.rb +11 -0
  55. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +12 -8
  56. data/spec/lib/flapjack/gateways/email_spec.rb +56 -51
  57. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +17 -12
  58. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +17 -12
  59. data/spec/lib/flapjack/pikelet_spec.rb +9 -23
  60. data/spec/lib/flapjack/redis_pool_spec.rb +1 -0
  61. data/tasks/profile.rake +25 -109
  62. metadata +37 -39
  63. data/Gemfile-ruby1.9 +0 -30
  64. data/Gemfile-ruby1.9.lock +0 -250
  65. data/tasks/benchmarks.rake +0 -237
@@ -32,10 +32,12 @@
32
32
  <td><%= @alert.state_title_case %></td>
33
33
  </tr>
34
34
 
35
- <tr>
36
- <td><strong>Summary</strong></td>
37
- <td><%= @alert.summary %></td>
38
- </tr>
35
+ <% if @alert.summary %>
36
+ <tr>
37
+ <td><strong>Summary</strong></td>
38
+ <td><%= @alert.summary %></td>
39
+ </tr>
40
+ <% end %>
39
41
 
40
42
  <% if @alert.details %>
41
43
  <tr>
@@ -5,7 +5,9 @@ Monitoring has detected the following:
5
5
  Entity: <%= @alert.entity %>
6
6
  Check: <%= @alert.check %>
7
7
  State: <%= @alert.state_title_case %>
8
+ <% if @alert.summary -%>
8
9
  Summary: <%= @alert.summary %>
10
+ <% end -%>
9
11
  <% if @alert.details -%>
10
12
  Details: <%= @alert.details %>
11
13
  <% end -%>
@@ -241,6 +241,7 @@ module Flapjack
241
241
  msg = "commands: \n" +
242
242
  " ACKID <id> <comment> [duration: <time spec>]\n" +
243
243
  " ack entities /pattern/ <comment> [duration: <time spec>]\n" +
244
+ " maint entities /pattern/ <comment> [(start-in|start-at): <time spec>] [duration: <time spec>]\n" +
244
245
  " status entities /pattern/\n" +
245
246
  " ack checks /check_pattern/ on /entity_pattern/ <comment> [duration: <time spec>]\n" +
246
247
  " status checks /check_pattern/ on /entity_pattern/\n" +
@@ -423,6 +424,66 @@ module Flapjack
423
424
  end
424
425
  end
425
426
 
427
+ when /^(?:maint )?entities\s+\/(.+)\/(?:\s*(.*?)(?:\s*start-in:.*?(\w+.*?))?(?:\s*start-at:.*?(\w+.*?))?(?:\s*duration:.*?(\w+.*?))?)$/i
428
+ entity_pattern = $1.strip
429
+ comment = $2 ? $2.strip : nil
430
+ start_in = $3 ? $3.strip : nil
431
+ start_at = $4 ? $4.strip : nil
432
+ duration_str = $5 ? $5.strip : '1 hour'
433
+ maint_duration = ChronicDuration.parse(duration_str)
434
+ entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
435
+
436
+ if comment.nil? || (comment.length == 0)
437
+ comment = "#{from}: Set via chatbot"
438
+ else
439
+ comment = "#{from}: #{comment}"
440
+ end
441
+
442
+ maint_start = case
443
+ when start_in
444
+ Time.now.to_i + ChronicDuration.parse(start_in)
445
+ when start_at
446
+ Chronic.parse(start_at).to_i
447
+ else
448
+ Time.now.to_i
449
+ end
450
+
451
+ if entity_names
452
+ number_found = entity_names.length
453
+ case
454
+ when number_found == 0
455
+ msg = "found no entities matching /#{entity_pattern}/"
456
+ when number_found >= 1
457
+ entities = entity_names.map {|name|
458
+ Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
459
+ }.compact.inject({}) {|memo, entity|
460
+ memo[entity] = entity.check_list.sort
461
+ memo
462
+ }
463
+ if entities.length >= 1
464
+ entities.each_pair do |entity,check_list|
465
+ check_list.each do |check|
466
+ entity_check = Flapjack::Data::EntityCheck.for_entity(entity, check, :redis => @redis)
467
+ entity_check.create_scheduled_maintenance(
468
+ maint_start,
469
+ maint_duration,
470
+ :summary => comment,
471
+ )
472
+ entity_check.update_current_scheduled_maintenance
473
+ end
474
+ end
475
+ msg = entities.inject("Maint list:\n") {|memo,kv|
476
+ kv[1].each {|e| memo << "#{kv[0].name}:#{e}\n" }
477
+ memo
478
+ }
479
+ else
480
+ msg = "found no matching entities with active checks"
481
+ end
482
+ else
483
+ msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
484
+ end
485
+ end
486
+
426
487
  when /^(?:status )?entities\s+\/(.+)\/.*$/im
427
488
  entity_pattern = $1 ? $1.strip : nil
428
489
  entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
@@ -766,4 +827,3 @@ module Flapjack
766
827
 
767
828
  end
768
829
  end
769
-
@@ -7,6 +7,6 @@
7
7
  <% if ['acknowledgement'].include?(@alert.type) -%>
8
8
  has been acknowledged, unscheduled maintenance created for <%= time_period_in_words(@alert.acknowledgement_duration) -%>
9
9
  <% end -%>
10
- <% if @alert.summary && @alert.summary.length > 0 -%>
10
+ <% if @alert.summary && !@alert.summary.empty? -%>
11
11
  , <%= @alert.summary -%>
12
12
  <% end -%>
@@ -5,6 +5,6 @@
5
5
  <% if ['acknowledgement'].include?(@alert.type) -%>
6
6
  has been acknowledged, unscheduled maintenance created for <%= time_period_in_words(@alert.acknowledgement_duration) -%>
7
7
  <% end -%>
8
- <% if @alert.summary && @alert.summary.length > 0 -%>
8
+ <% if @alert.summary && !@alert.summary.empty? -%>
9
9
  , <%= @alert.summary -%>
10
10
  <% end -%>
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'em-synchrony'
4
+ require "em-synchrony/mysql2"
5
+ require 'flapjack/data/alert'
6
+ require 'flapjack/utility'
7
+
8
+ module Flapjack
9
+ module Gateways
10
+ class SmsGammu
11
+ INSERT_QUERY = <<-SQL
12
+ INSERT INTO outbox (InsertIntoDB, TextDecoded, DestinationNumber, CreatorID, Class)
13
+ VALUES ('%s', '%s', '%s', '%s', %s)
14
+ SQL
15
+
16
+ include Flapjack::Utility
17
+
18
+ def initialize(opts = {})
19
+ @config = opts[:config]
20
+ @logger = opts[:logger]
21
+ @redis_config = opts[:redis_config] || {}
22
+
23
+ if @config.nil? || (@config.respond_to?(:empty?) && @config.empty?)
24
+ @logger.error "sms_gammu config is missing"
25
+ return
26
+ end
27
+
28
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1, :logger => @logger)
29
+
30
+ @logger.info("starting")
31
+ @logger.debug("new sms_gammu gateway pikelet with the following options: #{@config.inspect}")
32
+
33
+ @sent = 0
34
+ end
35
+
36
+ def stop
37
+ @logger.info("stopping")
38
+ @should_quit = true
39
+
40
+ redis_uri = @redis_config[:path] ||
41
+ "redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
42
+ shutdown_redis = EM::Hiredis.connect(redis_uri)
43
+ shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
44
+ end
45
+
46
+ def start
47
+ @db = Mysql2::EM::Client.new(:host => @config["mysql_host"],
48
+ :database => @config["mysql_database"],
49
+ :username => @config["mysql_username"],
50
+ :password => @config["mysql_password"])
51
+
52
+ queue = @config['queue']
53
+
54
+ until @should_quit
55
+ begin
56
+ @logger.debug("sms_gammu gateway is going into blpop mode on #{queue}")
57
+ deliver( Flapjack::Data::Alert.next(queue, :redis => @redis, :logger => @logger) )
58
+ rescue => e
59
+ @logger.error "Error generating or dispatching SMS Gammu message: #{e.class}: #{e.message}\n" +
60
+ e.backtrace.join("\n")
61
+ end
62
+ end
63
+ end
64
+
65
+ def deliver(alert)
66
+ @alert = alert
67
+ address = @alert.address
68
+ from = @config["from"]
69
+ message = prepare_message
70
+ errors = []
71
+
72
+ [[from, "SMS from address is missing"],
73
+ [address, "SMS address is missing"]].each do |val_err|
74
+
75
+ next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
76
+ errors << val_err.last
77
+ end
78
+
79
+ unless errors.empty?
80
+ errors.each {|err| @logger.error err }
81
+ return
82
+ end
83
+
84
+ send_message(message, from, address)
85
+ rescue => e
86
+ @logger.error "Error generating or delivering sms to #{contents['address']}: #{e.class}: #{e.message}"
87
+ @logger.error e.backtrace.join("\n")
88
+ raise
89
+ end
90
+
91
+ def prepare_message
92
+ message_type = @alert.rollup ? 'rollup' : 'alert'
93
+ template_path = @config['templates']["#{message_type}.text"]
94
+ template = ERB.new(File.read(template_path), nil, '-')
95
+
96
+ begin
97
+ message = template.result(binding).chomp
98
+ truncate(message, 159)
99
+ rescue => e
100
+ @logger.error "Error while excuting the ERB for an sms: " +
101
+ "ERB being executed: #{template_path}"
102
+ raise
103
+ end
104
+ end
105
+
106
+ def send_message(message, from, to)
107
+ begin
108
+ @db.query(INSERT_QUERY % [Time.now, message, to, from, 1])
109
+ @sent += 1
110
+ @alert.record_send_success!
111
+ @logger.debug "Sent SMS via Gammu"
112
+ rescue => e
113
+ @logger.error "Failed to send SMS via Gammu: #{e.class}, #{e.message}"
114
+ end
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -4,6 +4,8 @@ require 'em-synchrony'
4
4
  require 'em-synchrony/em-http'
5
5
  require 'active_support/inflector'
6
6
 
7
+ require 'flapjack/redis_pool'
8
+
7
9
  require 'flapjack/data/alert'
8
10
  require 'flapjack/utility'
9
11
 
@@ -13,95 +15,121 @@ module Flapjack
13
15
 
14
16
  MESSAGENET_DEFAULT_URL = 'https://www.messagenet.com.au/dotnet/Lodge.asmx/LodgeSMSMessage'
15
17
 
16
- class << self
17
-
18
- include Flapjack::Utility
18
+ include Flapjack::Utility
19
19
 
20
- def start
21
- @sent = 0
22
- end
20
+ def initialize(opts = {})
21
+ @config = opts[:config]
22
+ @logger = opts[:logger]
23
+ @redis_config = opts[:redis_config] || {}
24
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1, :logger => @logger)
23
25
 
24
- def perform(contents)
25
- @logger.debug "Woo, got a notification to send out: #{contents.inspect}"
26
- alert = Flapjack::Data::Alert.new(contents, :logger => @logger)
26
+ @logger.info("starting")
27
+ @logger.debug("new sms_messagenet gateway pikelet with the following options: #{@config.inspect}")
27
28
 
28
- endpoint = @config["endpoint"] || MESSAGENET_DEFAULT_URL
29
- username = @config["username"]
30
- password = @config["password"]
29
+ @sent = 0
30
+ end
31
31
 
32
- address = alert.address
33
- notification_id = alert.notification_id
34
- message_type = alert.rollup ? 'rollup' : 'alert'
32
+ def stop
33
+ @logger.info("stopping")
34
+ @should_quit = true
35
35
 
36
- my_dir = File.dirname(__FILE__)
37
- sms_template_path = case
38
- when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
39
- @config['templates']["#{message_type}.text"]
40
- else
41
- my_dir + "/sms_messagenet/#{message_type}.text.erb"
42
- end
43
- sms_template = ERB.new(File.read(sms_template_path), nil, '-')
36
+ redis_uri = @redis_config[:path] ||
37
+ "redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
38
+ shutdown_redis = EM::Hiredis.connect(redis_uri)
39
+ shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
40
+ end
44
41
 
45
- @alert = alert
46
- bnd = binding
42
+ def start
43
+ queue = @config['queue']
47
44
 
45
+ until @should_quit
48
46
  begin
49
- message = sms_template.result(bnd).chomp
47
+ @logger.debug("sms_messagenet gateway is going into blpop mode on #{queue}")
48
+ deliver( Flapjack::Data::Alert.next(queue, :redis => @redis, :logger => @logger) )
50
49
  rescue => e
51
- @logger.error "Error while excuting the ERB for an sms: " +
52
- "ERB being executed: #{sms_template_path}"
53
- raise
54
- end
55
-
56
- if @config.nil? || (@config.respond_to?(:empty?) && @config.empty?)
57
- @logger.error "Messagenet config is missing"
58
- return
50
+ @logger.error "Error generating or dispatching SMS Messagenet message: #{e.class}: #{e.message}\n" +
51
+ e.backtrace.join("\n")
59
52
  end
53
+ end
54
+ end
60
55
 
61
- errors = []
56
+ def deliver(alert)
57
+ endpoint = @config["endpoint"] || MESSAGENET_DEFAULT_URL
58
+ username = @config["username"]
59
+ password = @config["password"]
60
+
61
+ address = alert.address
62
+ notification_id = alert.notification_id
63
+ message_type = alert.rollup ? 'rollup' : 'alert'
64
+
65
+ my_dir = File.dirname(__FILE__)
66
+ sms_template_path = case
67
+ when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
68
+ @config['templates']["#{message_type}.text"]
69
+ else
70
+ my_dir + "/sms_messagenet/#{message_type}.text.erb"
71
+ end
72
+ sms_template = ERB.new(File.read(sms_template_path), nil, '-')
62
73
 
63
- safe_message = truncate(message, 159)
74
+ @alert = alert
75
+ bnd = binding
64
76
 
65
- [[username, "Messagenet username is missing"],
66
- [password, "Messagenet password is missing"],
67
- [address, "SMS address is missing"],
68
- [notification_id, "Notification id is missing"]].each do |val_err|
77
+ begin
78
+ message = sms_template.result(bnd).chomp
79
+ rescue => e
80
+ @logger.error "Error while excuting the ERB for an sms: " +
81
+ "ERB being executed: #{sms_template_path}"
82
+ raise
83
+ end
69
84
 
70
- next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
71
- errors << val_err.last
72
- end
85
+ if @config.nil? || (@config.respond_to?(:empty?) && @config.empty?)
86
+ @logger.error "Messagenet config is missing"
87
+ return
88
+ end
73
89
 
74
- unless errors.empty?
75
- errors.each {|err| @logger.error err }
76
- return
77
- end
90
+ errors = []
78
91
 
79
- query = {'Username' => username,
80
- 'Pwd' => password,
81
- 'PhoneNumber' => address,
82
- 'PhoneMessage' => safe_message}
92
+ safe_message = truncate(message, 159)
83
93
 
84
- http = EM::HttpRequest.new(endpoint).get(:query => query)
94
+ [[username, "Messagenet username is missing"],
95
+ [password, "Messagenet password is missing"],
96
+ [address, "SMS address is missing"],
97
+ [notification_id, "Notification id is missing"]].each do |val_err|
85
98
 
86
- @logger.debug "server response: #{http.response}"
99
+ next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
100
+ errors << val_err.last
101
+ end
87
102
 
88
- status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
89
- if (status >= 200) && (status <= 206)
90
- @sent += 1
91
- alert.record_send_success!
92
- @logger.debug "Sent SMS via Messagenet, response status is #{status}, " +
93
- "notification_id: #{notification_id}"
94
- else
95
- @logger.error "Failed to send SMS via Messagenet, response status is #{status}, " +
96
- "notification_id: #{notification_id}"
97
- end
98
- rescue => e
99
- @logger.error "Error generating or delivering sms to #{contents['address']}: #{e.class}: #{e.message}"
100
- @logger.error e.backtrace.join("\n")
101
- raise
103
+ unless errors.empty?
104
+ errors.each {|err| @logger.error err }
105
+ return
102
106
  end
103
107
 
108
+ query = {'Username' => username,
109
+ 'Pwd' => password,
110
+ 'PhoneNumber' => address,
111
+ 'PhoneMessage' => safe_message}
112
+
113
+ http = EM::HttpRequest.new(endpoint).get(:query => query)
114
+
115
+ @logger.debug "server response: #{http.response}"
116
+
117
+ status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
118
+ if (status >= 200) && (status <= 206)
119
+ @sent += 1
120
+ alert.record_send_success!
121
+ @logger.debug "Sent SMS via Messagenet, response status is #{status}, " +
122
+ "notification_id: #{notification_id}"
123
+ else
124
+ @logger.error "Failed to send SMS via Messagenet, response status is #{status}, " +
125
+ "notification_id: #{notification_id}"
126
+ end
127
+ rescue => e
128
+ @logger.error "Error generating or delivering sms to #{alert.address}: #{e.class}: #{e.message}"
129
+ @logger.error e.backtrace.join("\n")
130
+ raise
104
131
  end
132
+
105
133
  end
106
134
  end
107
135
  end
@@ -1,5 +1,6 @@
1
+ <% summary = @alert.summary -%>
1
2
  <%= @alert.type_sentence_case %>: '<%= @alert.check %>' on <%= @alert.entity -%>
2
3
  <% unless ['acknowledgement', 'test'].include?(@alert.notification_type) -%>
3
4
  is <%= @alert.state_title_case -%>
4
5
  <% end -%>
5
- at <%= Time.at(@alert.time).strftime('%-d %b %H:%M') %>, <%= @alert.summary -%>
6
+ at <%= Time.at(@alert.time).strftime('%-d %b %H:%M') %><%= (summary.nil? || summary.empty?) ? '' : ", #{summary}" -%>