flapjack 0.9.6 → 1.0.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +6 -0
  4. data/.travis.yml +20 -16
  5. data/CHANGELOG.md +11 -25
  6. data/Dockerfile +8 -0
  7. data/Gemfile +2 -5
  8. data/bin/flapjack +24 -213
  9. data/etc/flapjack_config.yaml.example +6 -30
  10. data/features/cli.feature +16 -14
  11. data/features/cli_flapjack-feed-events.feature +12 -13
  12. data/features/cli_flapjack-nagios-receiver.feature +14 -15
  13. data/features/cli_flapjack-populator.feature +16 -15
  14. data/features/cli_flapper.feature +12 -12
  15. data/features/cli_receive-events.feature +6 -5
  16. data/features/cli_simulate-failed-check.feature +7 -6
  17. data/features/steps/cli_steps.rb +2 -2
  18. data/features/support/env.rb +1 -0
  19. data/flapjack.gemspec +1 -0
  20. data/lib/flapjack/cli/flapper.rb +200 -0
  21. data/lib/flapjack/cli/import.rb +102 -0
  22. data/lib/flapjack/cli/receiver.rb +656 -0
  23. data/lib/flapjack/cli/server.rb +256 -0
  24. data/lib/flapjack/cli/simulate.rb +180 -0
  25. data/lib/flapjack/configuration.rb +2 -0
  26. data/lib/flapjack/data/entity_check.rb +5 -22
  27. data/lib/flapjack/data/event.rb +7 -12
  28. data/lib/flapjack/gateways/email.rb +4 -1
  29. data/lib/flapjack/gateways/jabber.rb +12 -36
  30. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +6 -6
  31. data/lib/flapjack/gateways/jsonapi/report_methods.rb +5 -3
  32. data/lib/flapjack/gateways/pagerduty.rb +1 -1
  33. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +1 -1
  34. data/lib/flapjack/gateways/web/public/js/modules/contact.js +2 -2
  35. data/lib/flapjack/gateways/web/public/js/modules/entity.js +2 -2
  36. data/lib/flapjack/gateways/web/public/js/modules/medium.js +4 -4
  37. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -1
  38. data/lib/flapjack/gateways/web/views/check.html.erb +7 -7
  39. data/lib/flapjack/gateways/web/views/checks.html.erb +2 -3
  40. data/lib/flapjack/gateways/web/views/contact.html.erb +4 -4
  41. data/lib/flapjack/gateways/web/views/contacts.html.erb +2 -2
  42. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +1 -1
  43. data/lib/flapjack/gateways/web/views/entities.html.erb +1 -1
  44. data/lib/flapjack/gateways/web/views/entity.html.erb +1 -1
  45. data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
  46. data/lib/flapjack/gateways/web/views/layout.erb +10 -10
  47. data/lib/flapjack/gateways/web/views/self_stats.html.erb +1 -1
  48. data/lib/flapjack/gateways/web.rb +36 -7
  49. data/lib/flapjack/pikelet.rb +0 -2
  50. data/lib/flapjack/processor.rb +3 -1
  51. data/lib/flapjack/redis_pool.rb +2 -6
  52. data/lib/flapjack/version.rb +1 -1
  53. data/spec/lib/flapjack/coordinator_spec.rb +3 -3
  54. data/spec/lib/flapjack/data/entity_check_spec.rb +2 -6
  55. data/spec/lib/flapjack/data/event_spec.rb +0 -31
  56. data/spec/lib/flapjack/gateways/email_spec.rb +109 -0
  57. data/spec/lib/flapjack/gateways/jabber_spec.rb +18 -16
  58. data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +12 -24
  59. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +1 -1
  60. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +2 -0
  61. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +2 -0
  62. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +2 -0
  63. data/spec/lib/flapjack/gateways/web_spec.rb +194 -145
  64. data/spec/lib/flapjack/redis_pool_spec.rb +0 -1
  65. data/spec/support/profile_all_formatter.rb +44 -0
  66. data/spec/support/uncolored_doc_formatter.rb +9 -0
  67. data/tasks/benchmarks.rake +0 -4
  68. metadata +28 -38
  69. data/.ruby-version +0 -1
  70. data/Gemfile-ruby1.9 +0 -28
  71. data/Gemfile-ruby1.9.lock +0 -227
  72. data/bin/flapjack-feed-events +0 -124
  73. data/bin/flapjack-nagios-receiver +0 -246
  74. data/bin/flapjack-nsca-receiver +0 -246
  75. data/bin/flapjack-populator +0 -132
  76. data/bin/flapper +0 -152
  77. data/bin/receive-events +0 -179
  78. data/bin/simulate-failed-check +0 -151
  79. data/lib/flapjack/data/migration.rb +0 -36
  80. data/lib/flapjack/gateways/api/contact_methods.rb +0 -369
  81. data/lib/flapjack/gateways/api/entity_check_presenter.rb +0 -218
  82. data/lib/flapjack/gateways/api/entity_methods.rb +0 -361
  83. data/lib/flapjack/gateways/api/entity_presenter.rb +0 -75
  84. data/lib/flapjack/gateways/api/rack/json_params_parser.rb +0 -26
  85. data/lib/flapjack/gateways/api.rb +0 -124
  86. data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +0 -772
  87. data/spec/lib/flapjack/gateways/api/entity_check_presenter_spec.rb +0 -211
  88. data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +0 -863
  89. data/spec/lib/flapjack/gateways/api/entity_presenter_spec.rb +0 -108
  90. data/spec/lib/flapjack/gateways/api_spec.rb +0 -30
@@ -50,17 +50,9 @@ module Flapjack
50
50
  @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
51
51
 
52
52
  @logger = opts[:logger]
53
- @logger.debug("Jabber Initializing")
54
53
 
55
54
  @buffer = []
56
55
  @hostname = Socket.gethostname
57
-
58
- # FIXME: i suspect the following should be in #setup so a config reload updates @identifiers
59
- # I moved it here so the rspec passes :-/
60
- @alias = @config['alias'] || 'flapjack'
61
- @identifiers = ((@config['identifiers'] || []) + [@alias]).uniq
62
- @logger.debug("I will respond to the following identifiers: #{@identifiers.join(', ')}")
63
-
64
56
  super()
65
57
  end
66
58
 
@@ -73,9 +65,7 @@ module Flapjack
73
65
  end
74
66
 
75
67
  def setup
76
- jid = @config['jabberid'] || 'flapjack'
77
- jid += '/' + @hostname unless jid.include?('/')
78
- @flapjack_jid = Blather::JID.new(jid)
68
+ @flapjack_jid = Blather::JID.new((@config['jabberid'] || 'flapjack') + '/' + @hostname)
79
69
 
80
70
  super(@flapjack_jid, @config['password'], @config['server'], @config['port'].to_i)
81
71
 
@@ -90,19 +80,13 @@ module Flapjack
90
80
  end
91
81
  end
92
82
 
93
- body_matchers = @identifiers.inject([]) do |memo, identifier|
94
- @logger.debug("identifier: #{identifier}, memo: #{memo}")
95
- memo << {:body => /^#{identifier}[:\s]/}
96
- memo
97
- end
98
- @logger.debug("body_matchers: #{body_matchers}")
99
- register_handler :message, :groupchat?, body_matchers do |stanza|
83
+ register_handler :message, :groupchat?, :body => /^#{@config['alias']}:\s+/ do |stanza|
100
84
  EventMachine::Synchrony.next_tick do
101
85
  on_groupchat(stanza)
102
86
  end
103
87
  end
104
88
 
105
- register_handler :message, :chat?, :body do |stanza|
89
+ register_handler :message, :chat? do |stanza|
106
90
  EventMachine::Synchrony.next_tick do
107
91
  on_chat(stanza)
108
92
  end
@@ -127,11 +111,11 @@ module Flapjack
127
111
  @logger.info("Joining room #{room}")
128
112
  presence = Blather::Stanza::Presence.new
129
113
  presence.from = @flapjack_jid
130
- presence.to = Blather::JID.new("#{room}/#{@alias}")
114
+ presence.to = Blather::JID.new("#{room}/#{@config['alias']}")
131
115
  presence << "<x xmlns='http://jabber.org/protocol/muc'><history maxstanzas='0'></x>"
132
116
  EventMachine::Synchrony.next_tick do
133
117
  write presence
134
- say(room, "flapjack jabber gateway started at #{Time.now}, hello! Try typing 'help'.", :groupchat)
118
+ say(room, "flapjack jabber gateway started at #{Time.now}, hello!", :groupchat)
135
119
  end
136
120
  end
137
121
  end
@@ -176,7 +160,7 @@ module Flapjack
176
160
  out
177
161
  end
178
162
 
179
- def interpreter(command_raw, from)
163
+ def interpreter(command_raw,from)
180
164
  msg = nil
181
165
  action = nil
182
166
  entity_check = nil
@@ -255,8 +239,7 @@ module Flapjack
255
239
  t = Process.times
256
240
  fqdn = `/bin/hostname -f`.chomp
257
241
  pid = Process.pid
258
- msg = "Flapjack #{Flapjack::VERSION} process #{pid} on #{fqdn}\n" +
259
- "Identifiers: #{@identifiers.join(', ')}\n" +
242
+ msg = "Flapjack #{Flapjack::VERSION} process #{pid} on #{fqdn} \n" +
260
243
  "Boot time: #{@boot_time}\n" +
261
244
  "User CPU Time: #{t.utime}\n" +
262
245
  "System CPU Time: #{t.stime}\n" +
@@ -554,23 +537,18 @@ module Flapjack
554
537
  return if @should_quit
555
538
  @logger.debug("groupchat message received: #{stanza.inspect}")
556
539
 
557
- the_command = nil
558
- @identifiers.each do |identifier|
559
- if stanza.body =~ /^#{identifier}:?\s*(.*)/m
560
- the_command = $1
561
- @logger.debug("matched identifier: #{identifier}, command: #{the_command.inspect}")
562
- break
563
- end
540
+ if stanza.body =~ /^#{@config['alias']}:\s+(.*)/m
541
+ command = $1
564
542
  end
565
543
 
566
544
  from = stanza.from
567
545
 
568
546
  begin
569
- results = interpreter(the_command, from.to_s)
547
+ results = interpreter(command, from.resource.to_s)
570
548
  msg = results[:msg]
571
549
  action = results[:action]
572
550
  rescue => e
573
- @logger.debug("Exception when interpreting command '#{the_command}' - #{e.class}, #{e.message}")
551
+ @logger.error("Exception when interpreting command '#{command}' - #{e.class}, #{e.message}")
574
552
  msg = "Oops, something went wrong processing that command (#{e.class}, #{e.message})"
575
553
  end
576
554
 
@@ -593,10 +571,8 @@ module Flapjack
593
571
  command = stanza.body
594
572
  end
595
573
 
596
- from = stanza.from
597
-
598
574
  begin
599
- results = interpreter(command, from.resource.to_s)
575
+ results = interpreter(command)
600
576
  msg = results[:msg]
601
577
  action = results[:action]
602
578
  rescue => e
@@ -81,7 +81,7 @@ module Flapjack
81
81
  }
82
82
  end
83
83
 
84
- {:outages => result}
84
+ result
85
85
  end
86
86
 
87
87
  def unscheduled_maintenance(start_time, end_time)
@@ -96,7 +96,7 @@ module Flapjack
96
96
  pu[:end_time] >= start_time
97
97
  }
98
98
 
99
- {:unscheduled_maintenances => (start_in_unsched + unsched_maintenance)}
99
+ start_in_unsched + unsched_maintenance
100
100
  end
101
101
 
102
102
  def scheduled_maintenance(start_time, end_time)
@@ -111,7 +111,7 @@ module Flapjack
111
111
  ps[:end_time] >= start_time
112
112
  }
113
113
 
114
- {:scheduled_maintenances => (start_in_sched + sched_maintenance)}
114
+ start_in_sched + sched_maintenance
115
115
  end
116
116
 
117
117
  # TODO test whether the below overlapping logic is prone to off-by-one
@@ -120,7 +120,9 @@ module Flapjack
120
120
  #
121
121
  # TODO test performance with larger data sets
122
122
  def downtime(start_time, end_time)
123
- outs = outage(start_time, end_time)[:outages]
123
+ sched_maintenances = scheduled_maintenance(start_time, end_time)
124
+
125
+ outs = outage(start_time, end_time)
124
126
 
125
127
  total_secs = {}
126
128
  percentages = {}
@@ -137,8 +139,6 @@ module Flapjack
137
139
  # We then create two new outage periods to cover the time around
138
140
  # the scheduled maintenance period, and remove the original.
139
141
 
140
- sched_maintenances = scheduled_maintenance(start_time, end_time)[:scheduled_maintenances]
141
-
142
142
  sched_maintenances.each do |sm|
143
143
 
144
144
  split_outs = []
@@ -27,9 +27,11 @@ module Flapjack
27
27
  end
28
28
 
29
29
  checks = if event_ids.nil?
30
- Flapjack::Data::EntityCheck.find_all(:redis => redis).collect {|check_name|
31
- find_entity_check_by_name(*check_name.split(':', 2))
32
- }
30
+ Flapjack::Data::Entity.all(:redis => redis).collect {|entity|
31
+ entity.check_list.collect {|check_name|
32
+ find_entity_check(entity, check_name)
33
+ }
34
+ }.flatten(2)
33
35
  elsif !event_ids.empty?
34
36
  event_ids.collect {|event_id| find_entity_check_by_name(*event_id.split(':', 2)) }
35
37
  else
@@ -178,7 +178,7 @@ module Flapjack
178
178
  def find_pagerduty_acknowledgements
179
179
  @logger.debug("looking for acks in pagerduty for unack'd problems")
180
180
 
181
- unacknowledged_failing_checks = Flapjack::Data::EntityCheck.unacknowledged_failing(:redis => @redis, :logger => @logger)
181
+ unacknowledged_failing_checks = Flapjack::Data::EntityCheck.unacknowledged_failing(:redis => @redis)
182
182
 
183
183
  @logger.debug "found unacknowledged failing checks as follows: " + unacknowledged_failing_checks.join(', ')
184
184
 
@@ -187,7 +187,7 @@ Backbone.JSONAPIModel = Backbone.Model.extend({
187
187
  this.linked[type].remove(obj);
188
188
  },
189
189
 
190
- urlRoot: function() { return(flapjack.api_url + this.name); },
190
+ urlRoot: function() { return(flapjack.api_url + "/" + this.name); },
191
191
 
192
192
  // can only be called from inside a 'change' event
193
193
  setDirty: function() {
@@ -48,7 +48,7 @@
48
48
 
49
49
  Contact.List = Backbone.JSONAPICollection.extend({
50
50
  model: Contact.Model,
51
- url: function() { return flapjack.api_url + "contacts"; }
51
+ url: function() { return flapjack.api_url + "/contacts"; }
52
52
  });
53
53
 
54
54
  Contact.Views.List = Backbone.View.extend({
@@ -518,4 +518,4 @@
518
518
  }
519
519
  });
520
520
 
521
- })(flapjack, flapjack.module("contact"));
521
+ })(flapjack, flapjack.module("contact"));
@@ -22,7 +22,7 @@
22
22
  Entity.List = Backbone.JSONAPICollection.extend({
23
23
  model: Entity.Model,
24
24
  comparator: 'name',
25
- url: function() { return flapjack.api_url + "entities"; }
25
+ url: function() { return flapjack.api_url + "/entities"; }
26
26
  });
27
27
 
28
- })(flapjack, flapjack.module("entity"));
28
+ })(flapjack, flapjack.module("entity"));
@@ -21,9 +21,9 @@
21
21
  },
22
22
  sync: function(method, model, options) {
23
23
  if ( method == 'create') {
24
- options.url = flapjack.api_url + 'contacts/' + model.contact.get('id') + '/' + this.name;
24
+ options.url = flapjack.api_url + '/contacts/' + model.contact.get('id') + '/' + this.name;
25
25
  } else {
26
- options.url = flapjack.api_url + this.name + '/' + model.contact.get('id') + '_' + model.get('type');
26
+ options.url = flapjack.api_url + '/' + this.name + '/' + model.contact.get('id') + '_' + model.get('type');
27
27
  }
28
28
  Backbone.JSONAPIModel.prototype.sync(method, model, options);
29
29
  }
@@ -33,7 +33,7 @@
33
33
  Medium.List = Backbone.JSONAPICollection.extend({
34
34
  model: Medium.Model,
35
35
  comparator: 'type',
36
- url: function() { return flapjack.api_url + "media"; }
36
+ url: function() { return flapjack.api_url + "/media"; }
37
37
  });
38
38
 
39
- })(flapjack, flapjack.module("medium"));
39
+ })(flapjack, flapjack.module("medium"));
@@ -62,7 +62,7 @@ $(document).ready(function() {
62
62
 
63
63
  function updateData() {
64
64
  var api_url = $('div#data-api-url').data('api-url');
65
- $.get(api_url + 'metrics?filter=event_queue_length', function(json) {
65
+ $.get(api_url + '/metrics?filter=event_queue_length', function(json) {
66
66
  var d = new Date().getTime();
67
67
  var value = {x: d, y: json.event_queue_length}
68
68
  data[0].values.push(value);
@@ -4,7 +4,7 @@
4
4
  current_time = Time.now
5
5
  %>
6
6
  <div class="page-header">
7
- <% entity_link = "/entity/" + u(@entity) %>
7
+ <% entity_link = u(@base_url) + "entity/" << u(@entity) %>
8
8
  <h2><%= h @check %> on <a href="<%= entity_link %>" title="entity summary"><%= h @entity %></a></h2>
9
9
  </div>
10
10
 
@@ -62,7 +62,7 @@
62
62
  <% if @current_unscheduled_maintenance %>
63
63
  <div class="alert alert-warning">
64
64
 
65
- <form action="/end_unscheduled_maintenance/<%= check_path_escaped %>" method="post" class="form-horizontal" role="form">
65
+ <form action="<%= @base_url %>end_unscheduled_maintenance/<%= check_path_escaped %>" method="post" class="form-horizontal" role="form">
66
66
 
67
67
  <div class="form-group">
68
68
  <label class="col-md-3 control-label">State</label>
@@ -132,7 +132,7 @@
132
132
  <div class="alert alert-warning">
133
133
  <% action = @current_unscheduled_maintenance ? "Re-acknowledge" : "Acknowledge" %>
134
134
  <h4><%= action %> alert</h4>
135
- <form action="/acknowledgements/<%= check_path_escaped %>" method="post" class="form-horizontal">
135
+ <form action="<%= @base_url %>acknowledgements/<%= check_path_escaped %>" method="post" class="form-horizontal">
136
136
  <div class="form-group">
137
137
  <div class="col-sm-12 text-left">
138
138
  <label class="col-sm-3 control-label" for="summary">Summary</label>
@@ -307,7 +307,7 @@
307
307
  <td>
308
308
  <% if end_time > current_time.to_i %>
309
309
  <% label = (start_time > current_time.to_i) ? 'Delete' : 'End Now' %>
310
- <form action="/scheduled_maintenances/<%= check_path_escaped %>" method="post">
310
+ <form action="<%= @base_url %>scheduled_maintenances/<%= check_path_escaped %>" method="post">
311
311
  <input type="hidden" name="_method" value="delete">
312
312
  <input type="hidden" name="start_time" value="<%= start_time %>">
313
313
  <button type="submit" class="btn btn-danger"><%= label %></button>
@@ -333,7 +333,7 @@
333
333
  <h3 class="panel-title">Add Scheduled Maintenance</h4>
334
334
  </div>
335
335
  <div class="panel-body">
336
- <form action="/scheduled_maintenances/<%= check_path_escaped %>" method="post" role="form" class="form-horizontal">
336
+ <form action="<%= @base_url %>scheduled_maintenances/<%= check_path_escaped %>" method="post" role="form" class="form-horizontal">
337
337
 
338
338
  <div class="form-group">
339
339
  <label class="col-sm-2 control-label" for="start_time">Start time:</label>
@@ -394,7 +394,7 @@
394
394
  </tr>
395
395
  <% @contacts.sort_by {|c| [c.first_name, c.last_name] }.each do |contact| %>
396
396
  <tr>
397
- <td><a href="/contacts/<%= contact.id %>" title="contact details"><%= h contact.name %></a></td>
397
+ <td><a href="<%= @base_url %>contacts/<%= contact.id %>" title="contact details"><%= h contact.name %></a></td>
398
398
  <td>
399
399
  <% if contact.media && !contact.media.empty? %>
400
400
  <p><%= h contact.media.keys.collect(&:capitalize).join(", ") %></p>
@@ -423,7 +423,7 @@
423
423
  <div class="panel-body">
424
424
  <% if @check_enabled %>
425
425
  <h4>Decommission check</h4>
426
- <form action="/checks/<%= check_path_escaped %>" method="post" style="display:inline-block" class="pull-right">
426
+ <form action="<%= @base_url %>checks/<%= check_path_escaped %>" method="post" style="display:inline-block" class="pull-right">
427
427
  <input type='hidden' name='_method' value='delete'>
428
428
  <button type='submit' class="btn btn-danger decommission-check">Decommission Check</button>
429
429
  </form>
@@ -21,7 +21,7 @@
21
21
  <tbody>
22
22
  <% @entities_sorted.each do |entity| %>
23
23
  <% row_entity = nil %>
24
- <% entity_link = "/entity/" << u(entity) %>
24
+ <% entity_link = u(@base_url) + "entity/" << u(entity) %>
25
25
  <% @states[entity].each do |check, status, summary, changed, updated, in_unscheduled_outage, in_scheduled_outage, notified| %>
26
26
  <%
27
27
  row_colour = case status
@@ -33,8 +33,7 @@
33
33
  status
34
34
  end
35
35
 
36
- check_link = "/check?entity=" << u(entity) << "&amp;check=" << u(check)
37
-
36
+ check_link = u(@base_url) + "check?entity=" << u(entity) << "&amp;check=" << u(check)
38
37
  %>
39
38
  <tr class="<%= row_colour %>">
40
39
  <% unless row_entity && entity == row_entity %>
@@ -81,9 +81,9 @@
81
81
  <td>
82
82
  <% checks.each do |entity_check| %>
83
83
  <% entity, check = entity_check.split(':', 2) %>
84
- <% check_link = "<a href=\"/check?entity=#{u(entity)}&amp;check=#{u(check)}\" title=\"check status\">" +
84
+ <% check_link = "<a href=\"#{u(@base_url)}check?entity=#{u(entity)}&amp;check=#{u(check)}\" title=\"check status\">" +
85
85
  h(check) + "</a>"%>
86
- <a href="/entity/<%= u(entity) %>" title="entity status"><%= h entity %></a> ::
86
+ <a href="<%= @base_url %>entity/<%= u(entity) %>" title="entity status"><%= h entity %></a> ::
87
87
  <%= check_link %> <br />
88
88
  <% end %>
89
89
  </td>
@@ -144,10 +144,10 @@
144
144
  checks = ec[:checks]
145
145
  %>
146
146
  <tr>
147
- <td><a href="/entity/<%= u(entity.name) %>" title="entity status"><%= h entity.name %></a></td>
147
+ <td><a href="<%= @base_url %>entity/<%= u(entity.name) %>" title="entity status"><%= h entity.name %></a></td>
148
148
  <td>
149
149
  <% checks.each do |check| %>
150
- <%= "<a href=\"/check?entity=#{u(entity.name)}&amp;check=#{u(check)}\" title=\"check status\">#{ h check }</a>" %>
150
+ <%= "<a href=\"#{u(@base_url)}check?entity=#{u(entity.name)}&amp;check=#{u(check)}\" title=\"check status\">#{ h check }</a>" %>
151
151
  <% end %>
152
152
  </td>
153
153
  </tr>
@@ -14,14 +14,14 @@
14
14
  </tr>
15
15
  <% @contacts.sort_by {|c| [c.last_name, c.first_name] }.each do |contact| %>
16
16
  <tr>
17
- <td><a href="/contacts/<%= contact.id %>" title="contact details"><%= h contact.name %></a></td>
17
+ <td><a href="<%= @base_url %>contacts/<%= contact.id %>" title="contact details"><%= h contact.name %></a></td>
18
18
  <td><%= h contact.email %></td>
19
19
  </tr>
20
20
  <% end %>
21
21
  </table>
22
22
  <% end %>
23
23
 
24
- <a href="/edit_contacts"/>
24
+ <a href="<%= @base_url %>edit_contacts"/>
25
25
  Edit contacts
26
26
  <span class="label label-danger">beta</span>
27
27
  </a>
@@ -36,7 +36,7 @@
36
36
  <h4 class="modal-title" id="contactModalLabel"><@- is_new ? 'New' : 'Edit' @> Contact</h4>
37
37
  </div>
38
38
  <div class="modal-body">
39
- <form action="/contacts" method="post" role="form" class="form-horizontal">
39
+ <form action="<%= @base_url %>contacts" method="post" role="form" class="form-horizontal">
40
40
 
41
41
  <div id="contactDetails">
42
42
  <div class="form-group">
@@ -16,7 +16,7 @@
16
16
  <tbody>
17
17
  <% @entities.sort.each do |entity| %>
18
18
  <tr>
19
- <td><a href="/entity/<%= CGI.escape(entity) %>"><%= h entity %></a>
19
+ <td><a href="<%= @base_url %>entity/<%= CGI.escape(entity) %>"><%= h entity %></a>
20
20
  </td>
21
21
  </tr>
22
22
  <% end %>
@@ -28,7 +28,7 @@
28
28
  status
29
29
  end
30
30
 
31
- check_link = "/check?entity=" << u(@entity) << "&amp;check=" << u(check)
31
+ check_link = u(@base_url) + "check?entity=" << u(@entity) << "&amp;check=" << u(check)
32
32
 
33
33
  %>
34
34
  <tr class="<%= row_colour %>">
@@ -4,5 +4,5 @@
4
4
  <h2>Summary</h2>
5
5
  </div> <!-- page header -->
6
6
 
7
- <h4><a href="/entities_failing" title="failing entities"><%= h @count_failing_entities %></a> out of <a href="/entities_all" title="all entities"><%= h @count_all_entities %></a> entities have failing checks</h4>
8
- <h4><a href="/checks_failing" title="failing checks"><%= h @count_failing_checks %></a> out of <a href="/checks_all" title="all checks"><%= h @count_all_checks %></a> checks are failing</h4>
7
+ <h4><a href="<% @base_url %>entities_failing" title="failing entities"><%= h @count_failing_entities %></a> out of <a href="<% @base_url %>entities_all" title="all entities"><%= h @count_all_entities %></a> entities have failing checks</h4>
8
+ <h4><a href="<% @base_url %>checks_failing" title="failing checks"><%= h @count_failing_checks %></a> out of <a href="<% @base_url %>checks_all" title="all checks"><%= h @count_all_checks %></a> checks are failing</h4>
@@ -16,7 +16,7 @@
16
16
  <head>
17
17
  <title><%= h include_page_title %></title>
18
18
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
- <link rel="shortcut icon" href="/img/flapjack-favicon-64-32-24-16.ico"> <!-- thank you http://xiconeditor.com/ -->
19
+ <link rel="shortcut icon" href="<%= @base_url %>img/flapjack-favicon-64-32-24-16.ico"> <!-- thank you http://xiconeditor.com/ -->
20
20
  <%= include_required_css %>
21
21
  <%= include_required_js %>
22
22
  </head>
@@ -24,8 +24,8 @@
24
24
  <nav class="navbar navbar-default navbar-inverse" role="navigation">
25
25
 
26
26
  <div class="navbar-header">
27
- <a class="navbar-brand" title="Summary" href="/">
28
- <img alt="Flapjack" class="logo" src="/img/flapjack-2013-notext-transparent-300-300.png">
27
+ <a class="navbar-brand" title="Summary" href="<%= @base_url %>">
28
+ <img alt="Flapjack" class="logo" src="<%= @base_url %><%= @logo_image_file ? "img/branding#{@logo_image_ext}" : @default_logo_url %>">
29
29
  </a>
30
30
  </div>
31
31
 
@@ -33,37 +33,37 @@
33
33
 
34
34
  <ul class="nav navbar-nav">
35
35
  <li<%= include_active?('') %>>
36
- <a title="Summary" href="/">
36
+ <a title="Summary" href="<%= @base_url %>">
37
37
  <i class="fa fa-trophy fa-lg"></i>
38
38
  Summary
39
39
  </a>
40
40
  </li>
41
41
  <li<%= include_active?('entities_all') %>>
42
- <a title="All Entities" href="/entities_all">
42
+ <a title="All Entities" href="<%= @base_url %>entities_all">
43
43
  <i class="fa fa-bullseye fa-lg"></i>
44
44
  All Entities
45
45
  </a>
46
46
  </li>
47
47
  <li<%= include_active?('entities_failing') %>>
48
- <a title="Failing Entities" href="/entities_failing">
48
+ <a title="Failing Entities" href="<%= @base_url %>entities_failing">
49
49
  <i class="fa fa-bullhorn fa-lg"></i>
50
50
  Failing Entities
51
51
  </a>
52
52
  </li>
53
53
  <li<%= include_active?('checks_all') %>>
54
- <a title="All Checks" href="/checks_all">
54
+ <a title="All Checks" href="<%= @base_url %>checks_all">
55
55
  <i class="fa fa-check-circle-o fa-lg"></i>
56
56
  All Checks
57
57
  </a>
58
58
  </li>
59
59
  <li<%= include_active?('checks_failing') %>>
60
- <a title="Failing Checks" href="/checks_failing">
60
+ <a title="Failing Checks" href="<%= @base_url %>checks_failing">
61
61
  <i class="fa fa-times-circle-o fa-lg"></i>
62
62
  Failing Checks
63
63
  </a>
64
64
  </li>
65
65
  <li<%= include_active?('contacts') %>>
66
- <a title="Contacts" href="/contacts">
66
+ <a title="Contacts" href="<%= @base_url %>contacts">
67
67
  <i class="fa fa-users fa-lg"></i>
68
68
  Contacts
69
69
  </a>
@@ -72,7 +72,7 @@
72
72
 
73
73
  <ul class="nav navbar-nav navbar-right">
74
74
  <li<%= include_active?('self_stats') %>>
75
- <a title="Internal Statistics" href="/self_stats">
75
+ <a title="Internal Statistics" href="<%= @base_url %>self_stats">
76
76
  <i class="fa fa-tachometer fa-lg"></i>
77
77
  Internal Statistics
78
78
  </a>
@@ -125,7 +125,7 @@
125
125
  </div>
126
126
 
127
127
  <p>
128
- <a class="btn btn-success" href="/self_stats.json">View as JSON</a>
128
+ <a class="btn btn-success" href="<% @base_url %>self_stats.json">View as JSON</a>
129
129
  Learn how to
130
130
  <a href="https://github.com/flapjack/flapjack/wiki/Gathering-internal-statistics-with-collectd">
131
131
  use these metrics</a>.
@@ -67,6 +67,28 @@ module Flapjack
67
67
  @logger.error "api_url is not configured, parts of the web interface will be broken"
68
68
  end
69
69
 
70
+ @base_url = @config['base_url']
71
+ if @base_url
72
+ @base_url = $1 if @base_url.match(/^(.+\/)$/)
73
+ else
74
+ dummy_url = "/"
75
+ @logger.error "base_url must contain trailing '/', setting it to safe default (#{dummy_url})"
76
+ @base_url = dummy_url
77
+ end
78
+
79
+ # constants won't be exposed to eRb scope
80
+ @default_logo_url = "img/flapjack-2013-notext-transparent-300-300.png"
81
+ @logo_image_file = nil
82
+ @logo_image_ext = nil
83
+
84
+ if logo_image_path = @config['logo_image_path']
85
+ if File.file?(logo_image_path)
86
+ @logo_image_file = logo_image_path
87
+ @logo_image_ext = File.extname(logo_image_path)
88
+ else
89
+ @logger.error "logo_image_path '#{logo_image_path}'' does not point to a valid file."
90
+ end
91
+ end
70
92
  end
71
93
  end
72
94
 
@@ -99,8 +121,17 @@ module Flapjack
99
121
  self.class.instance_variable_get('@logger')
100
122
  end
101
123
 
102
- def api_url
103
- self.class.instance_variable_get('@api_url')
124
+ before do
125
+ @api_url = self.class.instance_variable_get('@api_url')
126
+ @base_url = self.class.instance_variable_get('@base_url')
127
+ @default_logo_url = self.class.instance_variable_get('@default_logo_url')
128
+ @logo_image_file = self.class.instance_variable_get('@logo_image_file')
129
+ @logo_image_ext = self.class.instance_variable_get('@logo_image_ext')
130
+ end
131
+
132
+ get '/img/branding.*' do
133
+ halt(404) unless @logo_image_file && params[:splat].first.eql?(@logo_image_ext[1..-1])
134
+ send_file(@logo_image_file)
104
135
  end
105
136
 
106
137
  get '/' do
@@ -313,7 +344,6 @@ module Flapjack
313
344
  end
314
345
 
315
346
  get '/edit_contacts' do
316
- @api_url = api_url
317
347
  erb 'edit_contacts.html'.to_sym
318
348
  end
319
349
 
@@ -389,7 +419,6 @@ module Flapjack
389
419
  def self_stats
390
420
  @fqdn = `/bin/hostname -f`.chomp
391
421
  @pid = Process.pid
392
- @api_url = api_url
393
422
 
394
423
  @dbsize = redis.dbsize
395
424
  @executive_instances = redis.keys("executive_instance:*").inject({}) do |memo, i|
@@ -454,7 +483,7 @@ module Flapjack
454
483
  def include_required_js
455
484
  if @required_js
456
485
  @required_js.map { |filename|
457
- "<script type='text/javascript' src='#{link_to("/js/#{filename}.js")}'></script>"
486
+ "<script type='text/javascript' src='#{link_to("js/#{filename}.js")}'></script>"
458
487
  }.join("\n ")
459
488
  else
460
489
  ""
@@ -464,7 +493,7 @@ module Flapjack
464
493
  def include_required_css
465
494
  if @required_css
466
495
  @required_css.map { |filename|
467
- %(<link rel="stylesheet" href="#{link_to("/css/#{filename}.css")}" media="screen">)
496
+ %(<link rel="stylesheet" href="#{link_to("css/#{filename}.css")}" media="screen">)
468
497
  }.join("\n ")
469
498
  else
470
499
  ""
@@ -475,7 +504,7 @@ module Flapjack
475
504
  def link_to(url_fragment, mode=:path_only)
476
505
  case mode
477
506
  when :path_only
478
- base = request.script_name
507
+ base = @base_url
479
508
  when :full_url
480
509
  if (request.scheme == 'http' && request.port == 80 ||
481
510
  request.scheme == 'https' && request.port == 443)
@@ -19,7 +19,6 @@ require 'thin'
19
19
 
20
20
  require 'flapjack/notifier'
21
21
  require 'flapjack/processor'
22
- require 'flapjack/gateways/api'
23
22
  require 'flapjack/gateways/jsonapi'
24
23
  require 'flapjack/gateways/jabber'
25
24
  require 'flapjack/gateways/oobetet'
@@ -218,7 +217,6 @@ module Flapjack
218
217
  class Thin < Flapjack::Pikelet::Base
219
218
 
220
219
  PIKELET_TYPES = {'web' => Flapjack::Gateways::Web,
221
- 'api' => Flapjack::Gateways::API,
222
220
  'jsonapi' => Flapjack::Gateways::JSONAPI}
223
221
 
224
222
  def self.create(type, opts = {})
@@ -38,6 +38,8 @@ module Flapjack
38
38
  ncsm_duration_conf = @config['new_check_scheduled_maintenance_duration'] || '100 years'
39
39
  @ncsm_duration = ChronicDuration.parse(ncsm_duration_conf, :keep_zero => true)
40
40
 
41
+ @ncsm_ignore_tags = @config['new_check_scheduled_maintenance_ignore_tags'] || []
42
+
41
43
  @exit_on_queue_empty = !! @config['exit_on_queue_empty']
42
44
 
43
45
  options = { :logger => opts[:logger], :redis => @redis }
@@ -208,7 +210,7 @@ module Flapjack
208
210
  if previous_state.nil?
209
211
  @logger.info("No previous state for event #{event.id}")
210
212
 
211
- if @ncsm_duration > 0
213
+ if @ncsm_duration > 0 && (event.tags & @ncsm_ignore_tags).empty?
212
214
  @logger.info("Setting scheduled maintenance for #{time_period_in_words(@ncsm_duration)}")
213
215
  entity_check.create_scheduled_maintenance(timestamp,
214
216
  @ncsm_duration, :summary => 'Automatically created for new check')