noah 0.0.9 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -6
- data/TODO.md +15 -9
- data/bin/noah-watcher.rb +18 -10
- data/lib/noah/app.rb +1 -1
- data/lib/noah/application_routes.rb +1 -1
- data/lib/noah/configuration_routes.rb +1 -1
- data/lib/noah/ephemeral_routes.rb +35 -6
- data/lib/noah/helpers.rb +25 -0
- data/lib/noah/host_routes.rb +1 -1
- data/lib/noah/models/ephemerals.rb +21 -2
- data/lib/noah/models/watchers.rb +9 -1
- data/lib/noah/service_routes.rb +1 -1
- data/lib/noah/version.rb +1 -1
- data/lib/noah/watcher_routes.rb +34 -1
- data/noah.gemspec +1 -0
- data/spec/configuration_spec.rb +7 -10
- data/spec/ephemeral_spec.rb +20 -13
- data/spec/noahapp_configuration_spec.rb +2 -2
- data/spec/noahapp_ephemeral_spec.rb +115 -0
- data/spec/noahapp_host_spec.rb +1 -1
- data/spec/noahapp_service_spec.rb +1 -1
- data/spec/noahapp_watcher_spec.rb +89 -0
- data/spec/watcher_spec.rb +5 -5
- metadata +4 -4
- data/lib/vendor/em-hiredis/em-hiredis-0.0.1.gem +0 -0
data/Rakefile
CHANGED
@@ -13,28 +13,24 @@ end
|
|
13
13
|
|
14
14
|
|
15
15
|
task :default => :run
|
16
|
-
task :test =>
|
16
|
+
task :test => :run
|
17
17
|
|
18
18
|
desc "Run tests and manage server start/stop"
|
19
19
|
task :run => [:start, :spec, :stop]
|
20
20
|
|
21
|
-
desc "Start the Redis server"
|
22
21
|
task :start do
|
23
22
|
puts "Starting redis-server"
|
24
23
|
system "redis-server #{REDIS_CNF}"
|
25
24
|
end
|
26
25
|
|
27
|
-
desc "Stop the Redis server"
|
28
26
|
task :stop do
|
29
27
|
puts "Killing redis"
|
30
28
|
system "killall -TERM redis-server"
|
31
29
|
end
|
32
30
|
|
33
31
|
namespace :coverage do
|
34
|
-
desc "Delete aggregate coverage data."
|
35
32
|
task(:clean) { rm_f "coverage.data" }
|
36
33
|
end
|
37
|
-
desc "Run Rcov code coverage analysis"
|
38
34
|
RSpec::Core::RakeTask.new(:coverage) do |t|
|
39
35
|
t.rcov = true
|
40
36
|
t.verbose = true
|
@@ -128,7 +124,6 @@ rescue LoadError
|
|
128
124
|
"You need YARD installed to generate docs"
|
129
125
|
end
|
130
126
|
|
131
|
-
desc "Demo environment"
|
132
127
|
task :start_demo do
|
133
128
|
puts "Soon, young padawan"
|
134
129
|
end
|
data/TODO.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
# Brain dump of stuff
|
2
|
+
* Fix JRuby
|
3
|
+
|
4
|
+
This is an ongoing issue for me. I can't rely on stuff that's MRI only.
|
5
|
+
|
6
|
+
* Break agent into separate gem
|
7
|
+
|
8
|
+
Again so that the server gem can be as lean as possible
|
9
|
+
|
2
10
|
* Documentation
|
3
11
|
|
4
12
|
Need to finish documenting everything for YARD to pick up.
|
@@ -13,15 +21,18 @@
|
|
13
21
|
|
14
22
|
* Watchers
|
15
23
|
|
16
|
-
|
24
|
+
**IN PROGRESS**
|
25
|
+
Need to resolve some issues around pathing for Configuration and Service nodes however watch registration and listing are up.
|
26
|
+
Need to address alternative watcher URIs. Webhook is the only one supported right now.
|
17
27
|
|
18
28
|
* Ephemeral nodes
|
19
29
|
|
20
|
-
|
30
|
+
**IN PROGRESS**
|
31
|
+
implement lifetime support
|
21
32
|
|
22
33
|
* Examples
|
23
34
|
|
24
|
-
I
|
35
|
+
Pretty happy with the examples I have but I need more. Want some in other languages - Python, Java, whatever!
|
25
36
|
|
26
37
|
* Clean up deps
|
27
38
|
|
@@ -35,9 +46,6 @@
|
|
35
46
|
* Github pages
|
36
47
|
- see [[http://lusis.github.com/Noah/]]
|
37
48
|
|
38
|
-
* Bundle a war
|
39
|
-
- see [[https://github.com/downloads/lusis/Noah/noah.war]]
|
40
|
-
|
41
49
|
* Examples
|
42
50
|
- Sort of done. Demo app is up! [[http://noah-demo.heroku.com/]]. Also see `examples` directory.
|
43
51
|
|
@@ -48,12 +56,10 @@
|
|
48
56
|
- Done.
|
49
57
|
|
50
58
|
* Watchers
|
51
|
-
-
|
59
|
+
- Done. GET PUT DELETE are all available at the '/w/' endpoint now!
|
52
60
|
|
53
61
|
|
54
62
|
## Watcher specific stuff
|
55
|
-
* Implement a watcher endpoint
|
56
|
-
* Implement webhooks
|
57
63
|
* Implement AMQP
|
58
64
|
* Implement REST
|
59
65
|
* Implement JMX on JRuby
|
data/bin/noah-watcher.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
3
|
+
HELP = <<-EOH
|
4
|
+
Unfortunately, the agent script has some difficult requirements right now.
|
5
|
+
Please see https://github.com/lusis/Noah/Watcher-Agent for details.
|
6
|
+
EOH
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
require 'logger'
|
10
|
+
require 'optparse'
|
11
|
+
require 'em-hiredis'
|
12
|
+
require 'eventmachine'
|
13
|
+
require 'em-http-request'
|
14
|
+
require 'noah'
|
15
|
+
require 'json'
|
16
|
+
rescue LoadError
|
17
|
+
puts HELP
|
18
|
+
exit
|
19
|
+
end
|
13
20
|
|
14
21
|
LOGGER = Logger.new(STDOUT)
|
15
22
|
|
@@ -73,6 +80,7 @@ end
|
|
73
80
|
|
74
81
|
EventMachine.run do
|
75
82
|
logger = LOGGER
|
83
|
+
trap("INT") { logger.debug("Shutting down. Watches will not be fired");EM.stop }
|
76
84
|
noah = EventMachine::NoahAgent.new
|
77
85
|
# Passing messages...like a boss
|
78
86
|
master_channel = EventMachine::Channel.new
|
data/lib/noah/app.rb
CHANGED
@@ -63,7 +63,7 @@ module Noah
|
|
63
63
|
load File.join(File.dirname(__FILE__), 'application_routes.rb')
|
64
64
|
load File.join(File.dirname(__FILE__), 'configuration_routes.rb')
|
65
65
|
load File.join(File.dirname(__FILE__), 'watcher_routes.rb')
|
66
|
-
|
66
|
+
load File.join(File.dirname(__FILE__), 'ephemeral_routes.rb')
|
67
67
|
|
68
68
|
end
|
69
69
|
end
|
@@ -59,7 +59,7 @@ class Noah::App
|
|
59
59
|
r = {"result" => "success","id" => "#{config.id}", "action" => action, "dependencies" => dependency_action, "application" => app.name, "item" => config.name}
|
60
60
|
r.to_json
|
61
61
|
else
|
62
|
-
raise "#{config
|
62
|
+
raise "#{format_errors(config)}"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -1,19 +1,48 @@
|
|
1
1
|
class Noah::App
|
2
|
-
|
2
|
+
get '/e/?' do
|
3
|
+
halt 404
|
4
|
+
end
|
5
|
+
|
3
6
|
get '/e/*' do
|
4
|
-
|
5
|
-
|
7
|
+
params["splat"].size == 0 ? (halt 404) : (e=Noah::Ephemeral.find(:path => "/#{params["splat"][0]}").first)
|
8
|
+
(halt 404) if e.nil?
|
9
|
+
content_type "application/octet-stream"
|
10
|
+
e.data.nil? ? "" : "#{e.data}"
|
6
11
|
end
|
7
12
|
|
8
13
|
put '/e/*/watch' do
|
9
|
-
|
14
|
+
required_params = ["endpoint"]
|
15
|
+
data = JSON.parse(request.body.read)
|
16
|
+
(data.keys.sort == required_params.sort) ? (e = Noah::Watcher.find(:path => params[:splat][0]).first) : (raise "Missing Parameters")
|
17
|
+
e.nil? ? (halt 404) : (w = e.watch!(:endpoint => data["endpoint"]))
|
18
|
+
w.to_json
|
10
19
|
end
|
11
20
|
|
12
21
|
put '/e/*' do
|
13
|
-
|
22
|
+
raise("Data too large") if request.body.size > 512
|
23
|
+
d = request.body.read || nil
|
24
|
+
e = Noah::Ephemeral.find_or_create(:path => "/#{params[:splat][0]}")
|
25
|
+
e.data = d
|
26
|
+
if e.valid?
|
27
|
+
e.save
|
28
|
+
action = e.is_new? ? "create" : "update"
|
29
|
+
r = {"action" => action, "result" => "success", "id" => e.id, "path" => e.path, "data" => e.data}
|
30
|
+
r.to_json
|
31
|
+
else
|
32
|
+
raise "#{format_errors(e)}"
|
33
|
+
end
|
14
34
|
end
|
15
35
|
|
16
36
|
delete '/e/*' do
|
17
|
-
|
37
|
+
p = params[:splat][0]
|
38
|
+
e = Noah::Ephemeral.find(:path => "/"+p).first
|
39
|
+
if e
|
40
|
+
e.delete
|
41
|
+
r = {"result" => "success", "id" => "#{e.id}", "action" => "delete", "path" => e.name}
|
42
|
+
r.to_json
|
43
|
+
else
|
44
|
+
halt 404
|
45
|
+
end
|
18
46
|
end
|
47
|
+
|
19
48
|
end
|
data/lib/noah/helpers.rb
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
module Noah
|
2
2
|
module SinatraHelpers
|
3
|
+
|
4
|
+
def format_errors(model)
|
5
|
+
error_messages = model.errors.present do |e|
|
6
|
+
# Missing attributes
|
7
|
+
e.on [:name, :not_present], "Name attribute missing"
|
8
|
+
e.on [:status, :not_present], "Status attribute missing"
|
9
|
+
e.on [:format, :not_present], "Format attribute missing"
|
10
|
+
e.on [:body, :not_present], "Body attribute missing"
|
11
|
+
e.on [:application_id, :not_present], "Application attribute missing"
|
12
|
+
e.on [:path, :not_present], "Path attribute missing"
|
13
|
+
e.on [:pattern, :not_present], "Pattern attribute missing"
|
14
|
+
e.on [:endpoint, :not_present], "Endpoint attribute missing"
|
15
|
+
# Invalid option
|
16
|
+
e.on [:status, :not_member], "Status must be up, down or pending"
|
17
|
+
# Duplicate keys
|
18
|
+
e.on [[:name, :application_id], :not_unique], "Record already exists"
|
19
|
+
e.on [[:name, :host_id], :not_unique], "Record already exists"
|
20
|
+
e.on [[:endpoint, :pattern], :not_unique], "Record already exists"
|
21
|
+
e.on [:path, :not_unique], "Record already exists"
|
22
|
+
# Custom exceptions
|
23
|
+
e.on [:pattern, :already_provided], "Pattern is already provided"
|
24
|
+
e.on [:pattern, :replaces_existing], "Pattern would overwrite existing"
|
25
|
+
end
|
26
|
+
error_messages.first
|
27
|
+
end
|
3
28
|
|
4
29
|
def host(opts = {})
|
5
30
|
Noah::Host.find(opts).first
|
data/lib/noah/host_routes.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'digest/sha1'
|
2
1
|
module Noah
|
3
2
|
class Ephemeral < Model #NYI
|
4
3
|
|
5
4
|
attribute :path
|
6
5
|
attribute :data
|
6
|
+
attribute :lifetime
|
7
7
|
|
8
8
|
index :path
|
9
9
|
|
@@ -17,6 +17,25 @@ module Noah
|
|
17
17
|
@name = path
|
18
18
|
end
|
19
19
|
|
20
|
+
def to_hash
|
21
|
+
h = {:path => path, :data => data, :created_at => created_at, :updated_at => :updated_at}
|
22
|
+
super.merge(h)
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def find_or_create(opts = {})
|
27
|
+
begin
|
28
|
+
find(opts).first.nil? ? (eph = create(opts)) : (eph = find(opts).first)
|
29
|
+
if eph.valid?
|
30
|
+
eph.save
|
31
|
+
end
|
32
|
+
eph
|
33
|
+
rescue Exception => e
|
34
|
+
e.message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
20
39
|
protected
|
21
40
|
def save_hook
|
22
41
|
# called after any create,update,delete
|
@@ -27,7 +46,7 @@ module Noah
|
|
27
46
|
def path_protected?(path_part)
|
28
47
|
# Check for protected paths in ephemeral nodes
|
29
48
|
end
|
30
|
-
|
49
|
+
|
31
50
|
end
|
32
51
|
|
33
52
|
end
|
data/lib/noah/models/watchers.rb
CHANGED
@@ -7,6 +7,7 @@ module Noah
|
|
7
7
|
|
8
8
|
attribute :pattern
|
9
9
|
attribute :endpoint
|
10
|
+
attribute :name
|
10
11
|
|
11
12
|
index :pattern
|
12
13
|
index :endpoint
|
@@ -29,12 +30,19 @@ module Noah
|
|
29
30
|
super.merge(h)
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
+
class << self
|
34
|
+
def find_by_name(name)
|
35
|
+
pattern, endpoint = Base64.decode64(name).split('|')
|
36
|
+
find(:pattern => pattern, :endpoint => endpoint).first
|
37
|
+
end
|
38
|
+
|
39
|
+
def watch_list
|
33
40
|
arr = []
|
34
41
|
watches = self.all.sort_by(:pattern)
|
35
42
|
watches.each {|w| arr << w.name}
|
36
43
|
arr
|
37
44
|
end
|
45
|
+
end
|
38
46
|
|
39
47
|
private
|
40
48
|
# Not sure about these next two.
|
data/lib/noah/service_routes.rb
CHANGED
@@ -50,7 +50,7 @@ class Noah::App
|
|
50
50
|
r = {"action" => action, "result" => "success", "id" => service.id, "host" => h.name, "name" => service.name}
|
51
51
|
r.to_json
|
52
52
|
else
|
53
|
-
raise "#{service
|
53
|
+
raise "#{format_errors(service)}"
|
54
54
|
end
|
55
55
|
else
|
56
56
|
raise "Missing Parameters"
|
data/lib/noah/version.rb
CHANGED
data/lib/noah/watcher_routes.rb
CHANGED
@@ -1,12 +1,45 @@
|
|
1
1
|
class Noah::App
|
2
2
|
|
3
|
+
get '/w/:name' do |name|
|
4
|
+
w = Noah::Watcher.find_by_name(name)
|
5
|
+
w.nil? ? (halt 404) : w.to_json
|
6
|
+
end
|
7
|
+
|
3
8
|
get '/w/?' do
|
4
9
|
w = Noah::Watcher.all.sort_by(:pattern)
|
5
10
|
if w.size == 0
|
6
11
|
halt 404
|
7
12
|
else
|
8
13
|
w.to_json
|
9
|
-
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
put '/w/?' do
|
18
|
+
required_params = %w[endpoint pattern]
|
19
|
+
data = JSON.parse(request.body.read)
|
20
|
+
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
21
|
+
w = Noah::Watcher.create(:pattern => pattern, :endpoint => endpoint)
|
22
|
+
if w.valid?
|
23
|
+
w.save
|
24
|
+
r = {"action" => "create", "result" => "success"}.merge(w.to_hash)
|
25
|
+
r.to_json
|
26
|
+
else
|
27
|
+
raise "#{format_errors(w)}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
delete '/w/?' do
|
32
|
+
required_params = %w[endpoint pattern]
|
33
|
+
data = JSON.parse(request.body.read)
|
34
|
+
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
35
|
+
w = Noah::Watcher.find(:pattern => pattern, :endpoint => endpoint).first
|
36
|
+
if w.nil?
|
37
|
+
halt 404
|
38
|
+
else
|
39
|
+
w.delete
|
40
|
+
r = {"result" => "success", "action" => "delete"}.merge(w.to_hash)
|
41
|
+
r.to_json
|
42
|
+
end
|
10
43
|
end
|
11
44
|
|
12
45
|
end
|
data/noah.gemspec
CHANGED
data/spec/configuration_spec.rb
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "Using the Configuration Model", :reset_redis => true do
|
4
|
-
before(:all) do
|
5
|
-
app = Noah::Application.create(:name => "my_application")
|
6
|
-
app.save
|
7
|
-
@appconf_string = {:name => "mystringconf", :format => "string", :body => "some_var", :application_id => app.id}
|
8
|
-
@appconf_json = {:name => "myjsonconf", :format => "json", :body => @appconf_string.to_json, :application_id => app.id}
|
9
|
-
@appconf_missing_name = @appconf_string.reject {|x| x == :name}
|
10
|
-
@appconf_missing_format = @appconf_string.reject {|x| x == :format}
|
11
|
-
@appconf_missing_body = @appconf_string.reject {|x| x == :body}
|
12
|
-
@appconf_missing_application = @appconf_string.reject {|x| x == :application_id}
|
13
|
-
end
|
14
4
|
before(:each) do
|
15
5
|
Ohm.redis.flushdb
|
6
|
+
app = Noah::Application.create :name => "my_application"
|
7
|
+
@appconf_string = {:name => "mystringconf", :format => "string", :body => "some_var", :application_id => app.id}
|
8
|
+
@appconf_json = {:name => "myjsonconf", :format => "json", :body => @appconf_string.to_json, :application_id => app.id}
|
9
|
+
@appconf_missing_name = @appconf_string.reject {|k, v| k == :name}
|
10
|
+
@appconf_missing_format = @appconf_string.reject {|k, v| k == :format}
|
11
|
+
@appconf_missing_body = @appconf_string.reject {|k, v| k == :body}
|
12
|
+
@appconf_missing_application = @appconf_string.reject {|k, v| k == :application_id}
|
16
13
|
end
|
17
14
|
after(:each) do
|
18
15
|
Ohm.redis.flushdb
|
data/spec/ephemeral_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe "Using the Ephemeral Model", :reset_redis => true do
|
4
4
|
before(:all) do
|
5
5
|
@edata = {:path => "/foo/bar/baz", :data => "some_value"}
|
6
|
-
@emissing_path = @edata.reject {|
|
7
|
-
@emissing_data = @edata.reject {|
|
6
|
+
@emissing_path = @edata.reject {|k, v| k == :path}
|
7
|
+
@emissing_data = @edata.reject {|k, v| k == :data}
|
8
8
|
@good_ephemeral = Noah::Ephemeral.new(@edata)
|
9
9
|
@missing_path = Noah::Ephemeral.new(@emissing_path)
|
10
10
|
@missing_data = Noah::Ephemeral.new(@emissing_data)
|
@@ -28,15 +28,15 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
28
28
|
b = Noah::Ephemeral[@missing_data.id]
|
29
29
|
b.should == @missing_data
|
30
30
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
it "update an existing Noah::Ephemeral" do
|
32
|
+
e = Noah::Ephemeral.create :path => "/is/new/test"
|
33
|
+
Noah::Ephemeral.all.size.should == 1
|
34
|
+
sleep(2)
|
35
|
+
c = Noah::Ephemeral[e.id]
|
36
|
+
c.data = "updated_data"
|
37
|
+
c.save
|
38
|
+
c.is_new?.should == false
|
39
|
+
end
|
40
40
|
it "delete an existing Noah::Ephemeral" do
|
41
41
|
@good_ephemeral.save
|
42
42
|
@good_ephemeral.delete
|
@@ -45,8 +45,15 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
45
45
|
end
|
46
46
|
describe "should not" do
|
47
47
|
it "create a new Noah::Ephemeral with missing path" do
|
48
|
-
|
49
|
-
|
48
|
+
e = Noah::Ephemeral.create
|
49
|
+
e.valid?.should == false
|
50
|
+
e.errors.should == [[:path, :not_present]]
|
51
|
+
end
|
52
|
+
it "create a duplicate Noah::Ephemeral" do
|
53
|
+
e = Noah::Ephemeral.create :path => "/random/path"
|
54
|
+
f = Noah::Ephemeral.create :path => "/random/path"
|
55
|
+
f.valid?.should == false
|
56
|
+
f.errors.should == [[:path, :not_unique]]
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
@@ -34,8 +34,8 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
34
34
|
response = YAML.load(last_response.body)
|
35
35
|
response.is_a?(Hash).should == true
|
36
36
|
response.keys.should == ["development"]
|
37
|
-
response["development"].keys.should == ["
|
38
|
-
response["development"].values.should == ["
|
37
|
+
response["development"].keys.sort.should == ["adapter", "database", "password", "username"]
|
38
|
+
response["development"].values.sort.should == ["dev_password", "dev_user", "development_database", "mysql"]
|
39
39
|
end
|
40
40
|
it "invalid application should not work" do
|
41
41
|
get '/c/badapp'
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Using the Ephemeral API", :reset_redis => true do
|
4
|
+
before(:each) do
|
5
|
+
Ohm.redis.flushdb
|
6
|
+
Noah::Ephemeral.create(:path => "/foo/bar/baz", :data => "value1")
|
7
|
+
Noah::Ephemeral.create(:path => "/baz/bar")
|
8
|
+
end
|
9
|
+
after(:each) do
|
10
|
+
Ohm.redis.flushdb
|
11
|
+
end
|
12
|
+
describe "calling" do
|
13
|
+
|
14
|
+
describe "GET" do
|
15
|
+
it "all ephemerals should return 404" do
|
16
|
+
get '/e'
|
17
|
+
last_response.should_not be_ok
|
18
|
+
last_response.status.should == 404
|
19
|
+
response = last_response.should return_json
|
20
|
+
response['error_message'].should == 'Resource not found'
|
21
|
+
response['result'].should == 'failure'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "named path with data should work" do
|
25
|
+
get '/e/foo/bar/baz'
|
26
|
+
last_response.should be_ok
|
27
|
+
last_response.body.should == 'value1'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "named path without data should work" do
|
31
|
+
get '/e/baz/bar'
|
32
|
+
last_response.status.should == 200
|
33
|
+
last_response.body.should == ""
|
34
|
+
end
|
35
|
+
|
36
|
+
it "invalid path should not work" do
|
37
|
+
get '/e/ssss/dddd'
|
38
|
+
last_response.should_not be_ok
|
39
|
+
last_response.status.should == 404
|
40
|
+
response = last_response.should return_json
|
41
|
+
response['error_message'].should == 'Resource not found'
|
42
|
+
response['result'].should == 'failure'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "PUT" do
|
47
|
+
it "new ephemeral with data should work" do
|
48
|
+
put '/e/whiz/bang/', 'value3'
|
49
|
+
last_response.should be_ok
|
50
|
+
response = last_response.should return_json
|
51
|
+
response['result'].should == 'success'
|
52
|
+
response['id'].nil?.should == false
|
53
|
+
response['path'].should == '/whiz/bang/'
|
54
|
+
response['data'].should == 'value3'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "new ephemeral without data should work" do
|
58
|
+
put '/e/bang/whiz'
|
59
|
+
last_response.should be_ok
|
60
|
+
response = last_response.should return_json
|
61
|
+
response['result'].should == 'success'
|
62
|
+
response['action'].should == 'create'
|
63
|
+
response['id'].nil?.should == false
|
64
|
+
response['path'].should == '/bang/whiz'
|
65
|
+
response['data'].should == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "existing ephemeral with data should work" do
|
69
|
+
Noah::Ephemeral.create(:path => '/new/ephemeral', :data => 'old_value')
|
70
|
+
get '/e/new/ephemeral'
|
71
|
+
last_response.should be_ok
|
72
|
+
last_response.body.should == 'old_value'
|
73
|
+
put '/e/new/ephemeral', 'new_value'
|
74
|
+
last_response.should be_ok
|
75
|
+
get '/e/new/ephemeral'
|
76
|
+
last_response.should be_ok
|
77
|
+
last_response.body.should == 'new_value'
|
78
|
+
end
|
79
|
+
it "existing ephemeral without data should work" do
|
80
|
+
Noah::Ephemeral.create(:path => '/a/random/key')
|
81
|
+
get '/e/a/random/key'
|
82
|
+
last_response.should be_ok
|
83
|
+
last_response.body.should == ""
|
84
|
+
put '/e/a/random/key', 'a new value'
|
85
|
+
last_response.should be_ok
|
86
|
+
get '/e/a/random/key'
|
87
|
+
last_response.should be_ok
|
88
|
+
last_response.body.should == 'a new value'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "DELETE" do
|
93
|
+
it "existing path should work" do
|
94
|
+
e = Noah::Ephemeral.new(:path => '/slart/i/bart/fast', :data => 'someddata')
|
95
|
+
e.save
|
96
|
+
delete "/e/slart/i/bart/fast"
|
97
|
+
last_response.should be_ok
|
98
|
+
response = last_response.should return_json
|
99
|
+
response['result'].should == 'success'
|
100
|
+
response['action'].should == 'delete'
|
101
|
+
response['id'].should == e.id
|
102
|
+
response['path'].should == e.name
|
103
|
+
end
|
104
|
+
|
105
|
+
it "invalid path should not work" do
|
106
|
+
delete '/e/fork/spoon/knife'
|
107
|
+
last_response.should_not be_ok
|
108
|
+
last_response.status.should == 404
|
109
|
+
response = last_response.should return_json
|
110
|
+
response['error_message'].should == 'Resource not found'
|
111
|
+
response['result'].should == 'failure'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/spec/noahapp_host_spec.rb
CHANGED
@@ -82,7 +82,7 @@ describe "Using the Host API", :reset_redis => false, :populate_sample_data => t
|
|
82
82
|
response = last_response.should return_json
|
83
83
|
|
84
84
|
response["result"].should == "failure"
|
85
|
-
response["error_message"].should == "
|
85
|
+
response["error_message"].should == "Status must be up, down or pending"
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -68,7 +68,7 @@ describe "Using the Service API", :reset_redis => false, :populate_sample_data =
|
|
68
68
|
put "/s/foobar", {:name => "foobar", :status => "fsck", :host => @h.name}.to_json, "CONTENT_TYPE" => "application/json"
|
69
69
|
last_response.should_not be_ok
|
70
70
|
response = last_response.should return_json
|
71
|
-
response["error_message"].should == "
|
71
|
+
response["error_message"].should == "Status must be up, down or pending"
|
72
72
|
end
|
73
73
|
it "new service with missing name should not work" do
|
74
74
|
put "/s/foobar", {:status => "fsck", :host => @h.name}.to_json, "CONTENT_TYPE" => "application/json"
|
@@ -28,7 +28,96 @@ describe "Using the Watcher API", :reset_redis => true do
|
|
28
28
|
response.is_a?(Array).should == true
|
29
29
|
response.size.should == 4
|
30
30
|
end
|
31
|
+
|
32
|
+
it "named watch should work" do
|
33
|
+
w = Noah::Watcher.create(:pattern => '//noah/application/myapp', :endpoint => 'http://localhost/webhook')
|
34
|
+
get "/w/#{w.name}"
|
35
|
+
last_response.should be_ok
|
36
|
+
response = last_response.should return_json
|
37
|
+
response['pattern'].should == w.pattern
|
38
|
+
response['endpoint'].should == w.endpoint
|
39
|
+
end
|
40
|
+
|
41
|
+
it "invalid watch should not work" do
|
42
|
+
get '/w/asdfasdfasdfasdfasdfsdf'
|
43
|
+
last_response.should be_missing
|
44
|
+
end
|
31
45
|
end
|
32
46
|
|
47
|
+
describe "PUT" do
|
48
|
+
it "new watch should work" do
|
49
|
+
data = {:pattern => "//noah/application", :endpoint => "http://myendpoint/webhook"}
|
50
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
51
|
+
last_response.should be_ok
|
52
|
+
response = last_response.should return_json
|
53
|
+
response['pattern'].should == data[:pattern]
|
54
|
+
response['endpoint'].should == data[:endpoint]
|
55
|
+
w = Noah::Watcher.find(data).first
|
56
|
+
w.pattern.should == data[:pattern]
|
57
|
+
w.endpoint.should == data[:endpoint]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "new watch without pattern should not work" do
|
61
|
+
data = {:endpoint => "http://myendpoint/webhook"}
|
62
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
63
|
+
last_response.should be_invalid
|
64
|
+
end
|
65
|
+
|
66
|
+
it "new watch without endpoint should not work" do
|
67
|
+
data = {:pattern => "//noah/application"}
|
68
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
69
|
+
last_response.should be_invalid
|
70
|
+
end
|
71
|
+
|
72
|
+
it "new watch that supercedes existing should not work" do
|
73
|
+
Noah::Watcher.create(:endpoint => 'http://myendpoint/webhook', :pattern => '//noah/application/foo')
|
74
|
+
data = {:endpoint => "http://myendpoint/webhook", :pattern => '//noah/application'}
|
75
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
76
|
+
last_response.should_not be_ok
|
77
|
+
response = last_response.should return_json
|
78
|
+
response['error_message'].should == 'Pattern would overwrite existing'
|
79
|
+
end
|
80
|
+
|
81
|
+
it "new watch that subsets an existing should not work" do
|
82
|
+
Noah::Watcher.create(:endpoint => 'http://myendpoint/webhook', :pattern => '//noah/application')
|
83
|
+
data = {:endpoint => "http://myendpoint/webhook", :pattern => '//noah/application/foo'}
|
84
|
+
put '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
85
|
+
last_response.should_not be_ok
|
86
|
+
response = last_response.should return_json
|
87
|
+
response['error_message'].should == 'Pattern is already provided'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "DELETE" do
|
92
|
+
it "delete an existing watch should work" do
|
93
|
+
data = {:endpoint => "http://myendpoint/webhookd", :pattern => '//noah/application/d'}
|
94
|
+
w = Noah::Watcher.create(data)
|
95
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
96
|
+
last_response.should be_ok
|
97
|
+
response = last_response.should return_json
|
98
|
+
response['pattern'].should == data[:pattern]
|
99
|
+
response['endpoint'].should == data[:endpoint]
|
100
|
+
response['name'].should_not == "null"
|
101
|
+
Noah::Watcher.find(data).size.should == 0
|
102
|
+
end
|
103
|
+
|
104
|
+
it "delete an invalid watch should not work" do
|
105
|
+
data = {:endpoint => 'missing', :pattern => '//noah/application/dag'}
|
106
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
107
|
+
last_response.should be_missing
|
108
|
+
end
|
109
|
+
|
110
|
+
it "delete without pattern should not work" do
|
111
|
+
data = {:endpoint => "invalid"}
|
112
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
113
|
+
last_response.should be_invalid
|
114
|
+
end
|
115
|
+
|
116
|
+
it "delete without endpoint should not work" do
|
117
|
+
data = {:pattern => "//noah/invalid"}
|
118
|
+
delete '/w', data.to_json, "CONTENT_TYPE" => "application/json"
|
119
|
+
last_response.should be_invalid
|
120
|
+
end
|
121
|
+
end
|
33
122
|
end
|
34
123
|
end
|
data/spec/watcher_spec.rb
CHANGED
@@ -32,30 +32,30 @@ describe "Using the Watcher Model", :reset_redis => true do
|
|
32
32
|
it "create a new Noah::Watcher with missing endpoint" do
|
33
33
|
a = Noah::Watcher.create(:pattern => "/foo/bar")
|
34
34
|
a.valid?.should == false
|
35
|
-
a.errors.
|
35
|
+
a.errors.should == [[:endpoint, :not_present]]
|
36
36
|
end
|
37
37
|
it "create a new Noah::Watcher with missing pattern" do
|
38
38
|
a = Noah::Watcher.create(:endpoint => "http://localhost/webhook")
|
39
39
|
a.valid?.should == false
|
40
|
-
a.errors.
|
40
|
+
a.errors.should == [[:pattern, :not_present]]
|
41
41
|
end
|
42
42
|
it "create a new Noah::Watcher with subset pattern" do
|
43
43
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/")
|
44
44
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
45
45
|
b.valid?.should == false
|
46
|
-
b.errors.
|
46
|
+
b.errors.should == [[:pattern, :already_provided]]
|
47
47
|
end
|
48
48
|
it "create a new Noah::Watcher with superset pattern" do
|
49
49
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
50
50
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah")
|
51
51
|
b.valid?.should == false
|
52
|
-
b.errors.
|
52
|
+
b.errors.should == [[:pattern, :replaces_existing]]
|
53
53
|
end
|
54
54
|
it "create a duplicate Noah::Watcher" do
|
55
55
|
a = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
56
56
|
b = Noah::Watcher.create(:endpoint => "http://localhost.domain.com/webhook", :pattern => "//noah/foobar")
|
57
57
|
b.valid?.should == false
|
58
|
-
b.errors.
|
58
|
+
b.errors.should == [[[:endpoint, :pattern], :not_unique]]
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: noah
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: "0.1"
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- John E. Vincent
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-11 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -265,7 +265,6 @@ files:
|
|
265
265
|
- lib/vendor/em-hiredis/Gemfile
|
266
266
|
- lib/vendor/em-hiredis/README.md
|
267
267
|
- lib/vendor/em-hiredis/Rakefile
|
268
|
-
- lib/vendor/em-hiredis/em-hiredis-0.0.1.gem
|
269
268
|
- lib/vendor/em-hiredis/em-hiredis.gemspec
|
270
269
|
- lib/vendor/em-hiredis/lib/em-hiredis.rb
|
271
270
|
- lib/vendor/em-hiredis/lib/em-hiredis/client.rb
|
@@ -279,6 +278,7 @@ files:
|
|
279
278
|
- spec/host_spec.rb
|
280
279
|
- spec/noahapp_application_spec.rb
|
281
280
|
- spec/noahapp_configuration_spec.rb
|
281
|
+
- spec/noahapp_ephemeral_spec.rb
|
282
282
|
- spec/noahapp_host_spec.rb
|
283
283
|
- spec/noahapp_service_spec.rb
|
284
284
|
- spec/noahapp_spec.rb
|
@@ -316,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
316
316
|
requirements: []
|
317
317
|
|
318
318
|
rubyforge_project: noah
|
319
|
-
rubygems_version: 1.5.
|
319
|
+
rubygems_version: 1.5.2
|
320
320
|
signing_key:
|
321
321
|
specification_version: 3
|
322
322
|
summary: Application registry based on Apache Zookeeper
|
Binary file
|