sensu 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *~
3
+ \#*
4
+ dump.rdb
5
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sensu (0.4.0)
5
+ amqp (= 0.7.4)
6
+ async_sinatra
7
+ em-hiredis
8
+ em-syslog
9
+ json
10
+ thin
11
+ uuidtools
12
+
13
+ GEM
14
+ remote: http://rubygems.org/
15
+ specs:
16
+ amqp (0.7.4)
17
+ eventmachine
18
+ async_sinatra (0.5.0)
19
+ rack (>= 1.2.1)
20
+ sinatra (>= 1.0)
21
+ callsite (0.0.5)
22
+ bundler (~> 1.0.0)
23
+ daemons (1.1.4)
24
+ em-hiredis (0.1.0)
25
+ hiredis (~> 0.3.0)
26
+ em-syslog (0.0.2)
27
+ eventmachine
28
+ em-ventually (0.1.2)
29
+ callsite (~> 0.0.5)
30
+ eventmachine
31
+ eventmachine (0.12.10)
32
+ hiredis (0.3.2)
33
+ json (1.5.4)
34
+ mime-types (1.16)
35
+ minitest (2.5.1)
36
+ rack (1.3.2)
37
+ rake (0.9.2)
38
+ rest-client (1.6.3)
39
+ mime-types (>= 1.16)
40
+ sinatra (1.2.6)
41
+ rack (~> 1.1)
42
+ tilt (< 2.0, >= 1.2.2)
43
+ thin (1.2.11)
44
+ daemons (>= 1.0.9)
45
+ eventmachine (>= 0.12.6)
46
+ rack (>= 1.0.0)
47
+ tilt (1.3.3)
48
+ uuidtools (2.1.2)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ em-ventually
55
+ minitest
56
+ rake
57
+ rest-client
58
+ sensu!
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Sonian Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.org ADDED
@@ -0,0 +1,58 @@
1
+ * Welcome to Sensu
2
+ Sensu is a monitoring system framework, handling the remote execution of checks.
3
+
4
+ Checks can utilize user created plugins, returning an exit status code and outputting to STDOUT.
5
+
6
+ Check results are handled by user created handlers.
7
+
8
+ * License
9
+ Sensu is released under the [[https://github.com/sonian/sensu/blob/master/MIT-LICENSE.txt][MIT license]].
10
+
11
+ * Contributing
12
+ - [[http://help.github.com/fork-a-repo/][Fork]] [[https://github.com/sonian/sensu][Sensu]]
13
+ - Use a [[https://github.com/dchelimsky/rspec/wiki/Topic-Branches][topic branch]]
14
+ - Create a [[http://help.github.com/send-pull-requests/][pull request]]
15
+
16
+ Keep it simple.
17
+
18
+ ** Readme Driven Development
19
+ *** A Client Will
20
+ - Have a set of attributes to describe it, including its responsibilities
21
+ - Send keep-alives to a server
22
+ - Subscribe to a set of queues bound to a set of fanout exchanges, determined by its responsibilities
23
+ - Substitute tokens in check commands with their matching client attribute
24
+ - Receive checks from subscriptions, execute them, and publish the results to a queue with its client name
25
+ - Not allow overlapping check executions of the same name
26
+ - Report when it is unaware of a check it received from a subscription
27
+
28
+ *** A Server Will
29
+ - Subscribe to a queue for check scheduling, another for check results
30
+ - Populate the check scheduling queue using a JSON config file
31
+ - Pull a check from the check scheduling queue and push it onto its associated fanout exchanges
32
+ - Pull check results, storing the latest events for clients, a good result will flush a previous event for that client
33
+ - Create an event when it stops receiving keep-alives from a client, a new keep-alive for the client will clear the event
34
+ - Trigger a event handler, determined by the type of the check that produced the event, providing it with a JSON event file
35
+
36
+ *** An API Will
37
+ - List all current events
38
+ - List all clients and their attributes
39
+ - Show a client and its attributes
40
+ - Remove a client and resolve associated events
41
+
42
+ *** A Plugin Will
43
+ - Output to STDOUT
44
+ - Return a valid exit status code
45
+
46
+ *** A Handler Will
47
+ - Accept a command line argument "-f", for an event file path
48
+ - Parse the JSON event file
49
+ - Handle the event as it wishes
50
+
51
+ ** Testing
52
+ *** Requirements
53
+ - RabbitMQ (default configuration)
54
+ - Redis (default configuration)
55
+
56
+ *** MiniTest
57
+
58
+ : rake test
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => 'test'
5
+
6
+ Rake::TestTask.new do |test|
7
+ test.pattern = "test/*_test.rb"
8
+ end
data/bin/sensu-api ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
4
+ require 'sensu/api'
5
+
6
+ Sensu::API.run
data/bin/sensu-client ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
4
+ require 'sensu/client'
5
+
6
+ Sensu::Client.run
data/bin/sensu-server ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib' unless $:.include?(File.dirname(__FILE__) + '/../lib/')
4
+ require 'sensu/server'
5
+
6
+ Sensu::Server.run
data/lib/sensu.rb ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Sensu
4
+ end
data/lib/sensu/api.rb ADDED
@@ -0,0 +1,137 @@
1
+ require File.join(File.dirname(__FILE__), 'config')
2
+ require 'sinatra/async'
3
+ require 'em-hiredis'
4
+
5
+ module Sensu
6
+ class API < Sinatra::Base
7
+ register Sinatra::Async
8
+
9
+ def self.run(options={})
10
+ EM.run do
11
+ self.setup(options)
12
+ self.run!(:port => @settings['api']['port'])
13
+
14
+ Signal.trap('INT') do
15
+ EM.stop
16
+ end
17
+
18
+ Signal.trap('TERM') do
19
+ EM.stop
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.setup(options={})
25
+ config = Sensu::Config.new(options)
26
+ @settings = config.settings
27
+ set :redis, EM::Hiredis.connect('redis://' + @settings['redis']['host'] + ':' + @settings['redis']['port'].to_s)
28
+ connection = AMQP.connect(symbolize_keys(@settings['rabbitmq']))
29
+ set :amq, AMQP::Channel.new(connection)
30
+ end
31
+
32
+ helpers do
33
+ include Rack::Utils
34
+ alias_method :conn, :settings
35
+ end
36
+
37
+ before do
38
+ content_type 'application/json'
39
+ end
40
+
41
+ aget '/clients' do
42
+ current_clients = Array.new
43
+ conn.redis.smembers('clients').callback do |clients|
44
+ unless clients.empty?
45
+ clients.each_with_index do |client, index|
46
+ conn.redis.get('client:' + client).callback do |client_json|
47
+ current_clients.push(JSON.parse(client_json))
48
+ body current_clients.to_json if index == clients.size-1
49
+ end
50
+ end
51
+ else
52
+ body current_clients.to_json
53
+ end
54
+ end
55
+ end
56
+
57
+ aget '/client/:id' do |client|
58
+ conn.redis.get('client:' + client).callback do |client_json|
59
+ status 404 if client_json.nil?
60
+ body client_json
61
+ end
62
+ end
63
+
64
+ aget '/events' do
65
+ current_events = Hash.new
66
+ conn.redis.smembers('clients').callback do |clients|
67
+ unless clients.empty?
68
+ clients.each_with_index do |client, index|
69
+ conn.redis.hgetall('events:' + client).callback do |events|
70
+ client_events = Hash[*events]
71
+ client_events.each do |key, value|
72
+ client_events[key] = JSON.parse(value)
73
+ end
74
+ current_events.store(client, client_events) unless client_events.empty?
75
+ body current_events.to_json if index == clients.size-1
76
+ end
77
+ end
78
+ else
79
+ body current_events.to_json
80
+ end
81
+ end
82
+ end
83
+
84
+ adelete '/client/:id' do |client|
85
+ conn.redis.sismember('clients', client).callback do |client_exists|
86
+ unless client_exists == 0
87
+ conn.redis.exists('events:' + client).callback do |events_exist|
88
+ unless events_exist == 0
89
+ conn.redis.hgetall('events:' + client).callback do |events|
90
+ Hash[*events].keys.each do |check|
91
+ conn.amq.queue('results').publish({'check' => check, 'client' => client, 'status' => 0, 'output' => 'client is being removed...'}.to_json)
92
+ end
93
+ EM.add_timer(10) do
94
+ conn.redis.srem('clients', client)
95
+ conn.redis.del('events:' + client)
96
+ conn.redis.del('client:' + client)
97
+ end
98
+ end
99
+ else
100
+ conn.redis.srem('clients', client)
101
+ conn.redis.del('events:' + client)
102
+ conn.redis.del('client:' + client)
103
+ end
104
+ status 204
105
+ body ''
106
+ end
107
+ else
108
+ status 404
109
+ body ''
110
+ end
111
+ end
112
+ end
113
+
114
+ apost '/test/client' do
115
+ client = '{
116
+ "name": "test",
117
+ "address": "127.0.0.1",
118
+ "subscriptions": [
119
+ "foo",
120
+ "bar"
121
+ ]
122
+ }'
123
+ conn.redis.set('client:test', client).callback do
124
+ conn.redis.sadd('clients', 'test')
125
+ status 201
126
+ body ''
127
+ end
128
+ end
129
+
130
+ apost '/test/event' do
131
+ conn.redis.hset('events:test', 'test', {'status' => 2, 'output' => 'CRITICAL :: test'}.to_json).callback do
132
+ status 201
133
+ body ''
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,69 @@
1
+ require File.join(File.dirname(__FILE__), 'config')
2
+
3
+ module Sensu
4
+ class Client
5
+ def self.run(options={})
6
+ EM.run do
7
+ client = self.new(options)
8
+ client.setup_amqp
9
+ client.setup_keep_alives
10
+ client.setup_subscriptions
11
+
12
+ Signal.trap('INT') do
13
+ EM.stop
14
+ end
15
+
16
+ Signal.trap('TERM') do
17
+ EM.stop
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize(options={})
23
+ config = Sensu::Config.new(:config_file => options[:config_file])
24
+ @settings = config.settings
25
+ @checks_in_progress = Array.new
26
+ end
27
+
28
+ def setup_amqp
29
+ connection = AMQP.connect(symbolize_keys(@settings['rabbitmq']))
30
+ @amq = AMQP::Channel.new(connection)
31
+ @result_queue = @amq.queue('results')
32
+ end
33
+
34
+ def setup_keep_alives
35
+ keepalive_queue = @amq.queue('keepalives')
36
+ keepalive_queue.publish(@settings['client'].merge({'timestamp' => Time.now.to_i}).to_json)
37
+ EM.add_periodic_timer(30) do
38
+ keepalive_queue.publish(@settings['client'].merge({'timestamp' => Time.now.to_i}).to_json)
39
+ end
40
+ end
41
+
42
+ def execute_check(check)
43
+ if @settings['checks'][check['name']]
44
+ unless @checks_in_progress.include?(check['name'])
45
+ @checks_in_progress.push(check['name'])
46
+ command = @settings['checks'][check['name']]['command'].gsub(/:::(.*?):::/) do
47
+ @settings['client'][$1.to_s].to_s
48
+ end
49
+ EM.system('sh', '-c', command + ' 2>&1') do |output, status|
50
+ @result_queue.publish({'check' => check['name'], 'client' => @settings['client']['name'], 'status' => status.exitstatus, 'output' => output}.to_json)
51
+ @checks_in_progress.delete(check['name'])
52
+ end
53
+ end
54
+ else
55
+ @result_queue.publish({'check' => check['name'], 'client' => @settings['client']['name'], 'status' => 3, 'output' => 'Unknown check'}.to_json)
56
+ end
57
+ end
58
+
59
+ def setup_subscriptions
60
+ @settings['client']['subscriptions'].each do |exchange|
61
+ uniq_queue_name = UUIDTools::UUID.random_create.to_s
62
+ @amq.queue(uniq_queue_name, :auto_delete => true).bind(@amq.fanout(exchange)).subscribe do |check_json|
63
+ check = JSON.parse(check_json)
64
+ execute_check(check)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,55 @@
1
+ require 'rubygems' if RUBY_VERSION < '1.9.0'
2
+ require 'json'
3
+ require 'uuidtools'
4
+ require 'amqp'
5
+ require 'em/syslog'
6
+ require File.join(File.dirname(__FILE__), 'helpers')
7
+
8
+ module Sensu
9
+ class Config
10
+ attr_accessor :settings
11
+
12
+ def initialize(options={})
13
+ config_file = options[:config_file] || '/etc/sensu/config.json'
14
+ @settings = JSON.parse(File.open(config_file, 'r').read)
15
+ validate_config
16
+ end
17
+
18
+ def validate_config
19
+ @settings['checks'].each do |name, info|
20
+ unless info['interval'].is_a?(Integer) && info['interval'] > 0
21
+ raise 'configuration invalid, missing interval for check ' + name
22
+ end
23
+ unless info['command'].is_a?(String)
24
+ raise 'configuration invalid, missing command for check ' + name
25
+ end
26
+ unless info['subscribers'].is_a?(Array) && info['subscribers'].count > 0
27
+ raise 'configuration invalid, missing subscribers for check ' + name
28
+ end
29
+ end
30
+ unless @settings['client']['name'].is_a?(String)
31
+ raise 'configuration invalid, client must have a name'
32
+ end
33
+ unless @settings['client']['address'].is_a?(String)
34
+ raise 'configuration invalid, client must have an address (ip or hostname)'
35
+ end
36
+ unless @settings['client']['subscriptions'].is_a?(Array) && @settings['client']['subscriptions'].count > 0
37
+ raise 'configuration invalid, client must have subscriptions'
38
+ end
39
+ end
40
+
41
+ def create_working_directory
42
+ begin
43
+ Dir.mkdir('/tmp/sensu')
44
+ rescue SystemCallError
45
+ end
46
+ end
47
+
48
+ def purge_working_directory
49
+ Dir.foreach('/tmp/sensu') do |file|
50
+ next if file == '.' || file == '..'
51
+ File.delete('/tmp/sensu/' + file)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,18 @@
1
+ def symbolize_keys(item)
2
+ case item
3
+ when Array
4
+ item.map do |i|
5
+ symbolize_keys(i)
6
+ end
7
+ when Hash
8
+ Hash[
9
+ item.map do |key, value|
10
+ k = key.is_a?(String) ? key.to_sym : key
11
+ v = symbolize_keys(value)
12
+ [k,v]
13
+ end
14
+ ]
15
+ else
16
+ item
17
+ end
18
+ end
@@ -0,0 +1,184 @@
1
+ require File.join(File.dirname(__FILE__), 'config')
2
+ require 'em-hiredis'
3
+
4
+ module Sensu
5
+ class Server
6
+ attr_accessor :redis
7
+ alias :redis_connection :redis
8
+
9
+ def self.run(options={})
10
+ EM.run do
11
+ server = self.new(options)
12
+ server.setup_logging
13
+ server.setup_redis
14
+ server.setup_amqp
15
+ server.setup_keep_alives
16
+ server.setup_handlers
17
+ server.setup_results
18
+ server.setup_publisher
19
+ server.setup_populator
20
+ server.setup_keep_alive_monitor
21
+
22
+ Signal.trap('INT') do
23
+ EM.stop
24
+ end
25
+
26
+ Signal.trap('TERM') do
27
+ EM.stop
28
+ end
29
+ end
30
+ end
31
+
32
+ def initialize(options={})
33
+ config = Sensu::Config.new(:config_file => options[:config_file])
34
+ config.create_working_directory
35
+ @settings = config.settings
36
+ end
37
+
38
+ def setup_logging
39
+ EM.syslog_setup(@settings['syslog']['host'], @settings['syslog']['port'])
40
+ end
41
+
42
+ def setup_redis
43
+ @redis = EM::Hiredis.connect('redis://' + @settings['redis']['host'] + ':' + @settings['redis']['port'].to_s)
44
+ end
45
+
46
+ def setup_amqp
47
+ connection = AMQP.connect(symbolize_keys(@settings['rabbitmq']))
48
+ @amq = AMQP::Channel.new(connection)
49
+ end
50
+
51
+ def setup_keep_alives
52
+ @amq.queue('keepalives').subscribe do |keepalive_json|
53
+ client = JSON.parse(keepalive_json)['name']
54
+ @redis.set('client:' + client, keepalive_json).callback do
55
+ @redis.sadd('clients', client)
56
+ end
57
+ end
58
+ end
59
+
60
+ def setup_handlers
61
+ @handler_queue = EM::Queue.new
62
+ handlers_in_progress = 0
63
+ handle = Proc.new do |event|
64
+ if handlers_in_progress < 15
65
+ event_file = proc do
66
+ handlers_in_progress += 1
67
+ file_name = '/tmp/sensu/event-' + UUIDTools::UUID.random_create.to_s
68
+ File.open(file_name, 'w') do |file|
69
+ file.write(JSON.pretty_generate(event))
70
+ end
71
+ file_name
72
+ end
73
+ handler = proc do |event_file|
74
+ EM.system('sh', '-c', @settings['handlers'][event['check']['handler']] + ' -f ' + event_file + ' 2>&1') do |output, status|
75
+ EM.debug('handled :: ' + event['check']['handler'] + ' :: ' + status.exitstatus.to_s + ' :: ' + output)
76
+ File.delete(event_file)
77
+ handlers_in_progress -= 1
78
+ end
79
+ end
80
+ EM.defer(event_file, handler)
81
+ else
82
+ @handler_queue.push(event)
83
+ end
84
+ EM.next_tick do
85
+ @handler_queue.pop(&handle)
86
+ end
87
+ end
88
+ @handler_queue.pop(&handle)
89
+ end
90
+
91
+ def handle_event(event)
92
+ @handler_queue.push(event)
93
+ end
94
+
95
+ def setup_results
96
+ @amq.queue('results').subscribe do |result_json|
97
+ result = JSON.parse(result_json)
98
+ @redis.get('client:' + result['client']).callback do |client_json|
99
+ unless client_json.nil?
100
+ client = JSON.parse(client_json)
101
+ check = {'name' => result['check']}
102
+ check.merge!(@settings['checks'][result['check']]) if @settings['checks'].has_key?(result['check'])
103
+ check['handler'] = 'default' unless check['handler']
104
+ event = {
105
+ 'client' => client,
106
+ 'check' => check,
107
+ 'status' => result['status'],
108
+ 'output' => result['output']
109
+ }
110
+ if check['handler'] == 'metric'
111
+ handle_event(event)
112
+ else
113
+ if result['status'] == 0
114
+ @redis.hexists('events:' + client['name'], result['check']).callback do |exists|
115
+ if exists == 1
116
+ @redis.hdel('events:' + client['name'], result['check'])
117
+ event['action'] = 'resolve'
118
+ handle_event(event)
119
+ end
120
+ end
121
+ else
122
+ @redis.hset('events:' + client['name'], result['check'], {'status' => result['status'], 'output' => result['output']}.to_json).callback do
123
+ event['action'] = 'create'
124
+ handle_event(event)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def setup_publisher
134
+ exchanges = Hash.new
135
+ @amq.queue('checks').subscribe do |check_json|
136
+ check = JSON.parse(check_json)
137
+ check['subscribers'].each do |exchange|
138
+ if exchanges[exchange].nil?
139
+ exchanges[exchange] = @amq.fanout(exchange)
140
+ end
141
+ exchanges[exchange].publish({'name' => check['name']}.to_json)
142
+ EM.debug('published :: ' + exchange + ' :: ' + check['name'])
143
+ end
144
+ end
145
+ end
146
+
147
+ def setup_populator
148
+ check_queue = @amq.queue('checks')
149
+ @settings['checks'].each_with_index do |(name, info), index|
150
+ EM.add_timer(7*index) do
151
+ EM.add_periodic_timer(info['interval']) do
152
+ check_queue.publish({'name' => name, 'subscribers' => info['subscribers']}.to_json)
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ def setup_keep_alive_monitor
159
+ result_queue = @amq.queue('results')
160
+ EM.add_periodic_timer(30) do
161
+ @redis.smembers('clients').callback do |clients|
162
+ clients.each do |client_id|
163
+ @redis.get('client:' + client_id).callback do |client_json|
164
+ client = JSON.parse(client_json)
165
+ time_since_last_check = Time.now.to_i - client['timestamp']
166
+ case
167
+ when time_since_last_check >= 180
168
+ result_queue.publish({'check' => 'keepalive', 'client' => client['name'], 'status' => 2, 'output' => 'No keep-alive sent from host in over 180 seconds'}.to_json)
169
+ when time_since_last_check >= 120
170
+ result_queue.publish({'check' => 'keepalive', 'client' => client['name'], 'status' => 1, 'output' => 'No keep-alive sent from host in over 120 seconds'}.to_json)
171
+ else
172
+ @redis.hexists('events:' + client_id, 'keepalive').callback do |exists|
173
+ if exists == 1
174
+ result_queue.publish({'check' => 'keepalive', 'client' => client['name'], 'status' => 0, 'output' => 'Keep-alive sent from host'}.to_json)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
data/sensu.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "sensu"
3
+ s.version = "0.5.1"
4
+ s.authors = ["Sean Porter", "Justin Kolberg"]
5
+ s.email = ["sean.porter@sonian.net", "justin.kolberg@sonian.net"]
6
+ s.homepage = "https://github.com/sonian/sensu"
7
+ s.summary = %q{A server monitoring framework}
8
+ s.description = %q{A server monitoring framework using the publish-subscribe model}
9
+ s.license = "MIT"
10
+ s.has_rdoc = false
11
+
12
+ s.add_dependency("amqp", "0.7.4")
13
+ s.add_dependency("json")
14
+ s.add_dependency("uuidtools")
15
+ s.add_dependency("em-hiredis")
16
+ s.add_dependency("em-syslog")
17
+ s.add_dependency("async_sinatra")
18
+ s.add_dependency("thin")
19
+ s.add_development_dependency('rake')
20
+ s.add_development_dependency('minitest')
21
+ s.add_development_dependency('em-ventually')
22
+ s.add_development_dependency('rest-client')
23
+
24
+ s.files = `git ls-files`.split("\n").reject {|f| f =~ /(dist|test)/}
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sensu
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.5.1
6
+ platform: ruby
7
+ authors:
8
+ - Sean Porter
9
+ - Justin Kolberg
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-09-09 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: amqp
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - "="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.7.4
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: uuidtools
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: em-hiredis
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: em-syslog
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: async_sinatra
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ type: :runtime
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: thin
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ type: :runtime
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
94
+ name: rake
95
+ prerelease: false
96
+ requirement: &id008 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ type: :development
103
+ version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: minitest
106
+ prerelease: false
107
+ requirement: &id009 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: "0"
113
+ type: :development
114
+ version_requirements: *id009
115
+ - !ruby/object:Gem::Dependency
116
+ name: em-ventually
117
+ prerelease: false
118
+ requirement: &id010 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: "0"
124
+ type: :development
125
+ version_requirements: *id010
126
+ - !ruby/object:Gem::Dependency
127
+ name: rest-client
128
+ prerelease: false
129
+ requirement: &id011 !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: "0"
135
+ type: :development
136
+ version_requirements: *id011
137
+ description: A server monitoring framework using the publish-subscribe model
138
+ email:
139
+ - sean.porter@sonian.net
140
+ - justin.kolberg@sonian.net
141
+ executables:
142
+ - sensu-api
143
+ - sensu-client
144
+ - sensu-server
145
+ extensions: []
146
+
147
+ extra_rdoc_files: []
148
+
149
+ files:
150
+ - .gitignore
151
+ - Gemfile
152
+ - Gemfile.lock
153
+ - MIT-LICENSE.txt
154
+ - README.org
155
+ - Rakefile
156
+ - bin/sensu-api
157
+ - bin/sensu-client
158
+ - bin/sensu-server
159
+ - lib/sensu.rb
160
+ - lib/sensu/api.rb
161
+ - lib/sensu/client.rb
162
+ - lib/sensu/config.rb
163
+ - lib/sensu/helpers.rb
164
+ - lib/sensu/server.rb
165
+ - sensu.gemspec
166
+ homepage: https://github.com/sonian/sensu
167
+ licenses:
168
+ - MIT
169
+ post_install_message:
170
+ rdoc_options: []
171
+
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: "0"
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ none: false
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: "0"
186
+ requirements: []
187
+
188
+ rubyforge_project:
189
+ rubygems_version: 1.8.8
190
+ signing_key:
191
+ specification_version: 3
192
+ summary: A server monitoring framework
193
+ test_files: []
194
+