noah 0.0.5 → 0.0.9
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/.gemtest +0 -0
- data/.gitignore +9 -0
- data/LICENSE +201 -0
- data/README.md +68 -212
- data/Rakefile +70 -41
- data/TODO.md +59 -0
- data/bin/noah +2 -1
- data/bin/noah-watcher.rb +93 -0
- data/config.ru +6 -3
- data/config/warble.rb +18 -0
- data/examples/README.md +116 -0
- data/examples/cluster.ru +2 -0
- data/examples/custom-watcher.rb +10 -0
- data/examples/httpclient-server.rb +7 -0
- data/examples/httpclient.rb +12 -0
- data/examples/httpclient2.rb +28 -0
- data/examples/js/FABridge.js +1452 -0
- data/examples/js/WebSocketMain.swf +830 -0
- data/examples/js/swfobject.js +851 -0
- data/examples/js/web_socket.js +312 -0
- data/examples/logger.rb +11 -0
- data/examples/reconfiguring-sinatra-watcher.rb +11 -0
- data/examples/reconfiguring-sinatra.rb +32 -0
- data/examples/simple-post.rb +17 -0
- data/examples/websocket.html +24 -0
- data/examples/websocket.rb +41 -0
- data/lib/noah.rb +5 -8
- data/lib/noah/app.rb +20 -268
- data/lib/noah/application_routes.rb +70 -0
- data/lib/noah/ark.rb +0 -0
- data/lib/noah/configuration_routes.rb +81 -0
- data/lib/noah/ephemeral_routes.rb +19 -0
- data/lib/noah/helpers.rb +12 -14
- data/lib/noah/host_routes.rb +69 -0
- data/lib/noah/models.rb +86 -5
- data/lib/noah/models/applications.rb +41 -0
- data/lib/noah/models/configurations.rb +49 -0
- data/lib/noah/models/ephemerals.rb +33 -0
- data/lib/noah/models/hosts.rb +56 -0
- data/lib/noah/models/services.rb +54 -0
- data/lib/noah/models/watchers.rb +54 -0
- data/lib/noah/passthrough.rb +11 -0
- data/lib/noah/service_routes.rb +71 -0
- data/lib/noah/validations.rb +1 -0
- data/lib/noah/validations/watcher_validations.rb +48 -0
- data/lib/noah/version.rb +1 -1
- data/lib/noah/watcher.rb +75 -0
- data/lib/noah/watcher_routes.rb +12 -0
- data/lib/vendor/em-hiredis/Gemfile +4 -0
- data/lib/vendor/em-hiredis/README.md +61 -0
- data/lib/vendor/em-hiredis/Rakefile +2 -0
- data/lib/vendor/em-hiredis/em-hiredis-0.0.1.gem +0 -0
- data/lib/vendor/em-hiredis/em-hiredis.gemspec +23 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis.rb +22 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/client.rb +131 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/connection.rb +61 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/event_emitter.rb +29 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/version.rb +5 -0
- data/noah.gemspec +21 -17
- data/spec/application_spec.rb +30 -30
- data/spec/configuration_spec.rb +81 -14
- data/spec/ephemeral_spec.rb +52 -0
- data/spec/host_spec.rb +21 -21
- data/spec/noahapp_application_spec.rb +6 -6
- data/spec/noahapp_configuration_spec.rb +3 -3
- data/spec/noahapp_host_spec.rb +2 -2
- data/spec/noahapp_service_spec.rb +9 -9
- data/spec/noahapp_watcher_spec.rb +34 -0
- data/spec/service_spec.rb +27 -27
- data/spec/spec_helper.rb +13 -22
- data/spec/support/db/.keep +0 -0
- data/spec/support/test-redis.conf +8 -0
- data/spec/watcher_spec.rb +62 -0
- data/views/index.haml +21 -15
- metadata +124 -148
- data/Gemfile.lock +0 -85
- data/doc/coverage/index.html +0 -138
- data/doc/coverage/jquery-1.3.2.min.js +0 -19
- data/doc/coverage/jquery.tablesorter.min.js +0 -15
- data/doc/coverage/lib-helpers_rb.html +0 -393
- data/doc/coverage/lib-models_rb.html +0 -1449
- data/doc/coverage/noah_rb.html +0 -2019
- data/doc/coverage/print.css +0 -12
- data/doc/coverage/rcov.js +0 -42
- data/doc/coverage/screen.css +0 -270
- data/lib/noah/applications.rb +0 -46
- data/lib/noah/configurations.rb +0 -49
- data/lib/noah/hosts.rb +0 -54
- data/lib/noah/services.rb +0 -57
- data/lib/noah/watchers.rb +0 -18
data/Rakefile
CHANGED
@@ -1,48 +1,74 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib")))
|
1
2
|
require 'bundler'
|
2
|
-
begin
|
3
|
-
Bundler.setup(:default, :development)
|
4
|
-
rescue Bundler::BundlerError => e
|
5
|
-
$stderr.puts e.message
|
6
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
-
exit e.status_code
|
8
|
-
end
|
9
|
-
require 'rake'
|
10
|
-
|
11
3
|
require 'rspec/core'
|
12
4
|
require 'rspec/core/rake_task'
|
13
5
|
|
6
|
+
REDIS_DIR = File.expand_path(File.join("..", "spec", "support"), __FILE__)
|
7
|
+
REDIS_CNF = File.join(REDIS_DIR, "test-redis.conf")
|
8
|
+
|
14
9
|
Bundler::GemHelper.install_tasks
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
task :default => :run
|
16
|
+
task :test => [:start, :spec, :stop]
|
17
|
+
|
18
|
+
desc "Run tests and manage server start/stop"
|
19
|
+
task :run => [:start, :spec, :stop]
|
20
|
+
|
21
|
+
desc "Start the Redis server"
|
22
|
+
task :start do
|
23
|
+
puts "Starting redis-server"
|
24
|
+
system "redis-server #{REDIS_CNF}"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Stop the Redis server"
|
28
|
+
task :stop do
|
29
|
+
puts "Killing redis"
|
30
|
+
system "killall -TERM redis-server"
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :coverage do
|
34
|
+
desc "Delete aggregate coverage data."
|
35
|
+
task(:clean) { rm_f "coverage.data" }
|
36
|
+
end
|
37
|
+
desc "Run Rcov code coverage analysis"
|
38
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
39
|
+
t.rcov = true
|
40
|
+
t.verbose = true
|
41
|
+
t.rcov_opts = %q[--aggregate coverage.data --sort coverage --text-report --exclude "config,.bundle/*,gems/*,spec/*" -o doc/coverage -Ilib -i "noah.rb"]
|
42
|
+
end
|
15
43
|
|
16
44
|
desc "Populate database with sample dataset"
|
17
45
|
task :sample, :redis_url do |t, args|
|
18
|
-
require '
|
19
|
-
begin
|
20
|
-
require 'yajl'
|
21
|
-
rescue LoadError
|
22
|
-
require 'json'
|
23
|
-
end
|
24
|
-
require File.join(File.dirname(__FILE__), 'lib','noah')
|
46
|
+
require 'noah'
|
25
47
|
|
26
|
-
|
27
48
|
Ohm::connect(:url => args.redis_url)
|
28
49
|
Ohm::redis.flushdb
|
50
|
+
puts "Creating watchers..."
|
51
|
+
Noah::Watcher.create :endpoint => "http://localhost:3000/webhook", :pattern => "//noah/application"
|
52
|
+
Noah::Watcher.create :endpoint => "http://localhost:3001/webhook", :pattern => "//noah/configuration"
|
53
|
+
Noah::Watcher.create :endpoint => "http://localhost:3002/webhook", :pattern => "//noah/host"
|
54
|
+
Noah::Watcher.create :endpoint => "http://localhost:3003/webhook", :pattern => "//noah/service"
|
29
55
|
puts "Creating Host entry for 'localhost'"
|
30
|
-
h = Host.create(:name => 'localhost', :status => "up")
|
56
|
+
h = Noah::Host.create(:name => 'localhost', :status => "up")
|
31
57
|
if h.save
|
32
58
|
%w[redis noah].each do |service|
|
33
59
|
puts "Create Service entry for #{service}"
|
34
|
-
s = Service.create(:name => service, :status => "up", :host => h)
|
60
|
+
s = Noah::Service.create(:name => service, :status => "up", :host => h)
|
35
61
|
h.services << s
|
36
62
|
end
|
37
63
|
end
|
38
64
|
|
39
65
|
puts "Creating Application entry for 'noah'"
|
40
|
-
a = Application.create(:name => 'noah')
|
66
|
+
a = Noah::Application.create(:name => 'noah')
|
41
67
|
if a.save
|
42
68
|
puts "Creating Configuration entry for 'noah'"
|
43
|
-
cr = Configuration.create(:name => 'redis', :format => 'string', :body => 'redis://127.0.0.1:6379/0', :application => a)
|
44
|
-
ch = Configuration.create(:name => 'host', :format => 'string', :body => 'localhost', :application => a)
|
45
|
-
cp = Configuration.create(:name => 'port', :format => 'string', :body => '9292', :application => a)
|
69
|
+
cr = Noah::Configuration.create(:name => 'redis', :format => 'string', :body => 'redis://127.0.0.1:6379/0', :application => a)
|
70
|
+
ch = Noah::Configuration.create(:name => 'host', :format => 'string', :body => 'localhost', :application => a)
|
71
|
+
cp = Noah::Configuration.create(:name => 'port', :format => 'string', :body => '9292', :application => a)
|
46
72
|
%w[cr ch cp].each do |c|
|
47
73
|
a.configurations << eval(c)
|
48
74
|
end
|
@@ -50,10 +76,10 @@ task :sample, :redis_url do |t, args|
|
|
50
76
|
|
51
77
|
puts "Creating sample entries - Host and Service"
|
52
78
|
%w[host1.domain.com host2.domain.com host3.domain.com].each do |host|
|
53
|
-
h = Host.create(:name => host, :status => "up")
|
79
|
+
h = Noah::Host.create(:name => host, :status => "up")
|
54
80
|
if h.save
|
55
81
|
%w[http https smtp mysql].each do |service|
|
56
|
-
s = Service.create(:name => service, :status => "pending", :host => h)
|
82
|
+
s = Noah::Service.create(:name => service, :status => "pending", :host => h)
|
57
83
|
h.services << s
|
58
84
|
end
|
59
85
|
end
|
@@ -74,32 +100,35 @@ EOY
|
|
74
100
|
}
|
75
101
|
EOJ
|
76
102
|
|
77
|
-
a1 = Application.create(:name => 'myrailsapp1')
|
103
|
+
a1 = Noah::Application.create(:name => 'myrailsapp1')
|
78
104
|
if a1.save
|
79
|
-
c1 = Configuration.create(:name => 'database.yml', :format => 'yaml', :body => my_yaml, :application => a1)
|
105
|
+
c1 = Noah::Configuration.create(:name => 'database.yml', :format => 'yaml', :body => my_yaml, :application => a1)
|
80
106
|
a1.configurations << c1
|
81
107
|
end
|
82
108
|
|
83
|
-
a2 = Application.create(:name => 'myrestapp1')
|
109
|
+
a2 = Noah::Application.create(:name => 'myrestapp1')
|
84
110
|
if a2.save
|
85
|
-
c2 = Configuration.create(:name => 'config.json', :format => 'json', :body => my_json, :application => a2)
|
111
|
+
c2 = Noah::Configuration.create(:name => 'config.json', :format => 'json', :body => my_json, :application => a2)
|
86
112
|
a2.configurations << c2
|
87
113
|
end
|
88
114
|
puts "Sample data populated!"
|
89
115
|
end
|
90
|
-
|
91
116
|
|
92
|
-
|
93
|
-
|
117
|
+
begin
|
118
|
+
require 'yard'
|
119
|
+
require 'yard/sinatra'
|
120
|
+
desc "Generate documentation"
|
121
|
+
YARD::Rake::YardocTask.new do |t|
|
122
|
+
t.files = ['lib/**/*.rb'] # optional
|
123
|
+
t.options = ['--title', "Noah #{Noah::VERSION} Documentation"]
|
124
|
+
t.options += ['--plugin', "yard-sinatra"]
|
125
|
+
t.options += ['--protected', '--private'] # optional
|
126
|
+
end
|
127
|
+
rescue LoadError
|
128
|
+
"You need YARD installed to generate docs"
|
94
129
|
end
|
95
130
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
desc "Run Rcov code coverage analysis"
|
101
|
-
RSpec::Core::RakeTask.new(:coverage) do |t|
|
102
|
-
t.rcov = true
|
103
|
-
t.verbose = true
|
104
|
-
t.rcov_opts = %q[--aggregate coverage.data --sort coverage --text-report --exclude "config,.bundle/*,gems/*,spec/*" -o doc/coverage -Ilib -i "noah.rb"]
|
131
|
+
desc "Demo environment"
|
132
|
+
task :start_demo do
|
133
|
+
puts "Soon, young padawan"
|
105
134
|
end
|
data/TODO.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Brain dump of stuff
|
2
|
+
* Documentation
|
3
|
+
|
4
|
+
Need to finish documenting everything for YARD to pick up.
|
5
|
+
|
6
|
+
* Stabilize API
|
7
|
+
|
8
|
+
I'm seriously considering moving to a single endpoint with JSON request bodies. Still up in the air. I'm not totally sold on the current layout.
|
9
|
+
|
10
|
+
* Write my own CLI class
|
11
|
+
|
12
|
+
I think I might be bumping into some issues related to Vegas as well.
|
13
|
+
|
14
|
+
* Watchers
|
15
|
+
|
16
|
+
This is going to be a fun task. I'm serious.
|
17
|
+
|
18
|
+
* Ephemeral nodes
|
19
|
+
|
20
|
+
Not sure how I want to implement that. Not too keen on storing them as in-memory hashes. Maybe a LRU in Redis?
|
21
|
+
|
22
|
+
* Examples
|
23
|
+
|
24
|
+
I need to make some example apps to really demonstrate what I'm trying to accomplish.
|
25
|
+
|
26
|
+
* Clean up deps
|
27
|
+
|
28
|
+
Feels like I'm relying too much on external libraries.
|
29
|
+
|
30
|
+
* Benchmark
|
31
|
+
|
32
|
+
Need some client libs for this
|
33
|
+
|
34
|
+
# Done TODOS
|
35
|
+
* Github pages
|
36
|
+
- see [[http://lusis.github.com/Noah/]]
|
37
|
+
|
38
|
+
* Bundle a war
|
39
|
+
- see [[https://github.com/downloads/lusis/Noah/noah.war]]
|
40
|
+
|
41
|
+
* Examples
|
42
|
+
- Sort of done. Demo app is up! [[http://noah-demo.heroku.com/]]. Also see `examples` directory.
|
43
|
+
|
44
|
+
* Consider ditching Sinatra::Namespace
|
45
|
+
- Done. It was also causing issues with YARD generation. @rkh confirmed known issue via twitter.
|
46
|
+
|
47
|
+
* Namespace models
|
48
|
+
- Done.
|
49
|
+
|
50
|
+
* Watchers
|
51
|
+
- Partially done. Framework is in place to create a custom Watcher by hooking directly into Redis. Need to expand that to "official" watchers
|
52
|
+
|
53
|
+
|
54
|
+
## Watcher specific stuff
|
55
|
+
* Implement a watcher endpoint
|
56
|
+
* Implement webhooks
|
57
|
+
* Implement AMQP
|
58
|
+
* Implement REST
|
59
|
+
* Implement JMX on JRuby
|
data/bin/noah
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
|
3
|
+
require 'rubygems'
|
3
4
|
require 'noah'
|
4
5
|
require 'vegas'
|
5
6
|
|
6
7
|
Vegas::Runner.new(Noah::App, 'noah') do |runner, opts, app|
|
7
|
-
opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r }
|
8
|
+
opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r; Noah::App.set :redis_url, r }
|
8
9
|
end
|
data/bin/noah-watcher.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rbtrace'
|
5
|
+
require 'logger'
|
6
|
+
require 'optparse'
|
7
|
+
require 'em-hiredis'
|
8
|
+
require 'eventmachine'
|
9
|
+
require 'em-http-request'
|
10
|
+
require 'thin'
|
11
|
+
require 'noah'
|
12
|
+
require 'json'
|
13
|
+
|
14
|
+
LOGGER = Logger.new(STDOUT)
|
15
|
+
|
16
|
+
class EventMachine::NoahAgent
|
17
|
+
include EM::Deferrable
|
18
|
+
|
19
|
+
@@watchers = Noah::Watcher.watch_list
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@logger = LOGGER
|
23
|
+
@logger.debug("Initializing with #{@@watchers.size} registered watches")
|
24
|
+
if EventMachine.reactor_running?
|
25
|
+
@worker = EM.spawn {|event, message, watch_list|
|
26
|
+
logger = LOGGER
|
27
|
+
logger.debug("Worker initiated")
|
28
|
+
logger.info("got event on http worker: #{event}")
|
29
|
+
logger.info("got message on http worker: #{message}")
|
30
|
+
matches = watch_list.find_all{|w| event =~ /^#{Base64.decode64(w)}/}
|
31
|
+
logger.debug("Found #{matches.size} matches for #{event}")
|
32
|
+
EM::Iterator.new(matches).each do |watch, iter|
|
33
|
+
p, ep = Base64.decode64(watch).split("|")
|
34
|
+
logger.info("Sending message to: #{ep} for pattern: #{p}")
|
35
|
+
http = EM::HttpRequest.new(ep, :connection_timeout => 2, :inactivity_timeout => 4).post :body => message
|
36
|
+
http.callback {
|
37
|
+
LOGGER.debug("Message posted to #{ep} successfully")
|
38
|
+
#iter.next
|
39
|
+
}
|
40
|
+
http.errback {
|
41
|
+
LOGGER.debug("Something went wrong")
|
42
|
+
#iter.net
|
43
|
+
}
|
44
|
+
iter.next
|
45
|
+
end
|
46
|
+
}
|
47
|
+
else
|
48
|
+
logger.fatal("Must be inside a reactor!")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def watchers
|
53
|
+
@@watchers.size
|
54
|
+
end
|
55
|
+
|
56
|
+
def reread_watchers
|
57
|
+
@logger.debug("Found new watches")
|
58
|
+
@logger.debug("Current watch count: #{@@watchers.size}")
|
59
|
+
@@watchers = Noah::Watcher.watch_list
|
60
|
+
@logger.debug("New watch count: #{@@watchers.size}")
|
61
|
+
#@logger.debug(@@watchers)
|
62
|
+
end
|
63
|
+
|
64
|
+
def broker(msg)
|
65
|
+
# This is just for testing for now
|
66
|
+
@logger.warn(msg)
|
67
|
+
e,m = msg.split("|")
|
68
|
+
be = Base64.encode64(e).gsub("\n","")
|
69
|
+
@logger.info("Encoded event: #{be}")
|
70
|
+
@worker.notify e, m, @@watchers.clone
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
EventMachine.run do
|
75
|
+
logger = LOGGER
|
76
|
+
noah = EventMachine::NoahAgent.new
|
77
|
+
# Passing messages...like a boss
|
78
|
+
master_channel = EventMachine::Channel.new
|
79
|
+
|
80
|
+
r = EventMachine::Hiredis::Client.connect
|
81
|
+
logger.debug("Starting up")
|
82
|
+
r.psubscribe("//noah/*")
|
83
|
+
r.on(:pmessage) do |pattern, event, message|
|
84
|
+
noah.reread_watchers if event =~ /^\/\/noah\/watcher\/.*/
|
85
|
+
master_channel.push "#{event}|#{message}"
|
86
|
+
logger.debug("Saw[#{event}]")
|
87
|
+
end
|
88
|
+
|
89
|
+
sub = master_channel.subscribe {|msg|
|
90
|
+
# We short circuit if we have no watchers
|
91
|
+
noah.broker(msg) unless noah.watchers == 0
|
92
|
+
}
|
93
|
+
end
|
data/config.ru
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join('.', 'lib','noah')
|
3
|
+
## Uncomment the following to hardcode a redis url
|
4
|
+
ENV['REDIS_URL'] = "redis://localhost:6379/1"
|
5
|
+
noah = Noah::App.new
|
6
|
+
run noah
|
data/config/warble.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Disable automatic framework detection by uncommenting/setting to false
|
2
|
+
# Warbler.framework_detection = false
|
3
|
+
|
4
|
+
# Warbler web application assembly configuration file
|
5
|
+
Warbler::Config.new do |config|
|
6
|
+
#config.features = %w(gemjar)
|
7
|
+
config.dirs = %w(config lib views)
|
8
|
+
config.includes = FileList["config.ru"]
|
9
|
+
config.excludes = FileList["noah.gemspec", "Gemfile", "Gemfile.lock"]
|
10
|
+
config.bundler = false
|
11
|
+
config.gems += ["json", "ohm", "ohm-contrib", "sinatra", "sinatra-namespace", "haml"]
|
12
|
+
config.gem_excludes = [/^(test|spec)\//]
|
13
|
+
config.public_html = FileList["views/**/*"]
|
14
|
+
config.webxml.booter = :rack
|
15
|
+
#config.webxml.rackup.path = 'WEB-INF/config.ru'
|
16
|
+
#config.webxml.rackup = %{require './lib/noah'; run Noah::App}
|
17
|
+
# config.webxml.rackup = require 'cgi' && CGI::escapeHTML(File.read("config.ru"))
|
18
|
+
end
|
data/examples/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# Examples
|
2
|
+
The following is a list of notes regarding the examples in this directory.
|
3
|
+
|
4
|
+
## General Requirements
|
5
|
+
|
6
|
+
You'll need a few additional gems
|
7
|
+
|
8
|
+
* [em-hiredis](https://github.com/mloughran/em-hiredis)
|
9
|
+
You'll have to compile/install from source. Sorry. Should pull in the `hiredis` native ext.
|
10
|
+
* [em-http-request](https://github.com/igrigorik/em-http-request)
|
11
|
+
Available via rubygems
|
12
|
+
* [em-websocket](https://github.com/igrigorik/em-websocket)
|
13
|
+
Available via rubygems
|
14
|
+
|
15
|
+
## custom-watcher.rb
|
16
|
+
This is an idea I'm tossing around for allowing easy custom watchers to be written.
|
17
|
+
Essentially the idea is that you tap into the Redis subscription with a defined pattern and a destination.
|
18
|
+
|
19
|
+
### Example
|
20
|
+
|
21
|
+
require './watcher-idea.rb'
|
22
|
+
|
23
|
+
Noah::Watcher.watch do
|
24
|
+
pattern "//noah/configuration/*"
|
25
|
+
destination Proc.new {|x| something_with(x)}
|
26
|
+
run!
|
27
|
+
end
|
28
|
+
|
29
|
+
## logger.rb
|
30
|
+
An example using logger as a watcher. Pretty straighforward.
|
31
|
+
|
32
|
+
|
33
|
+
## httpclient.rb/httpclient-server.rb
|
34
|
+
This is an example of how the Webhook system would work
|
35
|
+
|
36
|
+
### Running
|
37
|
+
|
38
|
+
To get the maximum effect, start with a clean Redis database
|
39
|
+
|
40
|
+
* Start the webhook reciever
|
41
|
+
|
42
|
+
noah/examples$ ruby httpclient-server.rb
|
43
|
+
== Sinatra/1.1.2 has taken the stage on 4567 for development with backup from Thin
|
44
|
+
>> Thin web server (v1.2.7 codename No Hup)
|
45
|
+
>> Maximum connections set to 1024
|
46
|
+
>> Listening on 0.0.0.0:4567, CTRL+C to stop
|
47
|
+
|
48
|
+
* Start the webhook publisher
|
49
|
+
|
50
|
+
noah/examples$ ruby httpclient.rb
|
51
|
+
|
52
|
+
* Run the rake sample script
|
53
|
+
|
54
|
+
In the publisher window, you should see some messages like so:
|
55
|
+
|
56
|
+
Got message for noah.Host[localhost].create
|
57
|
+
Got message for noah.Host[localhost].save
|
58
|
+
Got message for noah.Host[localhost].save
|
59
|
+
Got message for noah.Host[localhost].update
|
60
|
+
|
61
|
+
In the server window, you should see the following:
|
62
|
+
|
63
|
+
"{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
|
64
|
+
127.0.0.1 - - [15/Feb/2011 00:19:05] "POST /webhook HTTP/1.1" 200 135 0.0024
|
65
|
+
"{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
|
66
|
+
127.0.0.1 - - [15/Feb/2011 00:19:05] "POST /webhook HTTP/1.1" 200 135 0.0004
|
67
|
+
"{\"id\":\"1\",\"name\":\"localhost\",\"status\":\"up\",\"created_at\":\"2011-02-15 05:19:05 UTC\",\"updated_at\":\"2011-02-15 05:19:05 UTC\",\"services\":[]}"
|
68
|
+
|
69
|
+
|
70
|
+
## websocket.rb
|
71
|
+
This is an example of using Websockets, EventMachine and Redis PubSub to provide a "status" console of sorts.
|
72
|
+
|
73
|
+
### Running
|
74
|
+
|
75
|
+
To get the maximum effect, start with a clean Redis database.
|
76
|
+
|
77
|
+
* Start the server:
|
78
|
+
|
79
|
+
~/development/noah/examples$ ./websocket.rb
|
80
|
+
>> Thin web server (v1.2.7 codename No Hup)
|
81
|
+
>> Maximum connections set to 1024
|
82
|
+
>> Listening on 0.0.0.0:3000, CTRL+C to stop
|
83
|
+
|
84
|
+
You should be able to load up the "normal" Noah sample page on [http://localhost:3000].
|
85
|
+
|
86
|
+
* Load the "websocket" file
|
87
|
+
|
88
|
+
In another browser window, open the `websocket.html` file.
|
89
|
+
|
90
|
+
* Send a message
|
91
|
+
|
92
|
+
From another terminal window send the following:
|
93
|
+
|
94
|
+
curl -X PUT -d '{"name":"testhost2","status":"down"}' http://localhost:3000/h/testhost2
|
95
|
+
|
96
|
+
You should see the message come across in the browser window like so:
|
97
|
+
|
98
|
+
connected...
|
99
|
+
|
100
|
+
2 connected and waiting....
|
101
|
+
|
102
|
+
(noah.Host[testhost2].create) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
|
103
|
+
|
104
|
+
(noah.Host[testhost2].save) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
|
105
|
+
|
106
|
+
(noah.Host[testhost2].save) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
|
107
|
+
|
108
|
+
(noah.Host[testhost2].update) {"id":"1","name":"testhost2","status":"down","created_at":"2011-02-14 20:58:04 UTC","updated_at":"2011-02-14 20:58:04 UTC","services":[]}
|
109
|
+
|
110
|
+
You can see the Watcher pattern in the parenthesis and then the JSON message body.
|
111
|
+
|
112
|
+
For fun, refresh the page to clear it and then run the sample data population rake task.
|
113
|
+
|
114
|
+
### Known issues
|
115
|
+
When I started working on the Watcher stuff, I realized that I'm sending A LOT of extranous messages. These are mostly the result of the way I'm creating new objects with Ohm (i.e. via `.create`).
|
116
|
+
I'll be cleaning that up and trying to get down to a single message per operation.
|