flapjack 0.6.39 → 0.6.40

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 (66) hide show
  1. data/.gitignore +2 -2
  2. data/Gemfile +5 -1
  3. data/README.md +3 -2
  4. data/Rakefile +2 -1
  5. data/bin/flapjack +2 -2
  6. data/bin/flapjack-nagios-receiver +2 -8
  7. data/bin/flapjack-populator +11 -11
  8. data/etc/flapjack_config.yaml.example +28 -0
  9. data/features/steps/events_steps.rb +1 -1
  10. data/features/steps/notifications_steps.rb +7 -4
  11. data/features/support/env.rb +17 -6
  12. data/flapjack.gemspec +1 -0
  13. data/lib/flapjack/api.rb +72 -28
  14. data/lib/flapjack/configuration.rb +9 -1
  15. data/lib/flapjack/coordinator.rb +138 -162
  16. data/lib/flapjack/data/contact.rb +3 -1
  17. data/lib/flapjack/data/entity.rb +10 -1
  18. data/lib/flapjack/data/entity_check.rb +19 -21
  19. data/lib/flapjack/data/event.rb +26 -27
  20. data/lib/flapjack/data/message.rb +45 -0
  21. data/lib/flapjack/data/notification.rb +49 -0
  22. data/lib/flapjack/executive.rb +53 -74
  23. data/lib/flapjack/filters/acknowledgement.rb +14 -11
  24. data/lib/flapjack/jabber.rb +84 -18
  25. data/lib/flapjack/notification/email.rb +67 -37
  26. data/lib/flapjack/notification/sms.rb +40 -28
  27. data/lib/flapjack/oobetet.rb +1 -1
  28. data/lib/flapjack/pagerduty.rb +24 -15
  29. data/lib/flapjack/patches.rb +3 -1
  30. data/lib/flapjack/pikelet.rb +51 -20
  31. data/lib/flapjack/rack_logger.rb +8 -0
  32. data/lib/flapjack/version.rb +1 -1
  33. data/lib/flapjack/web.rb +51 -27
  34. data/spec/lib/flapjack/api_spec.rb +28 -3
  35. data/spec/lib/flapjack/coordinator_spec.rb +69 -43
  36. data/spec/lib/flapjack/data/contact_spec.rb +17 -9
  37. data/spec/lib/flapjack/data/entity_check_spec.rb +0 -25
  38. data/spec/lib/flapjack/data/entity_spec.rb +4 -0
  39. data/spec/lib/flapjack/data/global_spec.rb +6 -0
  40. data/spec/lib/flapjack/data/message_spec.rb +6 -0
  41. data/spec/lib/flapjack/data/notification_spec.rb +6 -0
  42. data/spec/lib/flapjack/executive_spec.rb +2 -2
  43. data/spec/lib/flapjack/jabber_spec.rb +8 -9
  44. data/spec/lib/flapjack/pagerduty_spec.rb +53 -45
  45. data/spec/lib/flapjack/utility_spec.rb +55 -0
  46. data/spec/lib/flapjack/web_spec.rb +7 -5
  47. data/tasks/events.rake +26 -59
  48. data/tasks/profile.rake +366 -0
  49. metadata +30 -19
  50. data/lib/flapjack/notification/common.rb +0 -23
  51. data/lib/flapjack/persistence/couch.rb +0 -5
  52. data/lib/flapjack/persistence/couch/connection.rb +0 -66
  53. data/lib/flapjack/persistence/couch/couch.rb +0 -63
  54. data/lib/flapjack/persistence/data_mapper.rb +0 -3
  55. data/lib/flapjack/persistence/data_mapper/data_mapper.rb +0 -67
  56. data/lib/flapjack/persistence/data_mapper/models/check.rb +0 -90
  57. data/lib/flapjack/persistence/data_mapper/models/check_template.rb +0 -20
  58. data/lib/flapjack/persistence/data_mapper/models/event.rb +0 -19
  59. data/lib/flapjack/persistence/data_mapper/models/node.rb +0 -18
  60. data/lib/flapjack/persistence/data_mapper/models/related_check.rb +0 -15
  61. data/lib/flapjack/persistence/sqlite3.rb +0 -3
  62. data/lib/flapjack/persistence/sqlite3/sqlite3.rb +0 -166
  63. data/lib/flapjack/transports/beanstalkd.rb +0 -50
  64. data/lib/flapjack/transports/result.rb +0 -58
  65. data/lib/flapjack/worker/application.rb +0 -121
  66. data/lib/flapjack/worker/cli.rb +0 -49
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- class CheckTemplate
4
- include DataMapper::Resource
5
-
6
- has n, :checks
7
-
8
- property :id, Serial
9
- property :command, Text, :nullable => false
10
- property :name, String, :nullable => false
11
- property :params, Yaml
12
-
13
- validates_is_unique :command, :name
14
-
15
- def name_for_select
16
- cmd = (self.command.size > 30 ? "#{self.command[0..50]}..." : self.command)
17
- "#{self.name} (#{cmd})"
18
- end
19
-
20
- end
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- class Event
4
- include DataMapper::Resource
5
-
6
- timestamps :at
7
-
8
- belongs_to :check
9
-
10
- property :id, Serial, :key => true
11
- property :check_id, Integer, :nullable => false
12
- #property :check_output, Text, :nullable => false
13
-
14
- # dm-timestamps
15
- property :created_at, DateTime
16
- property :updated_at, DateTime
17
- property :deleted_at, ParanoidDateTime
18
-
19
- end
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- class Node
4
- include DataMapper::Resource
5
-
6
- has n, :checks
7
-
8
- property :fqdn, String, :key => true
9
-
10
- validates_is_unique :fqdn
11
- validates_format :fqdn, :with => /^[0-9|a-z|A-Z|\-|\.]*$/,
12
- :message => "not a RFC1035-formatted FQDN (see section 2.3.1)"
13
-
14
- def hostname
15
- self.fqdn.split('.').first
16
- end
17
-
18
- end
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- class RelatedCheck
4
- include DataMapper::Resource
5
-
6
- belongs_to :parent_check, :class_name => "Check", :child_key => [:parent_id]
7
- belongs_to :child_check, :class_name => "Check", :child_key => [:child_id]
8
-
9
- property :id, Serial, :key => true
10
- #property :parent_check_id, Integer, :nullable => false
11
- #property :child_check_id, Integer, :nullable => false
12
-
13
-
14
-
15
- end
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.join(File.dirname(__FILE__), 'sqlite3', 'sqlite3')
@@ -1,166 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'sqlite3'
4
-
5
- module Flapjack
6
- module Persistence
7
- class Sqlite3
8
- def initialize(options={})
9
- @options = options
10
- @config = OpenStruct.new(options)
11
- @log = @config.log
12
- connect
13
- end
14
-
15
- def any_parents_failed?(check_id)
16
- rows = @db.execute(%(SELECT count(*) FROM "checks" INNER JOIN "related_checks" ON "related_checks".parent_id = "checks".id AND "related_checks".child_id = #{check_id};))
17
- rows.flatten.first != "0"
18
- end
19
-
20
- def save_check(result)
21
- if check = get_check(result[:id])
22
- result[:updated_at] = Time.now
23
- updates = result.map { |key, value| "#{key} = '#{value}'" }.join(', ')
24
- statement = %(UPDATE "checks" SET #{updates} WHERE "id" = #{result[:id]};)
25
- @db.execute(statement)
26
- else
27
- result[:created_at] = Time.now
28
- columns, values = columns_and_values_for(result)
29
- @db.execute(%(INSERT INTO "checks" #{columns} VALUES #{values}))
30
- end
31
- result
32
- end
33
-
34
- def get_check(id)
35
- result = @db.execute2(%(SELECT * FROM "checks" WHERE id = "#{id}"))
36
- return nil unless result[1]
37
- hash = {}
38
- result[0].each_with_index do |key, index|
39
- hash[key] = result[1][index]
40
- end
41
- hash
42
- end
43
-
44
- def delete_check(id)
45
- result = @db.execute2(%(DELETE FROM "checks" WHERE id = "#{id}"))
46
- end
47
-
48
- def all_checks
49
- results = @db.execute2(%(SELECT * FROM "checks";))
50
-
51
- records = results[1..-1].map do |values|
52
- hash = {}
53
- values.each_with_index do |value, index|
54
- hash[results[0][index]] = value
55
- end
56
- hash
57
- end
58
-
59
- records
60
- end
61
-
62
- def save_check_relationship(attrs)
63
- columns, values = columns_and_values_for(attrs)
64
- @db.execute(%(INSERT INTO "related_checks" #{columns} VALUES #{values}))
65
- end
66
-
67
- def all_check_relationships
68
- results = @db.execute2(%(SELECT * FROM "related_checks";))
69
-
70
- records = results[1..-1].map do |values|
71
- hash = {}
72
- values.each_with_index do |value, index|
73
- hash[results[0][index]] = value
74
- end
75
- hash
76
- end
77
-
78
- records
79
- end
80
-
81
- # events
82
- def all_events_for(id)
83
- results = @db.execute2(%(SELECT * FROM "events" WHERE check_id = #{id}))
84
-
85
- records = results[1..-1].map do |values|
86
- hash = {}
87
- values.each_with_index do |value, index|
88
- hash[results[0][index]] = value
89
- end
90
- hash
91
- end
92
-
93
- records
94
- end
95
-
96
- def all_events
97
- results = @db.execute2(%(SELECT * FROM "events";))
98
-
99
- records = results[1..-1].map do |values|
100
- hash = {}
101
- values.each_with_index do |value, index|
102
- hash[results[0][index]] = value
103
- end
104
- hash
105
- end
106
-
107
- records
108
- end
109
-
110
- def create_event(result)
111
- @db.execute(%(INSERT INTO "events" ("check_id", "created_at") VALUES ("#{result.result.check_id}", "#{Time.now}")))
112
- true
113
- end
114
-
115
- private
116
- def connect
117
- raise ArgumentError, "Database location wasn't specified" unless @config.database
118
- @db = ::SQLite3::Database.new(@config.database)
119
-
120
- auto_migrate if @config.auto_migrate
121
- end
122
-
123
- def auto_migrate
124
- statements = [
125
- %(DROP TABLE IF EXISTS "check_templates"),
126
- %(DROP TABLE IF EXISTS "events"),
127
- %(DROP TABLE IF EXISTS "related_checks"),
128
- %(DROP TABLE IF EXISTS "checks"),
129
- %(DROP TABLE IF EXISTS "nodes"),
130
- %(PRAGMA table_info('nodes')),
131
- %(SELECT sqlite_version(*)),
132
- %(CREATE TABLE "nodes" ("fqdn" VARCHAR(50) NOT NULL, PRIMARY KEY("fqdn"))),
133
- %(PRAGMA table_info('checks')),
134
- %(CREATE TABLE "checks" ("created_at" DATETIME, "updated_at" DATETIME, "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "command" TEXT NOT NULL, "params" TEXT DEFAULT NULL, "name" VARCHAR(50) NOT NULL, "enabled" BOOLEAN DEFAULT 'f', "status" INTEGER DEFAULT 0, "deleted_at" DATETIME DEFAULT NULL, "node_fqdn" VARCHAR(50), "check_template_id" INTEGER)),
135
- %(PRAGMA table_info('related_checks')),
136
- %(CREATE TABLE "related_checks" ("parent_id" INTEGER, "child_id" INTEGER, "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)),
137
- %(PRAGMA table_info('events')),
138
- %(CREATE TABLE "events" ("created_at" DATETIME, "updated_at" DATETIME, "check_id" INTEGER NOT NULL, "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "deleted_at" DATETIME DEFAULT NULL)),
139
- %(PRAGMA table_info('check_templates')),
140
- %(CREATE TABLE "check_templates" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "command" TEXT NOT NULL, "name" VARCHAR(50) NOT NULL, "params" TEXT DEFAULT NULL))
141
- ]
142
-
143
- statements.each do |statement|
144
- @db.execute(statement)
145
- end
146
- end
147
-
148
- def columns_and_values_for(result)
149
- @keys = []
150
- @values = []
151
-
152
- result.each_pair do |k,v|
153
- @keys << k
154
- @values << v
155
- end
156
-
157
- keys = "(\"" + @keys.join(%(", ")) + "\")"
158
- values = "(\"" + @values.join(%(", ")) + "\")"
159
-
160
- return keys, values
161
- end
162
-
163
- end
164
- end
165
- end
166
-
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- $: << File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
4
- require 'beanstalk-client'
5
- require 'flapjack/transports/result'
6
-
7
- module Flapjack
8
- module Transport
9
- class Beanstalkd
10
- def initialize(options={})
11
- @options = options
12
- @config = OpenStruct.new(options)
13
- @log = @config.log
14
-
15
- unless @config.host && @config.port && @config.queue_name
16
- raise ArgumentError, "You need to specify a beanstalkd host, port, and queue name to connect to."
17
- end
18
-
19
- connect
20
- end
21
-
22
- def connect
23
- begin
24
- @queue = Beanstalk::Pool.new(["#{@config.host}:#{@config.port}"], @config.queue_name)
25
- rescue Beanstalk::NotConnected => e
26
- @log.error("Couldn't connect to the '#{@config.queue_name}' Beanstalk queue. Retrying in 5 seconds.")
27
- sleep 5
28
- retry
29
- end
30
- end
31
-
32
- def next
33
- begin
34
- job = @queue.reserve # blocks
35
- result = YAML::load(job.body)
36
- Flapjack::Transport::Result.new(:job => job, :result => result)
37
- rescue Beanstalk::NotConnected
38
- @log.error("The '#{@config.queue_name}' Beanstalk queue went away. Waiting 5 seconds, then retrying.")
39
- sleep 5
40
- retry
41
- end
42
- end
43
-
44
- def delete(result)
45
- result.job.delete
46
- end
47
- end
48
- end
49
- end
50
-
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- module Flapjack
4
- module Transport
5
- class Result
6
-
7
- attr_accessor :job, :result
8
-
9
- def initialize(options={})
10
- @job = options[:job]
11
- @result = OpenStruct.new(options[:result])
12
- end
13
-
14
- # Whether a check returns an ok status.
15
- def ok?
16
- @result.retval == 0
17
- end
18
-
19
- # Whether a check has a warning status.
20
- def warning?
21
- @result.retval == 1
22
- end
23
-
24
- # Whether a check has a critical status.
25
- def critical?
26
- @result.retval == 2
27
- end
28
-
29
- # Human readable representation of the check's return value.
30
- def status
31
- case @result.retval
32
- when 0 ; "ok"
33
- when 1 ; "warning"
34
- when 2 ; "critical"
35
- end
36
- end
37
-
38
- # FIXME: there is a *lot* of duplication here - implement a proxy
39
- # object pattern?
40
- def id
41
- @result.check_id
42
- end
43
-
44
- def check_id
45
- @result.check_id
46
- end
47
-
48
- def command
49
- @result.command
50
- end
51
-
52
- def frequency
53
- @result.frequency
54
- end
55
-
56
- end
57
- end
58
- end
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'log4r'
4
- require 'log4r/outputter/syslogoutputter'
5
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'patches'))
6
-
7
- module Flapjack
8
- module Worker
9
- class Application
10
-
11
- # boots the worker
12
- def self.run(options={})
13
- app = self.new(options)
14
- app.setup_loggers
15
- app.setup_config
16
- app.setup_queues
17
-
18
- app
19
- end
20
-
21
- attr_accessor :log
22
-
23
- def initialize(options={})
24
- @log = options[:log]
25
- @options = options
26
-
27
- setup_event_handlers
28
- end
29
-
30
-
31
- def setup_event_handlers
32
- at_exit do
33
- @log.info("Shutting down")
34
- end
35
-
36
- trap("INT") do
37
- puts "Caught shutdown signal, cleaning up."
38
- exit
39
- end
40
- end
41
-
42
- def setup_loggers
43
- unless @log
44
- @log = Log4r::Logger.new("worker")
45
- @log.add(Log4r::StdoutOutputter.new("worker"))
46
- @log.add(Log4r::SyslogOutputter.new("worker"))
47
- end
48
- end
49
-
50
- def setup_config
51
- @config = OpenStruct.new(@options)
52
- end
53
-
54
- def setup_queues
55
- defaults = { :backend => :beanstalkd,
56
- :host => 'localhost',
57
- :port => '11300',
58
- :log => @log }
59
- config = defaults.merge(@config.transport || {})
60
- basedir = config.delete(:basedir) || File.join(File.dirname(__FILE__), '..', 'transports')
61
-
62
- %w(results checks).each do |queue_name|
63
-
64
- queue_config = config.merge(:queue_name => queue_name)
65
-
66
- class_name = config[:backend].to_s.camel_case
67
- filename = File.expand_path(File.join(basedir, "#{config[:backend]}.rb"))
68
-
69
- @log.info("Loading the #{class_name} transport for queue: #{queue_name}.")
70
-
71
- begin
72
- require filename
73
- transport = Flapjack::Transport.const_get("#{class_name}")
74
- queue = transport.new(queue_config)
75
- instance_variable_set("@#{queue_name}_queue", queue)
76
- rescue LoadError => e
77
- @log.warning("Attempted to load #{class_name} transport, but it doesn't exist!")
78
- @log.warning("Exiting.")
79
- raise # preserves original exception
80
- end
81
- end
82
- end
83
-
84
- def log(level, opts={})
85
- if opts[:data]
86
- @log.method(level).call(pp opts[:data])
87
- else
88
- @log.method(level).call(opts[:message])
89
- end
90
- end
91
-
92
- def process_check
93
- @log.info("Waiting for check...")
94
- check = @checks_queue.next
95
- @log.info("Processing check with id #{check.check_id}")
96
-
97
- command = "sh -c '#{check.command}'"
98
- @log.info("Executing check: #{command}")
99
-
100
- output = `#{command}`
101
- return_value = $?.exitstatus
102
-
103
- @log.info("Sending result.")
104
- @results_queue.put({:check_id => check.check_id, :output => output, :retval => return_value})
105
- @log.info("Returning check to transport.")
106
- @checks_queue.put({:check_id => check.check_id, :command => check.command, :frequency => check.frequency})
107
-
108
- @log.info("Cleaning up check.")
109
- @checks_queue.delete(check)
110
- end
111
-
112
- def main
113
- @log.info("Booting main loop.")
114
- loop do
115
- process_check
116
- end
117
- end
118
-
119
- end
120
- end
121
- end