noah 0.2.1-jruby → 0.3-jruby
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +10 -4
- data/bin/noah-watcher.rb +11 -8
- data/lib/noah.rb +8 -1
- data/lib/noah/agent.rb +30 -5
- data/lib/noah/agents/base_agent.rb +30 -6
- data/lib/noah/agents/dummy_agent.rb +6 -13
- data/lib/noah/agents/http_agent.rb +13 -20
- data/lib/noah/application_routes.rb +6 -6
- data/lib/noah/configuration_routes.rb +6 -6
- data/lib/noah/helpers.rb +1 -0
- data/lib/noah/host_routes.rb +6 -6
- data/lib/noah/log.rb +6 -0
- data/lib/noah/models.rb +50 -2
- data/lib/noah/models/ephemerals.rb +2 -0
- data/lib/noah/models/link.rb +45 -0
- data/lib/noah/models/link_member.rb +18 -0
- data/lib/noah/models/tags.rb +14 -0
- data/lib/noah/models/watchers.rb +1 -3
- data/lib/noah/service_routes.rb +6 -6
- data/lib/noah/validations.rb +1 -0
- data/lib/noah/validations/ephemeral_validations.rb +20 -0
- data/lib/noah/version.rb +1 -1
- data/lib/noah/watcher_routes.rb +4 -4
- data/noah.gemspec +1 -1
- data/spec/ephemeral_spec.rb +13 -0
- data/spec/noahapp_application_spec.rb +10 -10
- data/spec/noahapp_configuration_spec.rb +12 -12
- data/spec/noahapp_ephemeral_spec.rb +15 -0
- data/spec/noahapp_host_spec.rb +10 -10
- data/spec/noahapp_service_spec.rb +12 -12
- data/spec/noahapp_watcher_spec.rb +20 -20
- data/spec/spec_helper.rb +5 -0
- data/views/index.haml +15 -15
- metadata +306 -316
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'link_member')
|
2
|
+
module Noah
|
3
|
+
class Link < Model
|
4
|
+
attribute :path
|
5
|
+
list :nodes, LinkMember
|
6
|
+
|
7
|
+
index :path
|
8
|
+
|
9
|
+
def validate
|
10
|
+
super
|
11
|
+
assert_present :path
|
12
|
+
end
|
13
|
+
# Nothing to see yet.
|
14
|
+
# This will be for creating "overlays" or "link" relationships
|
15
|
+
# between arbitrary objects or modeling your data the way you want.
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# path = "/myservers"
|
19
|
+
# path.nodes = ["/applications/myapp","/some/ephemeral/path", "sometag"]
|
20
|
+
#
|
21
|
+
# would result in a structure like:
|
22
|
+
# path/
|
23
|
+
# applications/
|
24
|
+
# myapp
|
25
|
+
# some/ephemeral/path/
|
26
|
+
# child1
|
27
|
+
# child2
|
28
|
+
# child3
|
29
|
+
# sometag/
|
30
|
+
# tagged_item1
|
31
|
+
# tagged_item2
|
32
|
+
# tagged_item4
|
33
|
+
# tagged_item5
|
34
|
+
#
|
35
|
+
# The idea is to create a blended view across opinionated, tagged and
|
36
|
+
# ephemeral nodes.
|
37
|
+
#
|
38
|
+
# Almost a "choose your own model" thing.
|
39
|
+
|
40
|
+
def name
|
41
|
+
@name = path
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Noah
|
2
|
+
class LinkMember
|
3
|
+
|
4
|
+
class <<self
|
5
|
+
def create(path)
|
6
|
+
path_to_instance(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
def path_to_instance(path)
|
11
|
+
p = path.split('/')
|
12
|
+
model, name = p[1], p[2]
|
13
|
+
x = instance_eval(Noah::PATH_MAPPING[model])
|
14
|
+
x.find(:name => name).first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/noah/models/watchers.rb
CHANGED
data/lib/noah/service_routes.rb
CHANGED
@@ -2,7 +2,7 @@ class Noah::App
|
|
2
2
|
# Service URIs
|
3
3
|
|
4
4
|
# get named {Service} for named {Host}
|
5
|
-
get '/
|
5
|
+
get '/services/:servicename/:hostname/?' do |servicename, hostname|
|
6
6
|
hs = host_service(hostname, servicename)
|
7
7
|
if hs.nil?
|
8
8
|
halt 404
|
@@ -11,7 +11,7 @@ class Noah::App
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
get '/
|
14
|
+
get '/services/:servicename/?' do |servicename|
|
15
15
|
s = services(:name => servicename)
|
16
16
|
s.map {|x| x.to_hash}
|
17
17
|
if s.empty?
|
@@ -21,7 +21,7 @@ class Noah::App
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
get '/
|
24
|
+
get '/services/?' do
|
25
25
|
if services.empty?
|
26
26
|
halt 404
|
27
27
|
else
|
@@ -30,7 +30,7 @@ class Noah::App
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
put '/
|
33
|
+
put '/services/:servicename/watch' do |servicename|
|
34
34
|
required_params = ["endpoint"]
|
35
35
|
data = JSON.parse(request.body.read)
|
36
36
|
(data.keys.sort == required_params.sort) ? (s = Noah::Service.find(:name => servicename).first) : (raise "Missing Parameters")
|
@@ -38,7 +38,7 @@ class Noah::App
|
|
38
38
|
w.to_json
|
39
39
|
end
|
40
40
|
|
41
|
-
put '/
|
41
|
+
put '/services/:servicename/?' do |servicename|
|
42
42
|
required_params = ["status", "host", "name"]
|
43
43
|
data = JSON.parse(request.body.read)
|
44
44
|
if data.keys.sort == required_params.sort
|
@@ -57,7 +57,7 @@ class Noah::App
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
delete '/
|
60
|
+
delete '/services/:servicename/:hostname/?' do |servicename, hostname|
|
61
61
|
host = Noah::Host.find(:name => hostname).first || (halt 404)
|
62
62
|
service = Noah::Service.find(:name => servicename, :host_id => host.id).first || (halt 404)
|
63
63
|
if host && service
|
data/lib/noah/validations.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Noah
|
2
|
+
module EphemeralValidations
|
3
|
+
|
4
|
+
def assert_not_reserved(error = [:path, :reserved_path])
|
5
|
+
# This is to work around how Ohm evaluates validations
|
6
|
+
# Allows assert_present :path to override
|
7
|
+
return if self.path.nil?
|
8
|
+
# This is the real test
|
9
|
+
self.instance_of?(Noah::Ephemeral) ? (assert valid_path?, error) : (assert false, "Validation not applicable")
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def valid_path?
|
14
|
+
PROTECTED_PATHS.member?(self.path.split("/")[1]) ? (return false) : (return true)
|
15
|
+
rescue ArgumentError
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/noah/version.rb
CHANGED
data/lib/noah/watcher_routes.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
class Noah::App
|
2
2
|
|
3
|
-
get '/
|
3
|
+
get '/watches/:name' do |name|
|
4
4
|
w = Noah::Watcher.find_by_name(name)
|
5
5
|
w.nil? ? (halt 404) : w.to_json
|
6
6
|
end
|
7
7
|
|
8
|
-
get '/
|
8
|
+
get '/watches/?' do
|
9
9
|
w = Noah::Watcher.all.sort_by(:pattern)
|
10
10
|
if w.size == 0
|
11
11
|
halt 404
|
@@ -14,7 +14,7 @@ class Noah::App
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
put '/
|
17
|
+
put '/watches/?' do
|
18
18
|
required_params = %w[endpoint pattern]
|
19
19
|
data = JSON.parse(request.body.read)
|
20
20
|
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
@@ -28,7 +28,7 @@ class Noah::App
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
delete '/
|
31
|
+
delete '/watches/?' do
|
32
32
|
required_params = %w[endpoint pattern]
|
33
33
|
data = JSON.parse(request.body.read)
|
34
34
|
(data.keys.sort == required_params.sort) ? (pattern, endpoint = data['pattern'],data['endpoint']) : (raise "Missing Parameters")
|
data/noah.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_dependency("nest", ["= 1.1.0"])
|
27
27
|
s.add_dependency("rack", ["= 1.2.1"])
|
28
28
|
s.add_dependency("tilt", ["= 1.2.2"])
|
29
|
-
s.add_dependency("sinatra", ["= 1.
|
29
|
+
s.add_dependency("sinatra", ["= 1.2.0"])
|
30
30
|
s.add_dependency("ohm", ["= 0.1.3"])
|
31
31
|
s.add_dependency("ohm-contrib", ["= 0.1.1"])
|
32
32
|
s.add_dependency("haml", ["= 3.0.25"])
|
data/spec/ephemeral_spec.rb
CHANGED
@@ -42,6 +42,12 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
42
42
|
@good_ephemeral.delete
|
43
43
|
Noah::Ephemeral[@good_ephemeral.id].should == nil
|
44
44
|
end
|
45
|
+
it "should allow reserved keywords as subpaths" do
|
46
|
+
Noah::PROTECTED_PATHS.each do |path|
|
47
|
+
e = Noah::Ephemeral.new :path => "/this/should/be/#{path}"
|
48
|
+
e.valid?.should == true
|
49
|
+
end
|
50
|
+
end
|
45
51
|
end
|
46
52
|
describe "should not" do
|
47
53
|
it "create a new Noah::Ephemeral with missing path" do
|
@@ -55,5 +61,12 @@ describe "Using the Ephemeral Model", :reset_redis => true do
|
|
55
61
|
f.valid?.should == false
|
56
62
|
f.errors.should == [[:path, :not_unique]]
|
57
63
|
end
|
64
|
+
it "allow a reserved keyword as a path" do
|
65
|
+
Noah::PROTECTED_PATHS.each do |path|
|
66
|
+
e = Noah::Ephemeral.new :path => "/#{path}"
|
67
|
+
e.valid?.should == false
|
68
|
+
e.errors.should == [[:path, :reserved_path]]
|
69
|
+
end
|
70
|
+
end
|
58
71
|
end
|
59
72
|
end
|
@@ -11,13 +11,13 @@ describe "Using the Application API", :reset_redis => false do
|
|
11
11
|
|
12
12
|
describe "GET" do
|
13
13
|
it "all applications should work" do
|
14
|
-
get '/
|
14
|
+
get '/applications'
|
15
15
|
last_response.should be_ok
|
16
16
|
response = last_response.should return_json
|
17
17
|
response.is_a?(Array).should == true
|
18
18
|
end
|
19
19
|
it "named application should work" do
|
20
|
-
get '/
|
20
|
+
get '/applications/rspec_sample_app'
|
21
21
|
last_response.should be_ok
|
22
22
|
response = last_response.should return_json
|
23
23
|
|
@@ -30,7 +30,7 @@ describe "Using the Application API", :reset_redis => false do
|
|
30
30
|
c["format"].should == @c.format
|
31
31
|
end
|
32
32
|
it "named configuration for application should work" do
|
33
|
-
get "/
|
33
|
+
get "/applications/#{@a.name}/#{@c.name}"
|
34
34
|
last_response.should be_ok
|
35
35
|
response = last_response.should return_json
|
36
36
|
|
@@ -41,11 +41,11 @@ describe "Using the Application API", :reset_redis => false do
|
|
41
41
|
response["application"].should == @a.name
|
42
42
|
end
|
43
43
|
it "invalid application should not work" do
|
44
|
-
get "/
|
44
|
+
get "/applications/should_not_exist"
|
45
45
|
last_response.should be_missing
|
46
46
|
end
|
47
47
|
it "invalid configuration for application should not work" do
|
48
|
-
get "/
|
48
|
+
get "/applications/should_not_exist/should_not_exist"
|
49
49
|
last_response.should be_missing
|
50
50
|
end
|
51
51
|
end
|
@@ -55,7 +55,7 @@ describe "Using the Application API", :reset_redis => false do
|
|
55
55
|
@appdata = {:name => "should_now_exist"}
|
56
56
|
end
|
57
57
|
it "new application should work" do
|
58
|
-
put "/
|
58
|
+
put "/applications/#{@appdata[:name]}", @appdata.to_json, "CONTENT_TYPE" => "application/json"
|
59
59
|
last_response.should be_ok
|
60
60
|
response = last_response.should return_json
|
61
61
|
response["result"].should == "success"
|
@@ -66,13 +66,13 @@ describe "Using the Application API", :reset_redis => false do
|
|
66
66
|
Noah::Application.find(:name => @appdata[:name]).first.is_new?.should == true
|
67
67
|
end
|
68
68
|
it "new application with missing name should not work" do
|
69
|
-
put "/
|
69
|
+
put "/applications/should_not_work", '{"foo":"bar"}', "CONTENT_TYPE" => "application/json"
|
70
70
|
last_response.should be_invalid
|
71
71
|
end
|
72
72
|
it "existing application should work" do
|
73
73
|
sleep 3
|
74
74
|
|
75
|
-
put "/
|
75
|
+
put "/applications/#{@appdata[:name]}", @appdata.to_json, "CONTENT_TYPE" => "application/json"
|
76
76
|
last_response.should be_ok
|
77
77
|
response = last_response.should return_json
|
78
78
|
response["result"].should == "success"
|
@@ -89,7 +89,7 @@ describe "Using the Application API", :reset_redis => false do
|
|
89
89
|
@appdata = {:name => "should_now_exist"}
|
90
90
|
end
|
91
91
|
it "existing application should work" do
|
92
|
-
delete "/
|
92
|
+
delete "/applications/#{@appdata[:name]}"
|
93
93
|
last_response.should be_ok
|
94
94
|
response = last_response.should return_json
|
95
95
|
response["result"].should == "success"
|
@@ -99,7 +99,7 @@ describe "Using the Application API", :reset_redis => false do
|
|
99
99
|
response["configurations"].should == "0"
|
100
100
|
end
|
101
101
|
it "invalid application should not work" do
|
102
|
-
delete "/
|
102
|
+
delete "/applications/should_not_work"
|
103
103
|
last_response.should be_missing
|
104
104
|
end
|
105
105
|
end
|
@@ -5,12 +5,12 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
5
5
|
|
6
6
|
describe "GET" do
|
7
7
|
it "all configurations should work" do
|
8
|
-
get '/
|
8
|
+
get '/configurations'
|
9
9
|
last_response.should be_ok
|
10
10
|
last_response.should return_json
|
11
11
|
end
|
12
12
|
it "named application should work" do
|
13
|
-
get '/
|
13
|
+
get '/configurations/noah'
|
14
14
|
last_response.should be_ok
|
15
15
|
response = last_response.should return_json
|
16
16
|
|
@@ -21,14 +21,14 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
21
21
|
response.first["application"].should == "noah"
|
22
22
|
end
|
23
23
|
it "named configuration for application should work" do
|
24
|
-
get '/
|
24
|
+
get '/configurations/noah/redis'
|
25
25
|
last_response.should be_ok
|
26
26
|
response = last_response.body
|
27
27
|
response.should == "redis://127.0.0.1:6379/0"
|
28
28
|
end
|
29
29
|
it "named configuration should work with mime-type" do
|
30
30
|
require 'yaml'
|
31
|
-
get '/
|
31
|
+
get '/configurations/myrailsapp1/database.yml'
|
32
32
|
last_response.should be_ok
|
33
33
|
last_response.headers["Content-Type"].should == "text/x-yaml;charset=utf-8"
|
34
34
|
response = YAML.load(last_response.body)
|
@@ -38,11 +38,11 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
38
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
|
-
get '/
|
41
|
+
get '/configurations/badapp'
|
42
42
|
last_response.should be_missing
|
43
43
|
end
|
44
44
|
it "invalid configuration for application should not work" do
|
45
|
-
get '/
|
45
|
+
get '/configurations/badapp/badconfig'
|
46
46
|
last_response.should be_missing
|
47
47
|
end
|
48
48
|
end
|
@@ -50,7 +50,7 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
50
50
|
describe "PUT" do
|
51
51
|
it "new configuration should work" do
|
52
52
|
config_data = {:format => "string", :body => "sample_config_entry"}.to_json
|
53
|
-
put '/
|
53
|
+
put '/configurations/newapp/newconfig', config_data, "CONTENT_TYPE" => "application/json"
|
54
54
|
last_response.should be_ok
|
55
55
|
response = last_response.should return_json
|
56
56
|
response["result"].should == "success"
|
@@ -62,7 +62,7 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
62
62
|
it "existing configuration should work" do
|
63
63
|
config_data = {:format => "string", :body => "sample_config_entry"}.to_json
|
64
64
|
sleep 3
|
65
|
-
put '/
|
65
|
+
put '/configurations/newapp/newconfig', config_data, "CONTENT_TYPE" => "application/json"
|
66
66
|
last_response.should be_ok
|
67
67
|
response = last_response.should return_json
|
68
68
|
response["result"].should == "success"
|
@@ -73,12 +73,12 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
73
73
|
end
|
74
74
|
it "new configuration with missing format should not work" do
|
75
75
|
config_data = {:body => "a string"}.to_json
|
76
|
-
put '/
|
76
|
+
put '/configurations/newnewapp/someconfig', config_data, "CONTENT_TYPE" => "application/json"
|
77
77
|
last_response.should be_invalid
|
78
78
|
end
|
79
79
|
it "new configuration with missing body should not work" do
|
80
80
|
config_data = {:body => "a string"}.to_json
|
81
|
-
put '/
|
81
|
+
put '/configurations/newnewapp/someconfig', config_data, "CONTENT_TYPE" => "application/json"
|
82
82
|
last_response.should be_invalid
|
83
83
|
end
|
84
84
|
end
|
@@ -93,7 +93,7 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
93
93
|
end
|
94
94
|
|
95
95
|
it "existing configuration should work" do
|
96
|
-
delete "/
|
96
|
+
delete "/configurations/#{@a.name}/#{@c.name}"
|
97
97
|
last_response.should be_ok
|
98
98
|
response = last_response.should return_json
|
99
99
|
response["result"].should == "success"
|
@@ -103,7 +103,7 @@ describe "Using the Configuration API", :reset_redis => false, :populate_sample_
|
|
103
103
|
response["item"].should == @c.name
|
104
104
|
end
|
105
105
|
it "invalid configuration should not work" do
|
106
|
-
delete "/
|
106
|
+
delete "/configurations/#{@a.name}/#{@c.name}"
|
107
107
|
last_response.should be_missing
|
108
108
|
end
|
109
109
|
end
|
@@ -87,6 +87,21 @@ describe "Using the Ephemeral API", :reset_redis => true do
|
|
87
87
|
last_response.should be_ok
|
88
88
|
last_response.body.should == 'a new value'
|
89
89
|
end
|
90
|
+
it "ephemeral with reserved word in subpath should work" do
|
91
|
+
Noah::PROTECTED_PATHS.each do |path|
|
92
|
+
put "/e/a/valid/path/with/#{path}"
|
93
|
+
last_response.should be_ok
|
94
|
+
end
|
95
|
+
end
|
96
|
+
it "ephemeral with reserved word as path should not work" do
|
97
|
+
Noah::PROTECTED_PATHS.each do |path|
|
98
|
+
put "/e/#{path}/other/stuff"
|
99
|
+
last_response.should_not be_ok
|
100
|
+
response = last_response.should return_json
|
101
|
+
response['error_message'].should == 'Path is reserved'
|
102
|
+
response['result'].should == 'failure'
|
103
|
+
end
|
104
|
+
end
|
90
105
|
end
|
91
106
|
|
92
107
|
describe "DELETE" do
|