noah 0.0.5-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.
@@ -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