flapjack 1.3.0 → 1.4.0rc1

Sign up to get free protection for your applications and to get access to all the features.
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