smoke 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History.txt +3 -0
  2. data/License.txt +21 -0
  3. data/Manifest.txt +46 -0
  4. data/README.txt +3 -0
  5. data/Rakefile +4 -0
  6. data/bin/smoke +43 -0
  7. data/bin/smoked +44 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/etc/smoke.d/processors/smoke/remote_port_status_check_processor.rb +8 -0
  11. data/etc/smoke.d/processors/smoke/system_load_processor.rb +41 -0
  12. data/etc/smoke.d/signals/smoke/random_status_demo.rb +7 -0
  13. data/etc/smoke.d/signals/smoke/remote_port_status_check.rb +34 -0
  14. data/etc/smoke.d/signals/smoke/system_load.rb +14 -0
  15. data/lib/smoke.rb +5 -0
  16. data/lib/smoke/client.rb +50 -0
  17. data/lib/smoke/client/connection.rb +44 -0
  18. data/lib/smoke/client/signal_runner.rb +40 -0
  19. data/lib/smoke/client/version.rb +11 -0
  20. data/lib/smoke/server.rb +18 -0
  21. data/lib/smoke/server/signal_handler.rb +64 -0
  22. data/lib/smoke/server/signal_router.rb +38 -0
  23. data/lib/smoke/server/version.rb +11 -0
  24. data/lib/smoke/signal.rb +19 -0
  25. data/lib/smoke/signal_processor.rb +29 -0
  26. data/lib/smoke/version.rb +9 -0
  27. data/load_average.png +0 -0
  28. data/log/debug.log +0 -0
  29. data/log/development.log +0 -0
  30. data/log/production.log +0 -0
  31. data/log/server.log +0 -0
  32. data/log/test.log +0 -0
  33. data/script/destroy +14 -0
  34. data/script/generate +14 -0
  35. data/script/txt2html +74 -0
  36. data/setup.rb +1585 -0
  37. data/tasks/deployment.rake +35 -0
  38. data/tasks/environment.rake +7 -0
  39. data/tasks/website.rake +17 -0
  40. data/test/test_helper.rb +2 -0
  41. data/test/test_server.rb +11 -0
  42. data/website/index.html +94 -0
  43. data/website/index.txt +39 -0
  44. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  45. data/website/stylesheets/screen.css +138 -0
  46. data/website/template.rhtml +49 -0
  47. metadata +106 -0
@@ -0,0 +1,3 @@
1
+ == 0.0.1 2008-03-29
2
+
3
+ * Initial release
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008 Craig R Webster <craig@barkingiguana.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/smoke
7
+ bin/smoked
8
+ config/hoe.rb
9
+ config/requirements.rb
10
+ etc/smoke.d/processors/smoke/remote_port_status_check_processor.rb
11
+ etc/smoke.d/processors/smoke/system_load_processor.rb
12
+ etc/smoke.d/signals/smoke/random_status_demo.rb
13
+ etc/smoke.d/signals/smoke/remote_port_status_check.rb
14
+ etc/smoke.d/signals/smoke/system_load.rb
15
+ lib/smoke.rb
16
+ lib/smoke/client.rb
17
+ lib/smoke/client/connection.rb
18
+ lib/smoke/client/signal_runner.rb
19
+ lib/smoke/client/version.rb
20
+ lib/smoke/server.rb
21
+ lib/smoke/server/signal_handler.rb
22
+ lib/smoke/server/signal_router.rb
23
+ lib/smoke/server/version.rb
24
+ lib/smoke/signal.rb
25
+ lib/smoke/signal_processor.rb
26
+ lib/smoke/version.rb
27
+ load_average.png
28
+ log/debug.log
29
+ log/development.log
30
+ log/production.log
31
+ log/server.log
32
+ log/test.log
33
+ script/destroy
34
+ script/generate
35
+ script/txt2html
36
+ setup.rb
37
+ tasks/deployment.rake
38
+ tasks/environment.rake
39
+ tasks/website.rake
40
+ test/test_helper.rb
41
+ test/test_server.rb
42
+ website/index.html
43
+ website/index.txt
44
+ website/javascripts/rounded_corners_lite.inc.js
45
+ website/stylesheets/screen.css
46
+ website/template.rhtml
@@ -0,0 +1,3 @@
1
+ == Smoke Server
2
+
3
+ Run bin/smoked to listen for connections from Smoke clients.
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ GEM_ROOT = File.expand_path(File.dirname(File.dirname(__FILE__)))
4
+ SIGNAL_DIRECTORIES = [ "#{GEM_ROOT}/etc/smoke.d/signals", "/etc/smoke.d/signals" ]
5
+
6
+ $: << File.join(GEM_ROOT, 'lib')
7
+ SIGNAL_DIRECTORIES.each_with_index do |directory, index|
8
+ if directory =~ /[^\/]$/
9
+ directory += '/'
10
+ SIGNAL_DIRECTORIES[index] = directory
11
+ end
12
+ $: << directory
13
+ end
14
+
15
+ require 'rubygems'
16
+ require 'active_support'
17
+ require 'smoke/signal'
18
+ require 'smoke/client'
19
+
20
+ signals = returning([]) do |signal_list|
21
+ SIGNAL_DIRECTORIES.each do |directory|
22
+ Dir[directory + '**/*.rb'].collect do |signal_file|
23
+ require signal_file
24
+ signal = signal_file.sub(directory, '').sub('.rb', '').classify
25
+ begin
26
+ puts "Loading #{signal}."
27
+ signal_class = signal.constantize
28
+ if signal_class.ancestors.include? Smoke::Signal
29
+ signal_list << signal_class
30
+ else
31
+ puts "Expected #{signal} (#{signal_file}) to extend Smoke::Signal."
32
+ exit 2
33
+ end
34
+ rescue NameError
35
+ puts "Expected #{signal_file} to define #{signal}."
36
+ exit 1
37
+ end
38
+ end
39
+ end
40
+ end.flatten.compact.uniq
41
+
42
+ client = Smoke::Client.new signals
43
+ client.join
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created on 2008-3-29.
4
+ # Copyright (c) 2008 Craig R Webster <craig@barkingiguana.com>
5
+ #
6
+
7
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ require 'rubygems'
9
+ require 'mongrel'
10
+ require 'lib/smoke/server'
11
+ require 'optparse'
12
+
13
+ OPTIONS = {
14
+ :port => 8935,
15
+ :ip_address => "127.0.0.1"
16
+ }
17
+ MANDATORY_OPTIONS = %w( )
18
+
19
+ parser = OptionParser.new do |opts|
20
+ opts.banner = %Q(
21
+ A framework for processing Smoke signals.
22
+ http://smoke.rubyforge.org/
23
+
24
+ Usage: #{File.basename($0)} [options]
25
+
26
+ Options are:)
27
+ opts.separator ""
28
+ opts.on("-b", "--bind=IP_ADDRESS", String,
29
+ "IP address to bind to",
30
+ "Default: 127.0.0.1 (any IP address)") { |OPTIONS[:ip_address]| }
31
+ opts.on("-p", "--port=PORT", Integer,
32
+ "Port to listen on",
33
+ "Default: 8935") { |OPTIONS[:port]| }
34
+ opts.on("-h", "--help",
35
+ "Show this help message.") { puts opts; exit }
36
+ opts.parse!(ARGV)
37
+
38
+ if MANDATORY_OPTIONS && MANDATORY_OPTIONS.find { |option| OPTIONS[option.to_sym].nil? }
39
+ puts opts; exit
40
+ end
41
+ end
42
+
43
+ server = Smoke::Server.new(OPTIONS)
44
+ server.join
@@ -0,0 +1,70 @@
1
+ require 'smoke/version'
2
+
3
+ AUTHOR = 'Craig R Webster' # can also be an array of Authors
4
+ EMAIL = "craig@barkingiguana.com"
5
+ DESCRIPTION = "A simple framework for reporting to a central server. What is reported and how it is handled is passed off to plugins called Smoke Signals that are defined by the user."
6
+ GEM_NAME = 'smoke' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'smoke' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Smoke::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'smoke documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.developer(AUTHOR, EMAIL)
52
+ p.description = DESCRIPTION
53
+ p.summary = DESCRIPTION
54
+ p.url = HOMEPATH
55
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
56
+ p.test_globs = ["test/**/test_*.rb"]
57
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
58
+
59
+ # == Optional
60
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
61
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
+
63
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
64
+
65
+ end
66
+
67
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
68
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
69
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
70
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'smoke'
@@ -0,0 +1,8 @@
1
+ module Smoke
2
+ class RemotePortStatusCheckProcessor < Smoke::SignalProcessor
3
+ def process(signal)
4
+ puts signal.inspect
5
+ puts "-" * 80
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'scruffy'
3
+
4
+ module Smoke
5
+ class SystemLoadProcessor < Smoke::SignalProcessor
6
+ def initialize(*args)
7
+ super
8
+ @load = []
9
+ 0.upto(59) do |n|
10
+ @load[n] = [0, 0, 0]
11
+ end
12
+
13
+ # Generate a load graph every 60 seconds.
14
+ Thread.new(@load) do |load|
15
+ loop do
16
+ begin
17
+ graph = Scruffy::Graph.new(:title => "Load Average")
18
+ graph.value_formatter = Scruffy::Formatters::Number.new(:precision => 2)
19
+ graph.add(:area, ' 1min', load.collect { |sample| sample[0] }, :opacity => 0.5)
20
+ graph.add(:area, ' 5min', load.collect { |sample| sample[1] }, :opacity => 0.5)
21
+ graph.add(:area, '15min', load.collect { |sample| sample[2] }, :opacity => 0.5)
22
+ graph.render(:min_value => 0, :max_value => 1.00, :width => 700, :as => 'PNG', :to => 'load_average.png')
23
+ sleep 60
24
+ rescue => e
25
+ STDERR.puts e.message + ":\n\n" + e.backtrace.join("\n") + "\n\n"
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def process(signal)
32
+ @load.shift
33
+ load_averages = [
34
+ signal["report"]["one_minute"],
35
+ signal["report"]["five_minutes"],
36
+ signal["report"]["fifteen_minutes"]
37
+ ]
38
+ @load.push load_averages
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,7 @@
1
+ module Smoke
2
+ class RandomStatusDemo < Smoke::Signal
3
+ def run
4
+ { :report => { :status => %W(OK FAIL UNKNOWN)[rand(3).round] } }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,34 @@
1
+ module Smoke
2
+ class RemotePortStatusCheck < Smoke::Signal
3
+ HOSTS_PORTS_AND_STATUSES = [
4
+ [ "xeriom.net", 80, :open ],
5
+ [ "barkingiguana.com", 80, :open ],
6
+ [ "localhost", 80, :down ]
7
+ ]
8
+
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def start
14
+ HOSTS_PORTS_AND_STATUSES.map do |check|
15
+ Thread.new(@client, check) do |client, c|
16
+ host, port, desired_status = *c
17
+ loop do
18
+ current_status = begin
19
+ TCPSocket.new(host, port)
20
+ :open
21
+ rescue Errno::ECONNREFUSED
22
+ :closed
23
+ end
24
+ if current_status != desired_status
25
+ client.report self, { :host => host, :port => port, :status => current_status }
26
+ end
27
+ sleep 15
28
+ end
29
+ end
30
+ end
31
+ loop
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ module Smoke
2
+ class SystemLoad < Smoke::Signal
3
+ def run
4
+ one_minute, five_minutes, fifteen_minutes = %x[uptime].strip.split(/load averages: /).last.split(/ /)
5
+ {
6
+ :report => {
7
+ :one_minute => one_minute.to_f,
8
+ :five_minutes => five_minutes.to_f,
9
+ :fifteen_minutes => fifteen_minutes.to_f
10
+ }
11
+ }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ module Smoke
4
+
5
+ end
@@ -0,0 +1,50 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'smoke/client/signal_runner'
3
+
4
+ module Smoke
5
+ module Client
6
+ def new(signals = [])
7
+ @reporter = SignalRunner.new
8
+
9
+ polling_signals, interupting_signals = returning([[], []]) do |poll, interupt|
10
+ signals.map do |signal|
11
+ if signal.instance_methods.include?("start")
12
+ interupt << signal
13
+ else
14
+ poll << signal
15
+ end
16
+ end
17
+ end
18
+
19
+ interupting_signals.map do |signal|
20
+ Thread.new(self) do |client|
21
+ signal.new(client).start
22
+ end
23
+ end
24
+
25
+ loop do
26
+ polling_signals.map do |signal|
27
+ Thread.new(@reporter) do |r|
28
+ begin
29
+ response = signal.run
30
+ report(signal, response)
31
+ rescue => e
32
+ puts e.message + ":" + e.backtrace.join("\n")
33
+ end
34
+ end
35
+ end
36
+
37
+ # FIXME: This should be configurable.
38
+ sleep 60
39
+ end
40
+ end
41
+
42
+ def report(signal, response)
43
+ source = signal.is_a?(Class) ? signal.to_s : signal.class.to_s
44
+ response.merge!(:source => source, :time => Time.now)
45
+ @reporter.signals << response
46
+ end
47
+
48
+ extend self
49
+ end
50
+ end
@@ -0,0 +1,44 @@
1
+ require 'net/http'
2
+
3
+ module Smoke
4
+ module Client
5
+ class Connection
6
+ DEFAULT_OPTIONS = {
7
+ :hostname => "localhost",
8
+ :port => 8935,
9
+ :ssl => false,
10
+ :path => '/signals',
11
+ :timeout => 3
12
+ }
13
+
14
+ attr_reader :configuration
15
+
16
+ def initialize(configuration = {})
17
+ @configuration = DEFAULT_OPTIONS.merge(configuration)
18
+ @user_agent = if configuration[:ssl]
19
+ Net::HTTPS
20
+ else
21
+ Net::HTTP
22
+ end.new(configuration[:hostname], configuration[:port])
23
+ @user_agent.read_timeout = configuration[:timeout]
24
+ end
25
+
26
+ def send_signal(signal)
27
+ report_signal = Net::HTTP::Post.new(configuration[:path])
28
+ if configuration[:username] && configuration[:password]
29
+ report_signal.basic_auth configuration[:username], configuration[:password]
30
+ end
31
+ response = @user_agent.request report_signal, signal.to_xml(:root => :signal)
32
+ case response
33
+ when Net::HTTPCreated
34
+ true
35
+ else
36
+ response.error!
37
+ end
38
+ rescue => e
39
+ STDERR.puts "#{e.message}\n\n#{e.backtrace.join("\n")}\n\n"
40
+ raise
41
+ end
42
+ end
43
+ end
44
+ end