flapjack 1.3.0 → 1.4.0rc1

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -1
  3. data/bin/flapjack +11 -6
  4. data/etc/flapjack_config.yaml.example +4 -0
  5. data/features/steps/events_steps.rb +3 -3
  6. data/features/support/env.rb +2 -1
  7. data/lib/flapjack.rb +6 -0
  8. data/lib/flapjack/cli/flapper.rb +5 -0
  9. data/lib/flapjack/cli/import.rb +5 -0
  10. data/lib/flapjack/cli/maintenance.rb +5 -0
  11. data/lib/flapjack/cli/purge.rb +5 -0
  12. data/lib/flapjack/cli/receiver.rb +5 -0
  13. data/lib/flapjack/cli/server.rb +5 -0
  14. data/lib/flapjack/cli/simulate.rb +5 -0
  15. data/lib/flapjack/data/contact.rb +22 -35
  16. data/lib/flapjack/data/entity_check.rb +2 -2
  17. data/lib/flapjack/data/event.rb +2 -1
  18. data/lib/flapjack/data/notification.rb +4 -4
  19. data/lib/flapjack/gateways/aws_sns.rb +6 -11
  20. data/lib/flapjack/gateways/email.rb +18 -29
  21. data/lib/flapjack/gateways/jabber.rb +7 -13
  22. data/lib/flapjack/gateways/jsonapi.rb +10 -6
  23. data/lib/flapjack/gateways/pagerduty.rb +6 -11
  24. data/lib/flapjack/gateways/sms_messagenet.rb +6 -11
  25. data/lib/flapjack/gateways/sms_nexmo.rb +6 -11
  26. data/lib/flapjack/gateways/sms_twilio.rb +6 -11
  27. data/lib/flapjack/gateways/web.rb +7 -0
  28. data/lib/flapjack/pikelet.rb +3 -1
  29. data/lib/flapjack/utility.rb +14 -0
  30. data/lib/flapjack/version.rb +1 -1
  31. data/spec/lib/flapjack/data/contact_spec.rb +22 -2
  32. data/spec/lib/flapjack/pikelet_spec.rb +1 -0
  33. data/spec/service_consumers/pact_helper.rb +0 -2
  34. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +2095 -2095
  35. data/spec/spec_helper.rb +4 -3
  36. data/spec/support/jsonapi_helper.rb +2 -1
  37. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 198e6405b9d8cf5cf8eecb207b3a966ab1ec3b51
4
- data.tar.gz: 74a6ecc7d159cef46a6e46ae8bf378404967c1ff
3
+ metadata.gz: 430d4ccfe0c3f611279b7235de7ad5a3e621bd91
4
+ data.tar.gz: 4178c1f165b158fd89c719429020dfded2f801f3
5
5
  SHA512:
6
- metadata.gz: 300bb8e1d0f90e8d69fe65ccbae38bf49a96835e7c80884df51661ff11185dfe87715dedbd9fb091ae35eb7888a069a0b814fe37ea1579f387fa07c0efe840bc
7
- data.tar.gz: ff264c0cc717dc2a4b4b188af93bf4ef6e2f5cbdf238250d5b7e99042bc11627f1602fc88b586df7aab2f6f20715b834b87dffd48b409e1a1fa1a1790434041c
6
+ metadata.gz: 48f0e2bc2272f66b74db10bb355c0619dc103f93abc499e5fdbb3aab86c72e7ca825f1d8cacce230c9e56191eeab5f81ae49d038d03026d186225cdbe90c53b7
7
+ data.tar.gz: 4f7c9dd297ae3c2d7cc8fafd66bba4479e281f0321eb7f2994c9acf1cf3f3594710b199e8e9a2bdc2f7220eeb7659a2a4dfa110102b6f89a166741111ceb8ae9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Flapjack Changelog
2
2
 
3
+ # 1.4.0rc1 - 2015-03-12
4
+ - Bug: API : Wrong Timezone doesn't cause 422 status and makes GET /contacts crash #791 (@ali-graham)
5
+ - Bug: uncaught exception in Event#initialize: invalid byte sequence in UTF-8 #801 (@ali-graham)
6
+ - Bug: uncaught exception in Web UI: invalid byte sequence in US-ASCII #802 (@ali-graham)
7
+ - Feature: Add bind_address config option for http server pikelets #807 (@mrichar1)
8
+
3
9
  # 1.3.0 - 2015-02-17
4
10
  - No changes
5
11
 
@@ -11,7 +17,7 @@
11
17
  - Bug: Error uninstalling - Error generating or dispatching SMS Nexmo message #789 (@Hobbsee)
12
18
 
13
19
  # 1.3.0rc1 - 2015-02-13
14
- - Feature: Add Nexmo SMS gateway
20
+ - Feature: Add Nexmo SMS gateway #786 (@jsoriano)
15
21
  - Bug: Revert addition of sms_gammu gateway #759 (@ali-graham)
16
22
 
17
23
  # 1.2.2 - 2015-02-10
data/bin/flapjack CHANGED
@@ -14,14 +14,19 @@ program_desc 'Flexible monitoring notification routing system'
14
14
  version Flapjack::VERSION
15
15
 
16
16
  desc 'Configuration file to use'
17
- default_value '/etc/flapjack/flapjack_config.yaml'
18
- arg_name '/path/to/flapjack.yaml'
19
- flag [:c,:config]
17
+ flag [:c,:config],
18
+ :arg_name => '/path/to/flapjack.yaml',
19
+ :default_value => '/etc/flapjack/flapjack_config.yaml'
20
20
 
21
21
  desc 'Environment to boot'
22
- default_value 'production'
23
- arg_name '<environment>'
24
- flag [:n, :env, :environment]
22
+ flag [:n, :env, :environment],
23
+ :arg_name => '<environment>',
24
+ :default_value => 'production'
25
+
26
+ desc 'Force UTF-8 encoding'
27
+ switch [:'force-utf8'],
28
+ :negatable => true,
29
+ :default_value => true
25
30
 
26
31
  accept Array do |value|
27
32
  value.split(/,/).map(&:strip)
@@ -179,6 +179,7 @@ production:
179
179
  # Browsable web interface
180
180
  web:
181
181
  enabled: yes
182
+ #bind_address: 0.0.0.0
182
183
  port: 3080
183
184
  timeout: 300
184
185
  # Seconds between auto_refresh of entities/checks pages. Set to 0 to disable
@@ -197,6 +198,7 @@ production:
197
198
  # HTTP API server
198
199
  jsonapi:
199
200
  enabled: yes
201
+ #bind_address: 0.0.0.0
200
202
  port: 3081
201
203
  timeout: 300
202
204
  access_log: "/var/log/flapjack/jsonapi_access.log"
@@ -401,6 +403,7 @@ development:
401
403
  # Browsable web interface
402
404
  web:
403
405
  enabled: yes
406
+ #bind_address: 0.0.0.0
404
407
  port: 3080
405
408
  timeout: 300
406
409
  # Seconds between auto_refresh of entities/checks pages. Set to 0 to disable
@@ -416,6 +419,7 @@ development:
416
419
  # HTTP API server
417
420
  jsonapi:
418
421
  enabled: yes
422
+ #bind_address: 0.0.0.0
419
423
  port: 3081
420
424
  timeout: 300
421
425
  access_log: "log/jsonapi_access.log"
@@ -362,7 +362,7 @@ end
362
362
 
363
363
  Given /^user (\S+) has the following notification rules:$/ do |contact_id, rules|
364
364
  contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
365
- timezone = contact.timezone
365
+ time_zone = contact.time_zone
366
366
 
367
367
  # delete any autogenerated rules, and do it using redis directly so no new
368
368
  # ones will be created
@@ -384,9 +384,9 @@ Given /^user (\S+) has the following notification rules:$/ do |contact_id, rules
384
384
  }.inject([]) { |memo, time_restriction|
385
385
  case time_restriction
386
386
  when '8-18 weekdays'
387
- weekdays_8_18 = IceCube::Schedule.new(timezone.local(2013,2,1,8,0,0), :duration => 60 * 60 * 10)
387
+ weekdays_8_18 = IceCube::Schedule.new(time_zone.local(2013,2,1,8,0,0), :duration => 60 * 60 * 10)
388
388
  weekdays_8_18.add_recurrence_rule(IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday, :thursday, :friday))
389
- memo << icecube_schedule_to_time_restriction(weekdays_8_18, timezone)
389
+ memo << icecube_schedule_to_time_restriction(weekdays_8_18, time_zone)
390
390
  end
391
391
  } : []
392
392
  rule_data = {:contact_id => contact_id,
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- #
2
+
3
+ Encoding.default_internal = 'UTF-8'
3
4
 
4
5
  require 'delorean'
5
6
  require 'chronic'
data/lib/flapjack.rb CHANGED
@@ -15,5 +15,11 @@ module Flapjack
15
15
  Oj.dump(data, :mode => :compat, :time_format => :ruby, :indent => 0)
16
16
  end
17
17
 
18
+ def self.sanitize(str)
19
+ return str if str.nil? || !str.is_a?(String) || str.valid_encoding?
20
+ return str.scrub('?') if str.respond_to(:scrub)
21
+ str.chars.collect {|c| c.valid_encoding? ? c : '_' }.join
22
+ end
23
+
18
24
  end
19
25
 
@@ -28,6 +28,11 @@ module Flapjack
28
28
  @global_options = global_options
29
29
  @options = options
30
30
 
31
+ if @global_options[:'force-utf8']
32
+ Encoding.default_external = 'UTF-8'
33
+ Encoding.default_internal = 'UTF-8'
34
+ end
35
+
31
36
  @config = Flapjack::Configuration.new
32
37
  @config.load(global_options[:config])
33
38
  @config_env = @config.all
@@ -15,6 +15,11 @@ module Flapjack
15
15
  @global_options = global_options
16
16
  @options = options
17
17
 
18
+ if @global_options[:'force-utf8']
19
+ Encoding.default_external = 'UTF-8'
20
+ Encoding.default_internal = 'UTF-8'
21
+ end
22
+
18
23
  config = Flapjack::Configuration.new
19
24
  config.load(global_options[:config])
20
25
  @config_env = config.all
@@ -17,6 +17,11 @@ module Flapjack
17
17
  @global_options = global_options
18
18
  @options = options
19
19
 
20
+ if @global_options[:'force-utf8']
21
+ Encoding.default_external = 'UTF-8'
22
+ Encoding.default_internal = 'UTF-8'
23
+ end
24
+
20
25
  config = Flapjack::Configuration.new
21
26
  config.load(global_options[:config])
22
27
  @config_env = config.all
@@ -13,6 +13,11 @@ module Flapjack
13
13
  @global_options = global_options
14
14
  @options = options
15
15
 
16
+ if @global_options[:'force-utf8']
17
+ Encoding.default_external = 'UTF-8'
18
+ Encoding.default_internal = 'UTF-8'
19
+ end
20
+
16
21
  config = Flapjack::Configuration.new
17
22
  config.load(global_options[:config])
18
23
  @config_env = config.all
@@ -19,6 +19,11 @@ module Flapjack
19
19
  @global_options = global_options
20
20
  @options = options
21
21
 
22
+ if @global_options[:'force-utf8']
23
+ Encoding.default_external = 'UTF-8'
24
+ Encoding.default_internal = 'UTF-8'
25
+ end
26
+
22
27
  @config = Flapjack::Configuration.new
23
28
  @config.load(global_options[:config])
24
29
  @config_env = @config.all
@@ -12,6 +12,11 @@ module Flapjack
12
12
  @global_options = global_options
13
13
  @options = options
14
14
 
15
+ if @global_options[:'force-utf8']
16
+ Encoding.default_external = 'UTF-8'
17
+ Encoding.default_internal = 'UTF-8'
18
+ end
19
+
15
20
  @config = Flapjack::Configuration.new
16
21
  @config.load(global_options[:config])
17
22
  @config_env = @config.all
@@ -17,6 +17,11 @@ module Flapjack
17
17
  @global_options = global_options
18
18
  @options = options
19
19
 
20
+ if @global_options[:'force-utf8']
21
+ Encoding.default_external = 'UTF-8'
22
+ Encoding.default_internal = 'UTF-8'
23
+ end
24
+
20
25
  config = Flapjack::Configuration.new
21
26
  config.load(global_options[:config])
22
27
  @config_env = config.all
@@ -3,13 +3,15 @@
3
3
  # NB: use of redis.keys probably indicates we should maintain a data
4
4
  # structure to avoid the need for this type of query
5
5
 
6
+ require 'securerandom'
6
7
  require 'set'
8
+
7
9
  require 'ice_cube'
10
+
8
11
  require 'flapjack/data/entity'
12
+ require 'flapjack/data/entity_check'
9
13
  require 'flapjack/data/notification_rule'
10
14
 
11
- require 'securerandom'
12
-
13
15
  module Flapjack
14
16
 
15
17
  module Data
@@ -101,8 +103,10 @@ module Flapjack
101
103
  # TODO may want to make this protected/private, it's only
102
104
  # used in this class
103
105
  def refresh
104
- self.first_name, self.last_name, self.email =
105
- @redis.hmget("contact:#{@id}", 'first_name', 'last_name', 'email')
106
+ fn, ln, em = @redis.hmget("contact:#{@id}", 'first_name', 'last_name', 'email')
107
+ self.first_name = Flapjack.sanitize(fn)
108
+ self.last_name = Flapjack.sanitize(ln)
109
+ self.email = Flapjack.sanitize(em)
106
110
  self.media = @redis.hgetall("contact_media:#{@id}")
107
111
  self.media_intervals = @redis.hgetall("contact_media_intervals:#{self.id}")
108
112
  self.media_rollup_thresholds = @redis.hgetall("contact_media_rollup_thresholds:#{self.id}")
@@ -430,45 +434,30 @@ module Flapjack
430
434
  self.media_list.collect {|medium| "#{self.id}_#{medium}" }
431
435
  end
432
436
 
433
- # return the timezone of the contact, or the system default if none is set
434
- # TODO cache?
435
- def timezone(opts = {})
436
- logger = opts[:logger]
437
-
438
- tz_string = @redis.get("contact_tz:#{self.id}")
439
- tz = opts[:default] if (tz_string.nil? || tz_string.empty?)
440
-
441
- if tz.nil?
442
- begin
443
- tz = ActiveSupport::TimeZone.new(tz_string)
444
- rescue ArgumentError
445
- if logger
446
- logger.warn("Invalid timezone string set for contact #{self.id} or TZ (#{tz_string}), using 'UTC'!")
447
- end
448
- tz = ActiveSupport::TimeZone.new('UTC')
449
- end
450
- end
451
- tz
437
+ def timezone
438
+ @redis.get("contact_tz:#{self.id}")
452
439
  end
453
440
 
454
- # sets or removes the timezone for the contact
455
- def timezone=(tz)
456
- if tz.nil?
441
+ def timezone=(tz_string)
442
+ if tz_string.nil?
457
443
  @redis.del("contact_tz:#{self.id}")
458
- else
459
- # ActiveSupport::TimeZone or String
460
- @redis.set("contact_tz:#{self.id}",
461
- tz.respond_to?(:name) ? tz.name : tz )
444
+ elsif tz_string.is_a?(String) && !ActiveSupport::TimeZone[tz_string].nil?
445
+ @redis.set("contact_tz:#{self.id}", tz_string)
462
446
  end
463
447
  end
464
448
 
449
+ def time_zone
450
+ return nil if self.timezone.nil?
451
+ ActiveSupport::TimeZone[self.timezone]
452
+ end
453
+
465
454
  def to_jsonapi(opts = {})
466
455
  json_data = {
467
456
  "id" => self.id,
468
457
  "first_name" => self.first_name,
469
458
  "last_name" => self.last_name,
470
459
  "email" => self.email,
471
- "timezone" => self.timezone.name,
460
+ "timezone" => self.timezone,
472
461
  "links" => {
473
462
  :entities => opts[:entity_ids] || [],
474
463
  :media => self.media_ids || [],
@@ -521,10 +510,8 @@ module Flapjack
521
510
  tz = contact_data['timezone']
522
511
  if tz.nil?
523
512
  redis.del("contact_tz:#{contact_id}")
524
- else
525
- # ActiveSupport::TimeZone or String
526
- redis.set("contact_tz:#{contact_id}",
527
- tz.respond_to?(:name) ? tz.name : tz )
513
+ elsif tz.is_a?(String) && !ActiveSupport::TimeZone[tz].nil?
514
+ redis.set("contact_tz:#{contact_id}", tz )
528
515
  end
529
516
  end
530
517
  end
@@ -1000,8 +1000,8 @@ module Flapjack
1000
1000
 
1001
1001
  def initialize(entity, check, options = {})
1002
1002
  raise "Redis connection not set" unless @redis = options[:redis]
1003
- raise "Invalid entity (#{entity.inspect})" unless @entity = entity
1004
- raise "Invalid check (#{check.inspect} on #{entity.inspect})" unless @check = check
1003
+ raise "Invalid entity (#{entity.inspect})" unless @entity = Flapjack.sanitize(entity)
1004
+ raise "Invalid check (#{check.inspect} on #{entity.inspect})" unless @check = Flapjack.sanitize(check)
1005
1005
  @key = "#{entity.name}:#{check}"
1006
1006
  if @redis.zscore("all_checks", @key).nil?
1007
1007
  timestamp = options[:timestamp] || Time.now.to_i
@@ -234,7 +234,8 @@ module Flapjack
234
234
  ['type', 'state', 'entity', 'check', 'time', 'summary', 'details',
235
235
  'perfdata', 'acknowledgement_id', 'duration', 'initial_failure_delay',
236
236
  'repeat_failure_delay'].each do |key|
237
- instance_variable_set("@#{key}", attrs[key])
237
+
238
+ instance_variable_set("@#{key}", Flapjack.sanitize(attrs[key]))
238
239
  end
239
240
  # summary is optional. set it to nil if it only contains whitespace
240
241
  @summary = (@summary.is_a?(String) && ! @summary.strip.empty?) ? @summary.strip : nil
@@ -276,13 +276,13 @@ module Flapjack
276
276
 
277
277
  return true if rule.time_restrictions.nil? or rule.time_restrictions.empty?
278
278
 
279
- timezone = contact.timezone(:default => def_tz)
280
- usertime = timezone.now
279
+ time_zone = contact.time_zone || def_tz
280
+ usertime = time_zone.now
281
281
 
282
282
  rule.time_restrictions.any? do |tr|
283
- # add contact's timezone to the time restriction schedule
283
+ # add contact's time_zone to the time restriction schedule
284
284
  schedule = Flapjack::Data::NotificationRule.
285
- time_restriction_to_icecube_schedule(tr, timezone, :logger => options[:logger])
285
+ time_restriction_to_icecube_schedule(tr, time_zone, :logger => options[:logger])
286
286
  schedule && schedule.occurring_at?(usertime)
287
287
  end
288
288
  end
@@ -66,23 +66,18 @@ module Flapjack
66
66
  notification_id = alert.notification_id
67
67
  message_type = alert.rollup ? 'rollup' : 'alert'
68
68
 
69
- my_dir = File.dirname(__FILE__)
70
- sms_template_path = case
71
- when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
72
- @config['templates']["#{message_type}.text"]
73
- else
74
- my_dir + "/aws_sns/#{message_type}.text.erb"
75
- end
76
- sms_template = ERB.new(File.read(sms_template_path), nil, '-')
69
+ sms_template_erb, sms_template =
70
+ load_template(@config['templates'], message_type, 'text',
71
+ File.join(File.dirname(__FILE__), 'aws_sns'))
77
72
 
78
73
  @alert = alert
79
74
  bnd = binding
80
75
 
81
76
  begin
82
- message = sms_template.result(bnd).chomp
77
+ message = sms_template_erb.result(bnd).chomp
83
78
  rescue => e
84
- @logger.error "Error while excuting the ERB for an sms: " +
85
- "ERB being executed: #{sms_template_path}"
79
+ @logger.error "Error while executing the ERB for an sms: " +
80
+ "ERB being executed: #{sms_template}"
86
81
  raise
87
82
  end
88
83
 
@@ -131,44 +131,33 @@ module Flapjack
131
131
 
132
132
  message_type = alert.rollup ? 'rollup' : 'alert'
133
133
 
134
- mydir = File.dirname(__FILE__)
135
- subject_template_path = case
136
- when @config.has_key?('templates') && @config['templates']["#{message_type}_subject.text"]
137
- @config['templates']["#{message_type}_subject.text"]
138
- else
139
- mydir + "/email/#{message_type}_subject.text.erb"
140
- end
141
- text_template_path = case
142
- when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
143
- @config['templates']["#{message_type}.text"]
144
- else
145
- mydir + "/email/#{message_type}.text.erb"
146
- end
147
- html_template_path = case
148
- when @config.has_key?('templates') && @config['templates']["#{message_type}.html"]
149
- @config['templates']["#{message_type}.html"]
150
- else
151
- mydir + "/email/#{message_type}.html.erb"
152
- end
153
- subject_template = ERB.new(File.read(subject_template_path), nil, '-')
154
- text_template = ERB.new(File.read(text_template_path), nil, '-')
155
- html_template = ERB.new(File.read(html_template_path), nil, '-')
134
+ subject_template_erb, subject_template =
135
+ load_template(@config['templates'], "#{message_type}_subject",
136
+ 'text', File.join(File.dirname(__FILE__), 'email'))
137
+
138
+ text_template_erb, text_template =
139
+ load_template(@config['templates'], message_type,
140
+ 'text', File.join(File.dirname(__FILE__), 'email'))
141
+
142
+ html_template_erb, html_template =
143
+ load_template(@config['templates'], message_type,
144
+ 'html', File.join(File.dirname(__FILE__), 'email'))
156
145
 
157
146
  @alert = alert
158
147
  bnd = binding
159
148
 
160
149
  # do some intelligence gathering in case an ERB execution blows up
161
150
  begin
162
- erb_to_be_executed = subject_template_path
163
- subject = subject_template.result(bnd).chomp
151
+ erb_to_be_executed = subject_template
152
+ subject = subject_template_erb.result(bnd).chomp
164
153
 
165
- erb_to_be_executed = text_template_path
166
- body_text = text_template.result(bnd)
154
+ erb_to_be_executed = text_template
155
+ body_text = text_template_erb.result(bnd)
167
156
 
168
- erb_to_be_executed = html_template_path
169
- body_html = html_template.result(bnd)
157
+ erb_to_be_executed = html_template
158
+ body_html = html_template_erb.result(bnd)
170
159
  rescue => e
171
- @logger.error "Error while excuting ERBs for an email: " +
160
+ @logger.error "Error while executing ERBs for an email: " +
172
161
  "ERB being executed: #{erb_to_be_executed}"
173
162
  raise
174
163
  end