noah 0.2.1-jruby → 0.3-jruby
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/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
|