flapjack 0.6.39 → 0.6.40
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -2
- data/Gemfile +5 -1
- data/README.md +3 -2
- data/Rakefile +2 -1
- data/bin/flapjack +2 -2
- data/bin/flapjack-nagios-receiver +2 -8
- data/bin/flapjack-populator +11 -11
- data/etc/flapjack_config.yaml.example +28 -0
- data/features/steps/events_steps.rb +1 -1
- data/features/steps/notifications_steps.rb +7 -4
- data/features/support/env.rb +17 -6
- data/flapjack.gemspec +1 -0
- data/lib/flapjack/api.rb +72 -28
- data/lib/flapjack/configuration.rb +9 -1
- data/lib/flapjack/coordinator.rb +138 -162
- data/lib/flapjack/data/contact.rb +3 -1
- data/lib/flapjack/data/entity.rb +10 -1
- data/lib/flapjack/data/entity_check.rb +19 -21
- data/lib/flapjack/data/event.rb +26 -27
- data/lib/flapjack/data/message.rb +45 -0
- data/lib/flapjack/data/notification.rb +49 -0
- data/lib/flapjack/executive.rb +53 -74
- data/lib/flapjack/filters/acknowledgement.rb +14 -11
- data/lib/flapjack/jabber.rb +84 -18
- data/lib/flapjack/notification/email.rb +67 -37
- data/lib/flapjack/notification/sms.rb +40 -28
- data/lib/flapjack/oobetet.rb +1 -1
- data/lib/flapjack/pagerduty.rb +24 -15
- data/lib/flapjack/patches.rb +3 -1
- data/lib/flapjack/pikelet.rb +51 -20
- data/lib/flapjack/rack_logger.rb +8 -0
- data/lib/flapjack/version.rb +1 -1
- data/lib/flapjack/web.rb +51 -27
- data/spec/lib/flapjack/api_spec.rb +28 -3
- data/spec/lib/flapjack/coordinator_spec.rb +69 -43
- data/spec/lib/flapjack/data/contact_spec.rb +17 -9
- data/spec/lib/flapjack/data/entity_check_spec.rb +0 -25
- data/spec/lib/flapjack/data/entity_spec.rb +4 -0
- data/spec/lib/flapjack/data/global_spec.rb +6 -0
- data/spec/lib/flapjack/data/message_spec.rb +6 -0
- data/spec/lib/flapjack/data/notification_spec.rb +6 -0
- data/spec/lib/flapjack/executive_spec.rb +2 -2
- data/spec/lib/flapjack/jabber_spec.rb +8 -9
- data/spec/lib/flapjack/pagerduty_spec.rb +53 -45
- data/spec/lib/flapjack/utility_spec.rb +55 -0
- data/spec/lib/flapjack/web_spec.rb +7 -5
- data/tasks/events.rake +26 -59
- data/tasks/profile.rake +366 -0
- metadata +30 -19
- data/lib/flapjack/notification/common.rb +0 -23
- data/lib/flapjack/persistence/couch.rb +0 -5
- data/lib/flapjack/persistence/couch/connection.rb +0 -66
- data/lib/flapjack/persistence/couch/couch.rb +0 -63
- data/lib/flapjack/persistence/data_mapper.rb +0 -3
- data/lib/flapjack/persistence/data_mapper/data_mapper.rb +0 -67
- data/lib/flapjack/persistence/data_mapper/models/check.rb +0 -90
- data/lib/flapjack/persistence/data_mapper/models/check_template.rb +0 -20
- data/lib/flapjack/persistence/data_mapper/models/event.rb +0 -19
- data/lib/flapjack/persistence/data_mapper/models/node.rb +0 -18
- data/lib/flapjack/persistence/data_mapper/models/related_check.rb +0 -15
- data/lib/flapjack/persistence/sqlite3.rb +0 -3
- data/lib/flapjack/persistence/sqlite3/sqlite3.rb +0 -166
- data/lib/flapjack/transports/beanstalkd.rb +0 -50
- data/lib/flapjack/transports/result.rb +0 -58
- data/lib/flapjack/worker/application.rb +0 -121
- 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,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
|