noah 0.0.5-jruby

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
1
+ class Configuration < Ohm::Model
2
+ include Ohm::Typecast
3
+ include Ohm::Timestamping
4
+ include Ohm::Callbacks
5
+ include Ohm::ExtraValidations
6
+
7
+ attribute :name
8
+ attribute :format
9
+ attribute :body
10
+ attribute :new_record
11
+ reference :application, Application
12
+
13
+ index :name
14
+
15
+ def validate
16
+ assert_present :name
17
+ assert_present :format
18
+ assert_present :body
19
+ assert_unique [:name, :application_id]
20
+ end
21
+
22
+ def to_hash
23
+ super.merge(:name => name, :format => format, :body => body, :update_at => updated_at, :application => Application[application_id].name)
24
+ end
25
+
26
+ def is_new?
27
+ self.created_at == self.updated_at
28
+ end
29
+
30
+ class << self
31
+ def find_or_create(opts={})
32
+ begin
33
+ if find(opts).first.nil?
34
+ conf = create(opts)
35
+ else
36
+ conf = find(opts).first
37
+ end
38
+ rescue Exception => e
39
+ e.message
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ class Configurations
46
+ def self.all(options = {})
47
+ options.empty? ? Configuration.all.sort : Configuration.find(options).sort
48
+ end
49
+ end
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), 'models')
2
+ module Noah
3
+ module SinatraHelpers
4
+ extend(Ohm)
5
+
6
+ def host(opts = {})
7
+ Host.find(opts).first
8
+ end
9
+
10
+ def hosts(opts = {})
11
+ Hosts.all(opts)
12
+ end
13
+
14
+ def service(opts = {})
15
+ Service.find(options)
16
+ end
17
+
18
+ def services(opts = {})
19
+ Services.all(opts)
20
+ end
21
+
22
+ def host_service(hostname, servicename)
23
+ h = Host.find(:name => hostname).first
24
+ if h.nil?
25
+ nil
26
+ else
27
+ Service.find(:host_id => h.id, :name => servicename).first
28
+ end
29
+ end
30
+
31
+ def host_services(hostname)
32
+ h = Host.find(:name => hostname).first
33
+ if h.nil?
34
+ nil
35
+ else
36
+ Services.all(:host_id => id)
37
+ end
38
+ end
39
+
40
+ def application(opts = {})
41
+ Application.find(opts).first
42
+ end
43
+
44
+ def applications(opts = {})
45
+ Applications.all(opts)
46
+ end
47
+
48
+ def configuration(opts = {})
49
+ Configuration.find(opts).first
50
+ end
51
+
52
+ def configurations(opts = {})
53
+ Configurations.all(opts)
54
+ end
55
+ end
56
+
57
+ end
data/lib/noah/hosts.rb ADDED
@@ -0,0 +1,54 @@
1
+ class Host < Ohm::Model
2
+ include Ohm::Typecast
3
+ include Ohm::Timestamping
4
+ include Ohm::Callbacks
5
+ include Ohm::ExtraValidations
6
+
7
+ attribute :name
8
+ attribute :status
9
+ collection :services, Service
10
+
11
+ index :name
12
+ index :status
13
+
14
+ def validate
15
+ assert_present :name
16
+ assert_present :status
17
+ assert_unique :name
18
+ assert_member :status, ["up","down","pending"]
19
+ end
20
+
21
+ def to_hash
22
+ arr = []
23
+ services.sort.each {|s| arr << s.to_hash}
24
+ h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => arr}
25
+ super.merge(h)
26
+ end
27
+
28
+ def is_new?
29
+ self.created_at == self.updated_at
30
+ end
31
+
32
+ class << self
33
+ def find_or_create(opts = {})
34
+ begin
35
+ # exclude requested status from lookup
36
+ h = find(opts.reject{|key,value| key == :status}).first
37
+ host = h.nil? ? create(opts) : h
38
+ host.status = opts[:status]
39
+ if host.valid?
40
+ host.save
41
+ end
42
+ host
43
+ rescue Exception => e
44
+ e.message
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ class Hosts
51
+ def self.all(options = {})
52
+ options.empty? ? Host.all.sort : Host.find(options).sort
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__),'hosts')
2
+ require File.join(File.dirname(__FILE__),'services')
3
+ require File.join(File.dirname(__FILE__),'applications')
4
+ require File.join(File.dirname(__FILE__),'configurations')
5
+ require File.join(File.dirname(__FILE__),'watchers')
@@ -0,0 +1,57 @@
1
+ class Service < Ohm::Model
2
+ include Ohm::Typecast
3
+ include Ohm::Timestamping
4
+ include Ohm::Callbacks
5
+ include Ohm::ExtraValidations
6
+
7
+ attribute :name
8
+ attribute :status
9
+ reference :host, Host
10
+
11
+ index :name
12
+ index :status
13
+
14
+ def validate
15
+ assert_present :name
16
+ assert_present :status
17
+ assert_present :host_id
18
+ assert_unique [:name, :host_id]
19
+ assert_member :status, ["up", "down", "pending"]
20
+ end
21
+
22
+ def to_hash
23
+ super.merge(:name => name, :status => status, :updated_at => updated_at, :host => Host[host_id].name)
24
+ end
25
+
26
+ def is_new?
27
+ self.created_at == self.updated_at
28
+ end
29
+
30
+ class << self
31
+ def find_or_create(opts = {})
32
+ begin
33
+ # convert passed host object to host_id if passed
34
+ if opts.has_key?(:host)
35
+ opts.merge!({:host_id => opts[:host].id})
36
+ opts.reject!{|key, value| key == :host}
37
+ end
38
+ # exclude requested status from lookup
39
+ s = find(opts.reject{|key,value| key == :status}).first
40
+ service = s.nil? ? create(opts) : s
41
+ service.status = opts[:status]
42
+ if service.valid?
43
+ service.save
44
+ end
45
+ service
46
+ rescue Exception => e
47
+ e.message
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ class Services
54
+ def self.all(options = {})
55
+ options.empty? ? Service.all.sort : Service.find(options).sort
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module Noah
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,18 @@
1
+ class Watcher < Ohm::Model #NYI
2
+ include Ohm::Typecast
3
+ include Ohm::Timestamping
4
+ include Ohm::Callbacks
5
+
6
+ attribute :client
7
+ attribute :endpoint
8
+ attribute :event
9
+ attribute :action
10
+
11
+ index :client
12
+ index :event
13
+
14
+ def validate
15
+ assert_present :client, :endpoint, :event, :action
16
+ assert_unique [:client, :endpoint, :event, :action]
17
+ end
18
+ end
data/lib/noah.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'ohm'
2
+ require 'ohm/contrib'
3
+ begin
4
+ require 'yajl'
5
+ rescue LoadError
6
+ require 'json'
7
+ end
8
+ require 'haml'
9
+ require 'yaml'
10
+ require 'sinatra/base'
11
+ require 'sinatra/namespace'
12
+
13
+ require File.join(File.dirname(__FILE__), 'noah','hosts')
14
+ require File.join(File.dirname(__FILE__), 'noah','services')
15
+ require File.join(File.dirname(__FILE__), 'noah','applications')
16
+ require File.join(File.dirname(__FILE__), 'noah','configurations')
17
+ require File.join(File.dirname(__FILE__), 'noah','watchers')
18
+ require File.join(File.dirname(__FILE__), 'noah','app')
data/noah.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "noah/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "noah"
7
+ s.version = Noah::VERSION
8
+ s.platform = RUBY_ENGINE
9
+ s.authors = ["lusis"]
10
+ s.email = ["lusis.org+rubygems.org@gmail.com"]
11
+ s.homepage = "https://github.com/lusis/noah"
12
+ s.summary = %q{Application registry based on Apache Zookeeper}
13
+ s.description = %q{Application registry based on Apache Zookeeper}
14
+
15
+ s.rubyforge_project = "noah"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency("rake", ["= 0.8.7"])
23
+ s.add_dependency("sinatra", ["= 1.1.2"])
24
+ s.add_dependency("sinatra-namespace", ["0.6.1"])
25
+ s.add_dependency("ohm", ["= 0.1.3"])
26
+ s.add_dependency("ohm-contrib", ["= 0.1.0"])
27
+ s.add_dependency("haml", ["= 3.0.25"])
28
+ s.add_dependency("vegas", ["= 0.1.8"])
29
+ s.add_dependency("yajl-ruby", ["= 0.7.9"]) if s.platform.to_s == 'ruby'
30
+ s.add_dependency("jruby-json", ["= 1.5.0"]) if s.platform.to_s == 'jruby'
31
+ s.add_dependency("thin", ["= 1.2.7"]) if s.platform.to_s == 'ruby'
32
+ s.add_dependency("json-jruby", ["= 1.4.6"]) if s.platform.to_s == 'jruby'
33
+ s.add_dependency("jruby-openssl", ["= 0.7.3"]) if s.platform.to_s == 'jruby'
34
+
35
+ s.add_development_dependency("sinatra-reloader", ["= 0.5.0"])
36
+ s.add_development_dependency("rspec", ["= 2.4.0"])
37
+ s.add_development_dependency("rcov", ["= 0.9.9"]) if s.platform.to_s == 'ruby'
38
+ s.add_development_dependency("rack-test", ["= 0.5.7"])
39
+ s.add_development_dependency("ZenTest", ["= 4.4.2"])
40
+ s.add_development_dependency("autotest", ["= 4.4.6"])
41
+ s.add_development_dependency("autotest-growl", ["= 0.2.9"])
42
+ s.add_development_dependency("warbler", ["= 1.2.1"]) if s.platform.to_s == 'java'
43
+
44
+ end
@@ -0,0 +1,83 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Using the Application Model", :reset_redis => true do
4
+ before(:all) do
5
+ @appdata1 = {:name => "my_application"}
6
+ @appdata2 = {:name => "my_other_app"}
7
+ @appconf_string = {:name => "mystringconf", :format => "string", :body => "some_var"}
8
+ @appconf_json = {:name => "myjsonconf", :format => "json", :body => @appconf_string.to_json}
9
+ end
10
+ before(:each) do
11
+ Ohm.redis.flushdb
12
+ end
13
+ after(:each) do
14
+ Ohm.redis.flushdb
15
+ end
16
+ describe "should" do
17
+ it "create a new Application" do
18
+ a = Application.create(@appdata1)
19
+ a.valid?.should == true
20
+ a.is_new?.should == true
21
+ b = Application.find(@appdata1).first
22
+ b.should == a
23
+ end
24
+ it "create a new Application with Configurations" do
25
+ a = Application.create(@appdata1)
26
+ a.configurations << Configuration.create(@appconf_string.merge({:application => a}))
27
+ a.valid?.should == true
28
+ a.is_new?.should == true
29
+ a.save
30
+ b = Application.find(@appdata1).first
31
+ b.should == a
32
+ b.configurations.size.should == 1
33
+ b.configurations.first.name.should == @appconf_string[:name]
34
+ b.configurations.first.format.should == @appconf_string[:format]
35
+ b.configurations.first.body.should == @appconf_string[:body]
36
+ end
37
+ it "create a new Application via find_or_create" do
38
+ a = Application.find_or_create(@appdata2)
39
+ a.valid?.should == true
40
+ a.is_new?.should == true
41
+ b = Application.find(@appdata2).first
42
+ b.should == a
43
+ end
44
+ it "update an existing Application via find_or_create" do
45
+ a = Application.create(@appdata1)
46
+ a.is_new?.should == true
47
+ sleep 2
48
+ b = Application.find_or_create(@appdata1)
49
+ b.is_new?.should == false
50
+ end
51
+ it "delete an existing Application" do
52
+ a = Application.create(@appdata1)
53
+ b = Application.find(@appdata1).first
54
+ b.should == a
55
+ b.delete
56
+ c = Application.find(@appdata1).first
57
+ c.nil?.should == true
58
+ end
59
+ it "return all Applications" do
60
+ a = Application.create(@appdata1)
61
+ b = Application.create(@appdata2)
62
+ c = Applications.all
63
+ c.size.should == 2
64
+ c.member?(a).should == true
65
+ c.member?(b).should == true
66
+ end
67
+ end
68
+
69
+ describe "should not" do
70
+ it "should not create a new Application without a name" do
71
+ a = Application.create
72
+ a.valid?.should == false
73
+ a.errors.should == [[:name, :not_present]]
74
+ end
75
+ it "should not create a duplicate Application" do
76
+ a = Application.create(@appdata1)
77
+ a.valid?.should == true
78
+ b = Application.create(@appdata1)
79
+ b.valid?.should == false
80
+ b.errors.should == [[:name, :not_unique]]
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Using the Configuration Model", :reset_redis => true do
4
+
5
+ describe "should" do
6
+
7
+ it "create a new Configuration"
8
+ it "create a new Configuration via find_or_create"
9
+ it "update an existing Configuration via find_or_create"
10
+ it "delete an existing Configuration"
11
+ it "return all Configurations"
12
+
13
+ end
14
+
15
+ describe "should not" do
16
+
17
+ it "create a new Configuration without a name"
18
+ it "create a new Configuration without a format"
19
+ it "create a new Configuration without a body"
20
+ it "create a new Configuration without an Application"
21
+ it "create a duplicate Configuration"
22
+
23
+ end
24
+
25
+ end
data/spec/host_spec.rb ADDED
@@ -0,0 +1,119 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Using the Host Model", :reset_redis => true do
4
+
5
+ describe "should" do
6
+ it "create a new Host with no services" do
7
+ hostname = "host1.domain.com"
8
+ hoststatus = "up"
9
+ host = Host.create(:name => hostname, :status => hoststatus)
10
+ host.valid?.should == true
11
+ host.save
12
+ host.name.should == hostname
13
+ host.status.should == hoststatus
14
+ host.services.size.should == 0
15
+ end
16
+
17
+ it "create a new Host with services" do
18
+ hostname = "host2.domain.com"
19
+ hoststatus = "down"
20
+ servicename = 'myservice'
21
+ servicestatus = 'pending'
22
+ host = Host.create(:name => hostname, :status => hoststatus)
23
+ host.valid?.should == true
24
+ host.save
25
+ host.services << Service.create(:name => servicename, :status => servicestatus, :host => host)
26
+ host.name.should == hostname
27
+ host.status.should == hoststatus
28
+ host.services.size.should == 1
29
+ host.services[1].valid?.should == true
30
+ host.services[1].name.should == servicename
31
+ host.services[1].status.should == servicestatus
32
+ host.services[1].host_id.should == host.id
33
+ end
34
+
35
+ it "create a Host via find_or_create" do
36
+ hostname = "host3.domain.com"
37
+ hoststatus = "up"
38
+ host = Host.find_or_create(:name => hostname, :status => hoststatus)
39
+ host.valid?.should == true
40
+ host.save
41
+ host.is_new?.should == true
42
+ end
43
+
44
+ it "update a Host via find_or_create" do
45
+ hostname = "host3.domain.com"
46
+ hoststatus = "pending"
47
+ newstatus = "down"
48
+ host = Host.find_or_create(:name => hostname, :status => hoststatus)
49
+ host.valid?.should == true
50
+ host.save
51
+ host.is_new?.should == true
52
+ sleep 1
53
+ host1 = Host.find_or_create(:name => hostname, :status => newstatus)
54
+ host1.save
55
+ host1.is_new?.should == false
56
+ end
57
+
58
+ it "delete a Host" do
59
+ hostname = "host3.domain.com"
60
+ hoststatus = "pending"
61
+ host = Host.create(:name => hostname, :status => hoststatus)
62
+ host.save
63
+ host.delete
64
+ Host.find(:name => hostname).empty?.should == true
65
+ end
66
+
67
+ it "should return all Hosts" do
68
+ hostname1 = "host1.domain.com"
69
+ status1 = "up"
70
+ hostname2 = "host2.domain.com"
71
+ status2= "down"
72
+ host1 = Host.create(:name => hostname1, :status => status1)
73
+ host2 = Host.create(:name => hostname2, :status => status2)
74
+ host1.save
75
+ host2.save
76
+ Hosts.all.class.should == Array
77
+ Hosts.all.size.should == 2
78
+ Hosts.all.first.name.should == hostname1
79
+ Hosts.all.first.status.should == status1
80
+ Hosts.all.last.name.should == hostname2
81
+ Hosts.all.last.status.should == status2
82
+ end
83
+ end
84
+
85
+ describe "should not" do
86
+ it "create a new Host with missing status" do
87
+ hostname ="host3.domain.com"
88
+ host = Host.create(:name => hostname)
89
+ host.valid?.should == false
90
+ host.errors.should == [[:status, :not_present], [:status, :not_member]]
91
+ end
92
+
93
+ it "create a new Host with missing hostname" do
94
+ status = "up"
95
+ host = Host.create(:status => status)
96
+ host.valid?.should == false
97
+ host.errors.should == [[:name, :not_present]]
98
+ end
99
+
100
+ it "create a new Host with an invalid status" do
101
+ hostname = "host3.domain.com"
102
+ status = "online"
103
+ host = Host.create(:name => hostname, :status => status)
104
+ host.valid?.should == false
105
+ host.errors.should == [[:status, :not_member]]
106
+ end
107
+
108
+ it "create a duplicate Host" do
109
+ hostname = "host1.domain.com"
110
+ status = "up"
111
+ host1 = Host.create(:name => hostname, :status => status)
112
+ host1.save
113
+ host2 = Host.create(:name => hostname, :status => status)
114
+ host2.valid?.should == false
115
+ host2.errors.should == [[:name, :not_unique]]
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,108 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Using the Application API", :reset_redis => false do
4
+ before(:all) do
5
+ @a = Application.create(:name => 'rspec_sample_app')
6
+ @a.configurations << Configuration.create(:name => 'rspec_config', :format => 'string', :body => 'rspec is great', :application => @a)
7
+ @a.save
8
+ @c = @a.configurations.first
9
+ end
10
+ describe "calling" do
11
+
12
+ describe "GET" do
13
+ it "all applications should work" do
14
+ get '/a'
15
+ last_response.should be_ok
16
+ response = last_response.should return_json
17
+ response.is_a?(Array).should == true
18
+ end
19
+ it "named application should work" do
20
+ get '/a/rspec_sample_app'
21
+ last_response.should be_ok
22
+ response = last_response.should return_json
23
+
24
+ response["id"].should == @a.id
25
+ response["name"].should == @a.name
26
+ c = response["configurations"].first
27
+ c["id"].should == @c.id
28
+ c["name"].should == @c.name
29
+ c["body"].should == @c.body
30
+ c["format"].should == @c.format
31
+ end
32
+ it "named configuration for application should work" do
33
+ get "/a/#{@a.name}/#{@c.name}"
34
+ last_response.should be_ok
35
+ response = last_response.should return_json
36
+
37
+ response["id"].should == @c.id
38
+ response["name"].should == @c.name
39
+ response["format"].should == @c.format
40
+ response["body"].should == @c.body
41
+ response["application"].should == @a.name
42
+ end
43
+ it "invalid application should not work" do
44
+ get "/a/should_not_exist"
45
+ last_response.should be_missing
46
+ end
47
+ it "invalid configuration for application should not work" do
48
+ get "/a/should_not_exist/should_not_exist"
49
+ last_response.should be_missing
50
+ end
51
+ end
52
+
53
+ describe "PUT" do
54
+ before(:all) do
55
+ @appdata = {:name => "should_now_exist"}
56
+ end
57
+ it "new application should work" do
58
+ put "/a/#{@appdata[:name]}", @appdata.to_json, "CONTENT_TYPE" => "application/json"
59
+ last_response.should be_ok
60
+ response = last_response.should return_json
61
+ response["result"].should == "success"
62
+ response["id"].nil?.should == false
63
+ response["name"].should == @appdata[:name]
64
+ response["action"].should == "create"
65
+ Application.find(:name => @appdata[:name]).size.should == 1
66
+ Application.find(:name => @appdata[:name]).first.is_new?.should == true
67
+ end
68
+ it "new application with missing name should not work" do
69
+ put "/a/should_not_work", '{"foo":"bar"}', "CONTENT_TYPE" => "application/json"
70
+ last_response.should be_invalid
71
+ end
72
+ it "existing application should work" do
73
+ sleep 3
74
+
75
+ put "/a/#{@appdata[:name]}", @appdata.to_json, "CONTENT_TYPE" => "application/json"
76
+ last_response.should be_ok
77
+ response = last_response.should return_json
78
+ response["result"].should == "success"
79
+ response["id"].nil?.should == false
80
+ response["name"].should == @appdata[:name]
81
+ response["action"].should == "update"
82
+ Application.find(:name => @appdata[:name]).size.should == 1
83
+ Application.find(:name => @appdata[:name]).first.is_new?.should == false
84
+ end
85
+ end
86
+
87
+ describe "DELETE" do
88
+ before(:each) do
89
+ @appdata = {:name => "should_now_exist"}
90
+ end
91
+ it "existing application should work" do
92
+ delete "/a/#{@appdata[:name]}"
93
+ last_response.should be_ok
94
+ response = last_response.should return_json
95
+ response["result"].should == "success"
96
+ response["action"].should == "delete"
97
+ response["id"].nil?.should == false
98
+ response["name"].should == @appdata[:name]
99
+ response["configurations"].should == "0"
100
+ end
101
+ it "invalid application should not work" do
102
+ delete "/a/should_not_work"
103
+ last_response.should be_missing
104
+ end
105
+ end
106
+
107
+ end
108
+ end