noah 0.8.5-jruby → 0.8.7-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/.gitignore CHANGED
@@ -16,3 +16,4 @@ doc
16
16
  examples/log/*
17
17
  examples/tmp/*
18
18
  *.rbc
19
+ *.gem
@@ -0,0 +1,20 @@
1
+ # Noah Changelog
2
+
3
+ ## 0.8.6
4
+ - Issue #7 *Provide url for key-only enumeration*
5
+
6
+ - top-level configurations url now accepts `?short=true` to return shortened display of entries
7
+
8
+ - Issue #10 *noah-watcher daemon doesn't support REDIS_URL env*
9
+
10
+ - **BREAKING CHANGE** noah-watcher.rb renamed to noah-watcher
11
+ - noah-watcher now supports `-r redis://host:port/dbnum` to use alternate redis server
12
+ - noah-watcher now supports `-l logfile` for logging to file
13
+
14
+ ## 0.8.5
15
+ - Issue #9 *Ephemeral Tagging is broken*
16
+
17
+ - All tagging now moved from route files to Sinatra helper
18
+
19
+ # Historical
20
+ This changelog started being maintained at 0.8.5. Previous changes can be viewed in the commit history.
data/README.md CHANGED
@@ -1,13 +1,43 @@
1
1
  # Noah
2
2
  _"look at this effing rainbow I just made for you"_
3
3
 
4
- Noah is an application registry loosely based on [Apache ZooKeeper](http://zookeeper.apache.org)
4
+ Noah is an application registry inspired by [Apache ZooKeeper](http://zookeeper.apache.org)
5
5
 
6
6
  What does that mean? From the ZooKeeper Home Page:
7
7
 
8
8
  > ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications.
9
9
 
10
- Essentially Noah, is a port of those concepts into a stateless RESTful application.
10
+ Essentially Noah is a port of parts of that functionality into a stateless RESTish application.
11
+
12
+ ## Some background
13
+ It's probably worth reading the following blog posts before going any further to clear up any possible misunderstandings.
14
+ Noah is not a direct replacement for ZK. It's a conceptual port. More than anything, it was an itch I needed to scratch:
15
+
16
+ - [On Noah - Part 1](http://blog.lusis.org/blog/2011/05/16/on-noah-part-1/)
17
+ - [On Noah - Part 2](http://blog.lusis.org/blog/2011/05/17/on-noah-part-2/)
18
+ - [On Noah - Part 3](http://blog.lusis.org/blog/2011/05/18/on-noah-part-3/)
19
+ - [On Noah - Part 4](http://blog.lusis.org/blog/2011/05/20/on-noah-part-4/)
20
+
21
+ Also the following post was where I sort of discussed it early on:
22
+
23
+ - [Ad-hoc configuration and Coordination](http://lusislog.blogspot.com/2011/03/ad-hoc-configuration-coordination-and.html)
24
+
25
+ ## Things Noah does not do
26
+
27
+ - Paxos, ZAB or any other sort of consensus protocol
28
+ - Noah itself is not distributed (yet).
29
+ - ACLs (yet)
30
+ - Leader election of any kind
31
+
32
+ ## Things Noah can do
33
+ _note that these terms are fairly overloaded depending on who you talk to_
34
+
35
+ - Service registry
36
+ - Node registry
37
+ - Configuration Registry
38
+ - Group Services
39
+ - Watches (albeit differently)
40
+
11
41
 
12
42
  ## Quick Start
13
43
  The quickstart guide has been moved to the wiki:
@@ -68,4 +98,4 @@ Here are a list of some key [wiki](https://github.com/lusis/Noah/wiki) pages:
68
98
  * [Watchers and Callbacks](https://github.com/lusis/Noah/wiki/Watchers-and-Callbacks)
69
99
  The general idea behind how Noah would implement watches
70
100
  * [Watcher/Callback Examples](https://github.com/lusis/Noah/blob/master/examples/README.md)
71
- Some example callbacks.
101
+ Some example callbacks.
data/bin/noah CHANGED
@@ -6,4 +6,5 @@ require 'vegas'
6
6
 
7
7
  Vegas::Runner.new(Noah::App, 'noah') do |runner, opts, app|
8
8
  opts.on("-r", "--redis URL", "redis url to connect to (default: redis://localhost:6379/0)") {|r| ENV["REDIS_URL"] = r; Noah::App.set :redis_url, r }
9
+ opts.on("--esize SIZE", Integer, "Max allowed ephemeral size in bytes") {|esize| Noah::App.set :ephemeral_size, esize }
9
10
  end
@@ -8,10 +8,9 @@ Apparently we could not connect to the redis instance.
8
8
  By default the watcher will attempt to connect to "redis://localhost:6379/0"
9
9
  If your redis instance is listening elsewhere, please start like so:
10
10
 
11
- REDIS_URL="redis://hostname:port/dbnum" noah-watcher.rb
12
-
13
- This will be rectified in a future release. Sorry about that.
11
+ noah-watcher.rb -r redis://hostname:port/dbnum
14
12
  ----------------------------------------------------------------------------
13
+
15
14
  EOC
16
15
 
17
16
  HELP = <<-EOH
@@ -27,6 +26,8 @@ require 'json'
27
26
 
28
27
  opts = Slop.parse do
29
28
  banner "Usage: noah-watcher.rb [options]"
29
+ on :r, :redis_url, 'Redis URL to use. This MUST match what the Noah server is using for now', :default => 'redis://localhost:6379/0', :argument => true
30
+ on :o, :output, 'Log destination - full file path. Default is STDOUT', :default => STDOUT, :argument => true
30
31
  on '--depinstall', "Installs additional dependencies" do
31
32
  puts "Installing dependencies"
32
33
  puts "em-hiredis..."
@@ -54,6 +55,8 @@ rescue LoadError => e
54
55
  exit
55
56
  end
56
57
 
58
+ ENV['REDIS_URL'] = opts[:redis_url]
59
+
57
60
  begin
58
61
  require 'noah'
59
62
  require 'noah/agent'
@@ -62,7 +65,7 @@ rescue Errno::ECONNREFUSED
62
65
  exit
63
66
  end
64
67
 
65
- Noah::Log.logger = Logger.new(STDOUT)
68
+ Noah::Log.logger = Logger.new(opts[:output])
66
69
  LOGGER = Noah::Log.logger
67
70
  LOGGER.progname = __FILE__
68
71
 
@@ -78,10 +81,10 @@ EventMachine.run do
78
81
  r = EventMachine::Hiredis.connect(ENV["REDIS_URL"])
79
82
  r.errback{|x| LOGGER.error("Unable to connect to redis: #{x}")}
80
83
  LOGGER.info("Attaching to Redis Pubsub")
81
- r.psubscribe("*")
82
- r.on(:pmessage) do |pattern, event, message|
84
+ proc = Proc.new{ |event, message|
83
85
  noah.reread_watchers if event =~ /^\/\/noah\/watchers\/.*/
84
86
  noah.broker("#{event}|#{message}") unless noah.watchers == 0
85
- end
87
+ }
88
+ r.pubsub.psubscribe("*", proc)
86
89
 
87
90
  end
@@ -5,7 +5,7 @@ require 'em-http-request'
5
5
 
6
6
  class HttpPostWatch < Noah::CustomWatcher
7
7
  redis_host "redis://127.0.0.1:6379/0"
8
- pattern "//noah/configuration/redis_server"
8
+ pattern "//noah/configurations/redis_server"
9
9
  destination Proc.new {|x| ::EM::HttpRequest.new('http://localhost:4567/webhook', :connection_timeout => 2, :inactivity_timeout => 4).post :body => x}
10
10
  run!
11
11
  end
@@ -9,7 +9,7 @@ set :noah_client_name, 'my_sinatra_app'
9
9
 
10
10
  def get_config_from_noah(setting)
11
11
  begin
12
- c = open("#{settings.noah_server}/c/#{settings.noah_client_name}/#{setting}").read
12
+ c = open("#{settings.noah_server}/applications/#{settings.noah_client_name}/configurations/#{setting}").read
13
13
  set setting.to_sym, c
14
14
  end
15
15
  end
@@ -17,7 +17,7 @@ end
17
17
  get_config_from_noah('redis_server')
18
18
 
19
19
  def get_redis_version
20
- Ohm.connect :url => settings.redis_server
20
+ Ohm.connect :url => settings.redis_server['body']
21
21
  Ohm.redis.info["redis_version"]
22
22
  end
23
23
 
@@ -25,9 +25,10 @@ get "/" do
25
25
  "Redis version: #{get_redis_version}"
26
26
  end
27
27
 
28
- put "/webhook" do
28
+ post "/webhook" do
29
29
  data = JSON.parse(request.body.read)
30
- settings.redis_server = data["body"]
30
+ settings.redis_server = data
31
+ puts data["body"]
31
32
  resp = {:message => "reconfigured", :setting => data["name"], :body => data["body"]}.to_json
32
33
  "#{resp}"
33
34
  end
@@ -16,6 +16,8 @@ module Noah
16
16
  set :show_exceptions, false
17
17
  set :run, false
18
18
  set :redis_url, ENV['REDIS_URL'] || 'redis://localhost:6379/0'
19
+ set :ephemeral_size, ENV['NOAH_ESIZE'] || 512
20
+ disable :protection
19
21
  end
20
22
 
21
23
  configure(:development) do
@@ -43,12 +45,21 @@ module Noah
43
45
  end
44
46
 
45
47
  # Displays an overview page of all registered objects
46
- get '/' do
48
+ get '/', :provides => :html do
47
49
  content_type "text/html"
48
-
49
50
  haml :index, :format => :html5, :locals => {:redis_version => Ohm.redis.info["redis_version"].to_s, :noah_version => Noah::VERSION}
50
51
  end
51
52
 
53
+ get '/', :provides => :json do
54
+ content_type "application/json"
55
+ erb :'index.json', :locals => {:redis_version => Ohm.redis.info["redis_version"].to_s, :noah_version => Noah::VERSION}
56
+ end
57
+
58
+ get '/version', :provides => :json do
59
+ content_type "application/json"
60
+ {:redis_version => Ohm.redis.info["redis_version"].to_s, :noah_version => Noah::VERSION}.to_json
61
+ end
62
+
52
63
  not_found do
53
64
  content_type "application/json"
54
65
  erb :'404'
@@ -88,8 +88,11 @@ module Noah
88
88
  self.name.nil? ? name=@deleted_name : name=self.name
89
89
  # Pulling out dbnum for now. Need to rethink it
90
90
  #pub_category = "#{db}:noah.#{self.class.to_s}[#{name}].#{meth}"
91
+ # TODO
92
+ # Add a url in the message body containing the URL to the item
93
+ url = "/#{self.class_to_lower}s/#{name}"
91
94
  pub_category = "#{self.patternize_me}"
92
- Ohm.redis.publish(pub_category, self.to_hash.merge({"action" => meth, "pubcategory" => pub_category}).to_json)
95
+ Ohm.redis.publish(pub_category, self.to_hash.merge({"action" => meth, "pubcategory" => pub_category, "path" => url}).to_json)
93
96
 
94
97
  # The following provides a post post-action hook. It allows a class to provide it's own handling after the fact
95
98
  # good example is in [Noah::Ephemeral] where it's used to check for/clean up expired ephemeral nodes entries
@@ -31,7 +31,7 @@ module Noah
31
31
  if obj.valid?
32
32
  obj.save
33
33
  end
34
- obj
34
+ obj if obj.valid?
35
35
  rescue Exception => e
36
36
  e.message
37
37
  end
@@ -62,10 +62,25 @@ module Noah
62
62
  end
63
63
 
64
64
  class Configurations
65
- def self.all(options = {})
65
+ def self.all(options = {}, short=false)
66
+ short_keys = [:format, :created_at, :updated_at]
66
67
  config_hash = Hash.new
67
68
  options.empty? ? configs=Configuration.all.sort : configs=Configuration.find(options).sort
68
- configs.each {|x| config_hash["#{x.name}"] = x.to_hash.reject {|k,v| k == :name} }
69
+ if short == false
70
+ configs.each {|x| config_hash["#{x.name}"] = x.to_hash.reject {|k,v| k == :name} }
71
+ else
72
+ configs.each do |x|
73
+ items = x.to_hash.select {|k,v| k if short_keys.include?(k)}
74
+ # 1.8 fix for Hash#select
75
+ if items.is_a?(Array)
76
+ items_hash = {}
77
+ items.each {|item| items_hash.merge!(Hash[*item])}
78
+ else
79
+ items_hash = items
80
+ end
81
+ config_hash["#{x.name}"] = items_hash
82
+ end
83
+ end
69
84
  config_hash
70
85
  end
71
86
  end
@@ -47,7 +47,7 @@ class Noah::App
47
47
  end
48
48
  if app.valid?
49
49
  action = app.is_new? ? "create" : "update"
50
- app.save
50
+ #app.save
51
51
  r = {"result" => "success","id" => app.id, "action" => action, "name" => app.name }
52
52
  r.to_json
53
53
  else
@@ -13,16 +13,23 @@ class Noah::App
13
13
  get '/configurations/:configname/?' do |configname|
14
14
  c = Noah::Configuration.find(:name => configname).first
15
15
  (halt 404) if c.nil?
16
+ #content_type c.format.to_sym
16
17
  content_type content_type_mapping[c.format.to_sym] if content_type_mapping[c.format.to_sym]
17
- #response.headers['Content-Disposition'] = "attachment; filename=#{configname}"
18
- c.body
18
+ c.body.to_s
19
19
  end
20
+
20
21
  # GET all configurations
21
22
  get '/configurations/?' do
22
- configs = Noah::Configurations.all.to_hash
23
+ params[:short] ||= false
24
+ configs = Noah::Configurations.all({},params[:short])
23
25
  (halt 404) if configs.size == 0
26
+ configs.each do |config, values|
27
+ u = request.url.gsub(/(\/\?short=true|\?short=true)/,'/'+config)
28
+ values.merge!({:location=>u}) if params[:short]
29
+ end
24
30
  configs.to_json
25
31
  end
32
+
26
33
  # Add configuration object to a custom link hierarchy
27
34
  put '/configurations/:configname/link' do |configname|
28
35
  required_params = ["link_name"]
@@ -19,7 +19,7 @@ class Noah::App
19
19
  end
20
20
 
21
21
  put '/ephemerals/*' do
22
- raise("Data too large") if request.body.size > 512
22
+ raise("Data too large") if request.body.size > settings.ephemeral_size
23
23
  d = request.body.read || nil
24
24
  opts = {:path => "/#{params[:splat][0]}", :data => d}
25
25
  e = Noah::Ephemeral.find_or_create(opts)
@@ -1,3 +1,3 @@
1
1
  module Noah
2
- VERSION = "0.8.5"
2
+ VERSION = "0.8.7"
3
3
  end
@@ -21,36 +21,37 @@ Gem::Specification.new do |s|
21
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  s.require_paths = ["lib"]
23
23
 
24
- s.add_dependency("eventmachine", ["1.0.0.beta.3"])
25
- s.add_dependency("em-http-request", ["1.0.0.beta.4"])
26
- s.add_dependency("redis", ["= 2.2.0"])
27
- s.add_dependency("nest", ["= 1.1.0"])
28
- s.add_dependency("rack", ["= 1.2.2"])
29
- s.add_dependency("tilt", ["= 1.2.2"])
30
- s.add_dependency("sinatra", ["= 1.2.3"])
31
- s.add_dependency("ohm", ["= 0.1.3"])
32
- s.add_dependency("ohm-contrib", ["= 0.1.1"])
33
- s.add_dependency("haml", ["= 3.0.25"])
34
- s.add_dependency("vegas", ["= 0.1.8"])
35
- s.add_dependency("guid", ["= 0.1.1"])
36
- s.add_dependency("slop", ["= 2.1.0"])
24
+ s.add_dependency("eventmachine", "1.0.0.beta.4")
25
+ s.add_dependency("em-http-request", "1.0.0.beta.4")
26
+ s.add_dependency("cookiejar")
27
+ s.add_dependency("redis", "~> 2.2")
28
+ s.add_dependency("nest", "= 1.1.0")
29
+ s.add_dependency("rack", "~> 1.4")
30
+ s.add_dependency("tilt", "~> 1.3")
31
+ s.add_dependency("sinatra", "~> 1.3")
32
+ s.add_dependency("rack-protection", "~> 1.2")
33
+ s.add_dependency("ohm", "= 0.1.3")
34
+ s.add_dependency("ohm-contrib", "= 0.1.1")
35
+ s.add_dependency("haml", "= 3.0.25")
36
+ s.add_dependency("vegas", "= 0.1.8")
37
+ s.add_dependency("guid", "= 0.1.1")
38
+ s.add_dependency("slop", "= 2.1.0")
39
+ s.add_dependency("hiredis", "0.4.5")
40
+ s.add_dependency("cs-em-hiredis", "0.1.2")
37
41
 
38
42
 
39
43
  if RUBY_PLATFORM =~ /java/
40
44
  s.add_dependency("jruby-openssl")
41
45
  s.add_dependency("json")
42
- s.add_development_dependency("warbler", ["= 1.2.1"])
46
+ s.add_development_dependency("warbler", "= 1.2.1")
43
47
  else
44
- s.add_dependency("hiredis", ["= 0.3.1"])
45
48
  s.add_dependency("yajl-ruby")
46
- s.add_dependency("SystemTimer") if RUBY_VERSION =~ /1.8/
47
49
  s.add_dependency("thin")
48
50
  end
49
51
 
50
- s.add_development_dependency("diff-lcs", ["= 1.1.2"])
51
- s.add_development_dependency("sinatra-reloader", ["= 0.5.0"])
52
- s.add_development_dependency("rspec", ["~> 2.5"])
53
- # s.add_development_dependency("rcov", ["= 0.9.9"])
54
- s.add_development_dependency("rack-test", ["= 0.5.7"])
55
- s.add_development_dependency("rake", ["= 0.8.7"])
52
+ s.add_development_dependency("diff-lcs", "= 1.1.2")
53
+ s.add_development_dependency("sinatra-reloader", "= 0.5.0")
54
+ s.add_development_dependency("rspec", "~> 2.5")
55
+ s.add_development_dependency("rack-test", "= 0.6.1")
56
+ s.add_development_dependency("rake", "= 0.8.7")
56
57
  end
@@ -65,8 +65,19 @@ describe "Using the Configuration Model", :reset_redis => true do
65
65
  c = Noah::Configurations.all
66
66
  c.class.to_s.should == 'Hash'
67
67
  c.size.should == 2
68
- c.has_key?(a.name).should == true
69
- c.has_key?(b.name).should == true
68
+ c.has_key?(a.name.to_s).should == true
69
+ c.has_key?(b.name.to_s).should == true
70
+ end
71
+
72
+ it "return all Configurations in short form" do
73
+ a = Noah::Configuration.find_or_create(@appconf_string)
74
+ b = Noah::Configuration.find_or_create(@appconf_json)
75
+ c = Noah::Configurations.all({},true)
76
+ c.class.to_s.should == 'Hash'
77
+ c.size.should == 2
78
+ c.has_key?(a.name.to_s).should == true
79
+ c.has_key?(b.name.to_s).should == true
80
+ c.each {|k,v| v.keys.map {|k| k.to_s}.sort.should == ['created_at','format','updated_at']}
70
81
  end
71
82
  end
72
83
 
@@ -58,16 +58,16 @@ describe "Using the Link Model", :reset_redis => true do
58
58
  h[:name].should == l.name
59
59
  h[:updated_at].should == l.updated_at
60
60
  h[:created_at].should == l.created_at
61
- h[:hosts].has_key?(@host.name).should == true
62
- h[:hosts][@host.name].keys.map {|k| k.to_s}.sort.should == [:id, :status, :tags, :services].map {|k| k.to_s}.sort
63
- h[:services].has_key?(@service.name).should == true
64
- h[:services][@service.name][@host.name].keys.map {|k| k.to_s}.sort.should == [:id, :status, :tags].map {|k| k.to_s}.sort
65
- h[:applications].has_key?(@application.name).should == true
66
- h[:applications][@application.name].keys.map {|k| k.to_s}.sort.should == [:id, :tags, :configurations].map {|k| k.to_s}.sort
67
- h[:configurations].has_key?(@configuration.name).should == true
68
- h[:configurations][@configuration.name].keys.map {|k| k.to_s }.sort.should == [:id, :tags, :format, :body].map {|k| k.to_s}.sort
69
- h[:ephemerals].has_key?(@ephemeral.name).should == true
70
- h[:ephemerals][@ephemeral.name].keys.map {|k| k.to_s}.sort.should == [:id, :tags, :path, :data].map {|k| k.to_s}.sort
61
+ h[:hosts].has_key?(@host.name.to_s).should == true
62
+ h[:hosts]["#{@host.name}"].keys.map {|k| k.to_s}.sort.should == [:id, :status, :tags, :services].map {|k| k.to_s}.sort
63
+ h[:services].has_key?(@service.name.to_s).should == true
64
+ h[:services]["#{@service.name}"]["#{@host.name}"].keys.map {|k| k.to_s}.sort.should == [:id, :status, :tags].map {|k| k.to_s}.sort
65
+ h[:applications].has_key?(@application.name.to_s).should == true
66
+ h[:applications]["#{@application.name}"].keys.map {|k| k.to_s}.sort.should == [:id, :tags, :configurations].map {|k| k.to_s}.sort
67
+ h[:configurations].has_key?(@configuration.name.to_s).should == true
68
+ h[:configurations]["#{@configuration.name}"].keys.map {|k| k.to_s }.sort.should == [:id, :tags, :format, :body].map {|k| k.to_s}.sort
69
+ h[:ephemerals].has_key?(@ephemeral.name.to_s).should == true
70
+ h[:ephemerals]["#{@ephemeral.name}"].keys.map {|k| k.to_s}.sort.should == [:id, :tags, :path, :data].map {|k| k.to_s}.sort
71
71
 
72
72
  end
73
73
  end
@@ -27,7 +27,7 @@ describe "Using the Application API", :reset_redis => false do
27
27
  response["name"].should == @a.name
28
28
  response.has_key?("configurations").should == true
29
29
  c = response["configurations"]
30
- c.has_key?(@c.name).should == true
30
+ c.has_key?(@c.name.to_s).should == true
31
31
  c["#{@c.name}"]["format"].should == "#{@c.format}"
32
32
  c["#{@c.name}"]["body"].should == "#{@c.body}"
33
33
  end
@@ -41,6 +41,35 @@ describe "Using the Configuration API", :reset_redis => true, :populate_sample_d
41
41
  end
42
42
  end
43
43
  end
44
+
45
+ it "all configurations in short form with no trailing slash" do
46
+ get '/configurations?short=true'
47
+ last_response.should be_ok
48
+ response = last_response.should return_json
49
+ response.keys.size.should == 3
50
+ %w[redis_url json_config yaml_config].each do |c|
51
+ response.keys.member?(c).should == true
52
+ %w[format location created_at updated_at].each do |ck|
53
+ response[c].keys.member?(ck).should == true
54
+ end
55
+ end
56
+ response.each {|k,v| v['location'].should =~ /^http:\/\/.*\/configurations\/#{k}/}
57
+ end
58
+
59
+ it "all configurations in short form with trailing slash" do
60
+ get '/configurations/?short=true'
61
+ last_response.should be_ok
62
+ response = last_response.should return_json
63
+ response.keys.size.should == 3
64
+ %w[redis_url json_config yaml_config].each do |c|
65
+ response.keys.member?(c).should == true
66
+ %w[format location created_at updated_at].each do |ck|
67
+ response[c].keys.member?(ck).should == true
68
+ end
69
+ end
70
+ response.each {|k,v| v['location'].should =~ /^http:\/\/.*\/configurations\/#{k}/}
71
+ end
72
+
44
73
  it "named configuration should work as JSON" do
45
74
  header "Accept", "application/json"
46
75
  get '/configurations/redis_url'
@@ -22,13 +22,13 @@ describe "Using the Service API", :reset_redis => false, :populate_sample_data =
22
22
  get "/services/#{@sample_service[:name]}"
23
23
  last_response.should be_ok
24
24
  response = last_response.should return_json
25
- response.is_a?(Hash).should == true
26
- response.has_key?(@s.name).should == true
27
- response[@s.name].is_a?(Hash).should == true
28
- response[@s.name].has_key?(@h.name).should == true
29
- response[@s.name][@h.name].is_a?(Hash).should == true
30
- response[@s.name][@h.name]["id"].should == @s.id
31
- response[@s.name][@h.name]["status"].should == @s.status
25
+ response.class.to_s.should == "Hash"
26
+ response.has_key?(@s.name.to_s).should == true
27
+ response["#{@s.name}"].class.to_s.should == "Hash"
28
+ response["#{@s.name}"].has_key?(@h.name.to_s).should == true
29
+ response["#{@s.name}"]["#{@h.name}"].class.to_s.should == "Hash"
30
+ response["#{@s.name}"]["#{@h.name}"]["id"].should == @s.id
31
+ response["#{@s.name}"]["#{@h.name}"]["status"].should == @s.status
32
32
  end
33
33
  it "named service for host should work" do
34
34
  get "/services/#{@sample_service[:name]}/#{@sample_host[:name]}"
@@ -2,16 +2,27 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "Noah App Basics", :reset_redis => true do
4
4
 
5
- it "should show the index page" do
5
+ it "should show the index page as html" do
6
+ header "Accept", "text/html"
6
7
  get '/'
7
8
  last_response.should be_ok
8
9
  last_response.body.include?("Noah Start Page").should == true
9
10
  end
10
11
 
12
+ it "should show the index page as json" do
13
+ header "Accept", "application/json"
14
+ get '/'
15
+ last_response.should return_json
16
+ response = JSON.parse(last_response.body)
17
+ response.has_key?("redis_version").should == true
18
+ response.has_key?("noah_version").should == true
19
+ response.has_key?("resources").should == true
20
+ end
21
+
11
22
  it "should test the 404 message" do
12
23
  get '/foo'
13
24
  last_response.status.should == 404
14
- last_response.headers["Content-Type"].should == "application/json"
25
+ last_response.should return_json
15
26
  response = JSON.parse(last_response.body)
16
27
  response["result"].should == "failure"
17
28
  response["error_message"].should == "Resource not found"
@@ -72,7 +72,7 @@ end
72
72
 
73
73
  RSpec::Matchers.define :return_json do
74
74
  match do |last_response|
75
- last_response.headers["Content-Type"].should == "application/json"
75
+ last_response.headers["Content-Type"].should =~ /^application\/json;.*/
76
76
  response = JSON.parse(last_response.body)
77
77
  end
78
78
 
@@ -83,7 +83,7 @@ end
83
83
 
84
84
  RSpec::Matchers.define :be_missing do
85
85
  match do |last_response|
86
- last_response.headers["Content-Type"].should == "application/json"
86
+ last_response.headers["Content-Type"].should =~ /^application\/json;.*/
87
87
  last_response.status.should == 404
88
88
  response = JSON.parse(last_response.body)
89
89
  response["result"].should == "failure"
@@ -93,7 +93,7 @@ end
93
93
 
94
94
  RSpec::Matchers.define :be_invalid do
95
95
  match do |last_response|
96
- last_response.headers["Content-Type"].should == "application/json"
96
+ last_response.headers["Content-Type"].should =~ /^application\/json;.*/
97
97
  response = JSON.parse(last_response.body)
98
98
  response["result"].should == "failure"
99
99
  response["error_message"].should == "Missing Parameters"
@@ -0,0 +1,10 @@
1
+ {
2
+ "redis_version":"<%= locals[:redis_version] %>",
3
+ "noah_version":"<%= locals[:noah_version] %>",
4
+ "resources":{
5
+ "hosts":{"link":"<%= request.url %>hosts"},
6
+ "services":{"link":"<%= request.url %>services"},
7
+ "applications":{"link":"<%= request.url %>applications"},
8
+ "configurations":{"link":"<%= request.url %>configurations"}
9
+ }
10
+ }
metadata CHANGED
@@ -1,263 +1,304 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: noah
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.8.5
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.8.7
6
6
  platform: jruby
7
- authors:
7
+ authors:
8
8
  - John E. Vincent
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-08-05 00:00:00 -04:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2012-05-09 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
17
15
  name: eventmachine
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ version_requirements: &2056 !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - =
19
+ - !ruby/object:Gem::Version
20
+ version: 1.0.0.beta.4
20
21
  none: false
21
- requirements:
22
- - - "="
23
- - !ruby/object:Gem::Version
24
- version: 1.0.0.beta.3
22
+ requirement: *2056
23
+ prerelease: false
25
24
  type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
25
+ - !ruby/object:Gem::Dependency
28
26
  name: em-http-request
27
+ version_requirements: &2074 !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - =
30
+ - !ruby/object:Gem::Version
31
+ version: 1.0.0.beta.4
32
+ none: false
33
+ requirement: *2074
29
34
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
35
+ type: :runtime
36
+ - !ruby/object:Gem::Dependency
37
+ name: cookiejar
38
+ version_requirements: &2090 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
31
43
  none: false
32
- requirements:
33
- - - "="
34
- - !ruby/object:Gem::Version
35
- version: 1.0.0.beta.4
44
+ requirement: *2090
45
+ prerelease: false
36
46
  type: :runtime
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
47
+ - !ruby/object:Gem::Dependency
39
48
  name: redis
40
- prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
49
+ version_requirements: &2106 !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.2'
42
54
  none: false
43
- requirements:
44
- - - "="
45
- - !ruby/object:Gem::Version
46
- version: 2.2.0
55
+ requirement: *2106
56
+ prerelease: false
47
57
  type: :runtime
48
- version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
58
+ - !ruby/object:Gem::Dependency
50
59
  name: nest
51
- prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
53
- none: false
54
- requirements:
55
- - - "="
56
- - !ruby/object:Gem::Version
60
+ version_requirements: &2122 !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - =
63
+ - !ruby/object:Gem::Version
57
64
  version: 1.1.0
65
+ none: false
66
+ requirement: *2122
67
+ prerelease: false
58
68
  type: :runtime
59
- version_requirements: *id004
60
- - !ruby/object:Gem::Dependency
69
+ - !ruby/object:Gem::Dependency
61
70
  name: rack
62
- prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
71
+ version_requirements: &2138 !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
64
76
  none: false
65
- requirements:
66
- - - "="
67
- - !ruby/object:Gem::Version
68
- version: 1.2.2
77
+ requirement: *2138
78
+ prerelease: false
69
79
  type: :runtime
70
- version_requirements: *id005
71
- - !ruby/object:Gem::Dependency
80
+ - !ruby/object:Gem::Dependency
72
81
  name: tilt
73
- prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
82
+ version_requirements: &2154 !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: '1.3'
75
87
  none: false
76
- requirements:
77
- - - "="
78
- - !ruby/object:Gem::Version
79
- version: 1.2.2
88
+ requirement: *2154
89
+ prerelease: false
80
90
  type: :runtime
81
- version_requirements: *id006
82
- - !ruby/object:Gem::Dependency
91
+ - !ruby/object:Gem::Dependency
83
92
  name: sinatra
93
+ version_requirements: &2170 !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: '1.3'
98
+ none: false
99
+ requirement: *2170
84
100
  prerelease: false
85
- requirement: &id007 !ruby/object:Gem::Requirement
101
+ type: :runtime
102
+ - !ruby/object:Gem::Dependency
103
+ name: rack-protection
104
+ version_requirements: &2186 !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ version: '1.2'
86
109
  none: false
87
- requirements:
88
- - - "="
89
- - !ruby/object:Gem::Version
90
- version: 1.2.3
110
+ requirement: *2186
111
+ prerelease: false
91
112
  type: :runtime
92
- version_requirements: *id007
93
- - !ruby/object:Gem::Dependency
113
+ - !ruby/object:Gem::Dependency
94
114
  name: ohm
95
- prerelease: false
96
- requirement: &id008 !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - "="
100
- - !ruby/object:Gem::Version
115
+ version_requirements: &2202 !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - =
118
+ - !ruby/object:Gem::Version
101
119
  version: 0.1.3
120
+ none: false
121
+ requirement: *2202
122
+ prerelease: false
102
123
  type: :runtime
103
- version_requirements: *id008
104
- - !ruby/object:Gem::Dependency
124
+ - !ruby/object:Gem::Dependency
105
125
  name: ohm-contrib
106
- prerelease: false
107
- requirement: &id009 !ruby/object:Gem::Requirement
108
- none: false
109
- requirements:
110
- - - "="
111
- - !ruby/object:Gem::Version
126
+ version_requirements: &2218 !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - =
129
+ - !ruby/object:Gem::Version
112
130
  version: 0.1.1
131
+ none: false
132
+ requirement: *2218
133
+ prerelease: false
113
134
  type: :runtime
114
- version_requirements: *id009
115
- - !ruby/object:Gem::Dependency
135
+ - !ruby/object:Gem::Dependency
116
136
  name: haml
117
- prerelease: false
118
- requirement: &id010 !ruby/object:Gem::Requirement
119
- none: false
120
- requirements:
121
- - - "="
122
- - !ruby/object:Gem::Version
137
+ version_requirements: &2234 !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - =
140
+ - !ruby/object:Gem::Version
123
141
  version: 3.0.25
142
+ none: false
143
+ requirement: *2234
144
+ prerelease: false
124
145
  type: :runtime
125
- version_requirements: *id010
126
- - !ruby/object:Gem::Dependency
146
+ - !ruby/object:Gem::Dependency
127
147
  name: vegas
128
- prerelease: false
129
- requirement: &id011 !ruby/object:Gem::Requirement
130
- none: false
131
- requirements:
132
- - - "="
133
- - !ruby/object:Gem::Version
148
+ version_requirements: &2250 !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - =
151
+ - !ruby/object:Gem::Version
134
152
  version: 0.1.8
153
+ none: false
154
+ requirement: *2250
155
+ prerelease: false
135
156
  type: :runtime
136
- version_requirements: *id011
137
- - !ruby/object:Gem::Dependency
157
+ - !ruby/object:Gem::Dependency
138
158
  name: guid
139
- prerelease: false
140
- requirement: &id012 !ruby/object:Gem::Requirement
141
- none: false
142
- requirements:
143
- - - "="
144
- - !ruby/object:Gem::Version
159
+ version_requirements: &2266 !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - =
162
+ - !ruby/object:Gem::Version
145
163
  version: 0.1.1
164
+ none: false
165
+ requirement: *2266
166
+ prerelease: false
146
167
  type: :runtime
147
- version_requirements: *id012
148
- - !ruby/object:Gem::Dependency
168
+ - !ruby/object:Gem::Dependency
149
169
  name: slop
150
- prerelease: false
151
- requirement: &id013 !ruby/object:Gem::Requirement
152
- none: false
153
- requirements:
154
- - - "="
155
- - !ruby/object:Gem::Version
170
+ version_requirements: &2282 !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - =
173
+ - !ruby/object:Gem::Version
156
174
  version: 2.1.0
175
+ none: false
176
+ requirement: *2282
177
+ prerelease: false
157
178
  type: :runtime
158
- version_requirements: *id013
159
- - !ruby/object:Gem::Dependency
179
+ - !ruby/object:Gem::Dependency
160
180
  name: hiredis
161
- prerelease: false
162
- requirement: &id014 !ruby/object:Gem::Requirement
181
+ version_requirements: &2298 !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - =
184
+ - !ruby/object:Gem::Version
185
+ version: 0.4.5
163
186
  none: false
164
- requirements:
165
- - - "="
166
- - !ruby/object:Gem::Version
167
- version: 0.3.1
168
- type: :runtime
169
- version_requirements: *id014
170
- - !ruby/object:Gem::Dependency
171
- name: yajl-ruby
187
+ requirement: *2298
172
188
  prerelease: false
173
- requirement: &id015 !ruby/object:Gem::Requirement
174
- none: false
175
- requirements:
176
- - - ">="
177
- - !ruby/object:Gem::Version
178
- version: "0"
179
189
  type: :runtime
180
- version_requirements: *id015
181
- - !ruby/object:Gem::Dependency
182
- name: thin
190
+ - !ruby/object:Gem::Dependency
191
+ name: cs-em-hiredis
192
+ version_requirements: &2314 !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - =
195
+ - !ruby/object:Gem::Version
196
+ version: 0.1.2
197
+ none: false
198
+ requirement: *2314
183
199
  prerelease: false
184
- requirement: &id016 !ruby/object:Gem::Requirement
200
+ type: :runtime
201
+ - !ruby/object:Gem::Dependency
202
+ name: jruby-openssl
203
+ version_requirements: &2330 !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ! '>='
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
185
208
  none: false
186
- requirements:
187
- - - ">="
188
- - !ruby/object:Gem::Version
189
- version: "0"
209
+ requirement: *2330
210
+ prerelease: false
190
211
  type: :runtime
191
- version_requirements: *id016
192
- - !ruby/object:Gem::Dependency
193
- name: diff-lcs
212
+ - !ruby/object:Gem::Dependency
213
+ name: json
214
+ version_requirements: &2346 !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ! '>='
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ none: false
220
+ requirement: *2346
194
221
  prerelease: false
195
- requirement: &id017 !ruby/object:Gem::Requirement
222
+ type: :runtime
223
+ - !ruby/object:Gem::Dependency
224
+ name: warbler
225
+ version_requirements: &2362 !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - =
228
+ - !ruby/object:Gem::Version
229
+ version: 1.2.1
196
230
  none: false
197
- requirements:
198
- - - "="
199
- - !ruby/object:Gem::Version
231
+ requirement: *2362
232
+ prerelease: false
233
+ type: :development
234
+ - !ruby/object:Gem::Dependency
235
+ name: diff-lcs
236
+ version_requirements: &2380 !ruby/object:Gem::Requirement
237
+ requirements:
238
+ - - =
239
+ - !ruby/object:Gem::Version
200
240
  version: 1.1.2
241
+ none: false
242
+ requirement: *2380
243
+ prerelease: false
201
244
  type: :development
202
- version_requirements: *id017
203
- - !ruby/object:Gem::Dependency
245
+ - !ruby/object:Gem::Dependency
204
246
  name: sinatra-reloader
205
- prerelease: false
206
- requirement: &id018 !ruby/object:Gem::Requirement
207
- none: false
208
- requirements:
209
- - - "="
210
- - !ruby/object:Gem::Version
247
+ version_requirements: &2396 !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - =
250
+ - !ruby/object:Gem::Version
211
251
  version: 0.5.0
252
+ none: false
253
+ requirement: *2396
254
+ prerelease: false
212
255
  type: :development
213
- version_requirements: *id018
214
- - !ruby/object:Gem::Dependency
256
+ - !ruby/object:Gem::Dependency
215
257
  name: rspec
216
- prerelease: false
217
- requirement: &id019 !ruby/object:Gem::Requirement
218
- none: false
219
- requirements:
258
+ version_requirements: &2412 !ruby/object:Gem::Requirement
259
+ requirements:
220
260
  - - ~>
221
- - !ruby/object:Gem::Version
222
- version: "2.5"
261
+ - !ruby/object:Gem::Version
262
+ version: '2.5'
263
+ none: false
264
+ requirement: *2412
265
+ prerelease: false
223
266
  type: :development
224
- version_requirements: *id019
225
- - !ruby/object:Gem::Dependency
267
+ - !ruby/object:Gem::Dependency
226
268
  name: rack-test
227
- prerelease: false
228
- requirement: &id020 !ruby/object:Gem::Requirement
269
+ version_requirements: &2428 !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - =
272
+ - !ruby/object:Gem::Version
273
+ version: 0.6.1
229
274
  none: false
230
- requirements:
231
- - - "="
232
- - !ruby/object:Gem::Version
233
- version: 0.5.7
275
+ requirement: *2428
276
+ prerelease: false
234
277
  type: :development
235
- version_requirements: *id020
236
- - !ruby/object:Gem::Dependency
278
+ - !ruby/object:Gem::Dependency
237
279
  name: rake
238
- prerelease: false
239
- requirement: &id021 !ruby/object:Gem::Requirement
240
- none: false
241
- requirements:
242
- - - "="
243
- - !ruby/object:Gem::Version
280
+ version_requirements: &2444 !ruby/object:Gem::Requirement
281
+ requirements:
282
+ - - =
283
+ - !ruby/object:Gem::Version
244
284
  version: 0.8.7
285
+ none: false
286
+ requirement: *2444
287
+ prerelease: false
245
288
  type: :development
246
- version_requirements: *id021
247
289
  description: Application registry inspired by Apache Zookeeper
248
- email:
290
+ email:
249
291
  - lusis.org+rubygems.org@gmail.com
250
- executables:
292
+ executables:
251
293
  - noah
252
- - noah-watcher.rb
294
+ - noah-watcher
253
295
  extensions: []
254
-
255
296
  extra_rdoc_files: []
256
-
257
- files:
297
+ files:
258
298
  - .autotest
259
299
  - .gemtest
260
300
  - .gitignore
301
+ - CHANGELOG.md
261
302
  - Gemfile
262
303
  - LICENSE
263
304
  - README.md
@@ -265,7 +306,7 @@ files:
265
306
  - TODO.md
266
307
  - autotest/discover.rb
267
308
  - bin/noah
268
- - bin/noah-watcher.rb
309
+ - bin/noah-watcher
269
310
  - config.ru
270
311
  - config/warble.rb
271
312
  - examples/Kirkfile
@@ -354,33 +395,50 @@ files:
354
395
  - views/404.erb
355
396
  - views/500.erb
356
397
  - views/index.haml
357
- has_rdoc: true
398
+ - views/index.json.erb
358
399
  homepage: https://github.com/lusis/noah
359
400
  licenses: []
360
-
361
401
  post_install_message: This release has backwards incompatible changes to the API. Please watch http://goo.gl/jYqp2 for details
362
402
  rdoc_options: []
363
-
364
- require_paths:
403
+ require_paths:
365
404
  - lib
366
- required_ruby_version: !ruby/object:Gem::Requirement
405
+ required_ruby_version: !ruby/object:Gem::Requirement
406
+ requirements:
407
+ - - ! '>='
408
+ - !ruby/object:Gem::Version
409
+ version: '0'
367
410
  none: false
368
- requirements:
369
- - - ">="
370
- - !ruby/object:Gem::Version
371
- version: "0"
372
- required_rubygems_version: !ruby/object:Gem::Requirement
411
+ required_rubygems_version: !ruby/object:Gem::Requirement
412
+ requirements:
413
+ - - ! '>='
414
+ - !ruby/object:Gem::Version
415
+ version: '0'
373
416
  none: false
374
- requirements:
375
- - - ">="
376
- - !ruby/object:Gem::Version
377
- version: "0"
378
417
  requirements: []
379
-
380
418
  rubyforge_project: noah
381
- rubygems_version: 1.6.2
382
- signing_key:
419
+ rubygems_version: 1.8.15
420
+ signing_key:
383
421
  specification_version: 3
384
422
  summary: Application registry inspired by Apache Zookeeper
385
- test_files: []
386
-
423
+ test_files:
424
+ - spec/application_spec.rb
425
+ - spec/configuration_spec.rb
426
+ - spec/ephemeral_spec.rb
427
+ - spec/host_spec.rb
428
+ - spec/link_spec.rb
429
+ - spec/noahapp_application_spec.rb
430
+ - spec/noahapp_configuration_spec.rb
431
+ - spec/noahapp_ephemeral_spec.rb
432
+ - spec/noahapp_host_spec.rb
433
+ - spec/noahapp_service_spec.rb
434
+ - spec/noahapp_spec.rb
435
+ - spec/noahapp_tag_spec.rb
436
+ - spec/noahapp_watcher_spec.rb
437
+ - spec/service_spec.rb
438
+ - spec/spec_helper.rb
439
+ - spec/support/db/.keep
440
+ - spec/support/sample_data.rb
441
+ - spec/support/test-redis.conf
442
+ - spec/tag_spec.rb
443
+ - spec/watcher_spec.rb
444
+ ...