sensu 0.5.1

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.
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
+