flapjack 0.6.39 → 0.6.40

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