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 CHANGED
@@ -44,10 +44,11 @@ task :sample, :redis_url do |t, args|
44
44
  Ohm::connect(:url => args.redis_url)
45
45
  Ohm::redis.flushdb
46
46
  puts "Creating watchers..."
47
- Noah::Watcher.create :endpoint => "http://localhost:3000/webhook", :pattern => "//noah/application"
48
- Noah::Watcher.create :endpoint => "http://localhost:3001/webhook", :pattern => "//noah/configuration"
49
- Noah::Watcher.create :endpoint => "http://localhost:3002/webhook", :pattern => "//noah/host"
50
- Noah::Watcher.create :endpoint => "http://localhost:3003/webhook", :pattern => "//noah/service"
47
+ Noah::Watcher.create :endpoint => "dummy://applications", :pattern => "//noah/applications"
48
+ Noah::Watcher.create :endpoint => "dummy://configurations", :pattern => "//noah/configurations"
49
+ Noah::Watcher.create :endpoint => "dummy://hosts", :pattern => "//noah/hosts"
50
+ Noah::Watcher.create :endpoint => "dummy://services", :pattern => "//noah/services"
51
+ Noah::Watcher.create :endpoint => "dummy://ephemerals", :pattern => "//noah/ephemerals"
51
52
  puts "Creating Host entry for 'localhost'"
52
53
  h = Noah::Host.create(:name => 'localhost', :status => "up")
53
54
  if h.save
@@ -127,3 +128,8 @@ end
127
128
  task :start_demo do
128
129
  puts "Soon, young padawan"
129
130
  end
131
+
132
+ desc "Start an irb session with all libraries loaded"
133
+ task :shell do
134
+ sh "irb -r./lib/noah.rb"
135
+ end
data/bin/noah-watcher.rb CHANGED
@@ -20,7 +20,9 @@ rescue LoadError => e
20
20
  exit
21
21
  end
22
22
 
23
- LOGGER = Logger.new(STDOUT)
23
+ Noah::Log.logger = Logger.new(STDOUT)
24
+ LOGGER = Noah::Log.logger
25
+ LOGGER.progname = __FILE__
24
26
 
25
27
  EventMachine.run do
26
28
  EM.error_handler do |e|
@@ -32,19 +34,20 @@ EventMachine.run do
32
34
  noah.errback{|x| logger.error("Errback: #{x}")}
33
35
  noah.callback{|y| logger.info("Callback: #{y}")}
34
36
  # Passing messages...like a boss
35
- master_channel = EventMachine::Channel.new
37
+ #master_channel = EventMachine::Channel.new
36
38
 
37
39
  r = EventMachine::Hiredis::Client.connect
38
40
  r.errback{|x| logger.error("Unable to connect to redis: #{x}")}
39
41
  logger.debug("Starting up")
40
- r.psubscribe("//noah/*")
42
+ r.psubscribe("*")
41
43
  r.on(:pmessage) do |pattern, event, message|
42
- noah.reread_watchers if event =~ /^\/\/noah\/watcher\/.*/
43
- master_channel.push "#{event}|#{message}"
44
+ noah.reread_watchers if event =~ /^\/\/noah\/watchers\/.*/
45
+ noah.broker("#{event}|#{message}") unless noah.watchers == 0
46
+ #master_channel.push "#{event}|#{message}"
44
47
  end
45
48
 
46
- sub = master_channel.subscribe {|msg|
49
+ #sub = master_channel.subscribe {|msg|
47
50
  # We short circuit if we have no watchers
48
- noah.broker(msg) unless noah.watchers == 0
49
- }
51
+ # noah.broker(msg) unless noah.watchers == 0
52
+ #}
50
53
  end
data/lib/noah.rb CHANGED
@@ -1,5 +1,11 @@
1
1
  module Noah
2
- PROTECTED_PATHS = %w[a c h s w]
2
+ PROTECTED_PATHS = %w[applications configurations hosts services watches ark noah]
3
+ PATH_MAPPING = {"applications" => "Application",
4
+ "services" => "Service",
5
+ "configurations" => "Configuration",
6
+ "hosts" => "Host",
7
+ "tags" => "Tag",
8
+ "ephemeral" => "Ephemeral"}
3
9
  end
4
10
  begin
5
11
  require 'yajl'
@@ -10,6 +16,7 @@ require 'haml'
10
16
  require 'yaml'
11
17
  require 'sinatra/base'
12
18
 
19
+ require File.join(File.dirname(__FILE__), 'noah', 'log')
13
20
  require File.join(File.dirname(__FILE__), 'noah', 'custom_watcher')
14
21
  require File.join(File.dirname(__FILE__), 'noah','validations')
15
22
  require File.join(File.dirname(__FILE__), 'noah','models')
data/lib/noah/agent.rb CHANGED
@@ -1,9 +1,18 @@
1
1
  $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
2
2
  require 'rubygems'
3
- require 'logger'
4
3
  require 'noah'
5
4
  require 'noah/agents/http_agent'
6
5
  require 'noah/agents/dummy_agent'
6
+ begin
7
+ candidates = []
8
+ Gem.source_index.find_all {|g| candidates << g[1].name if g[1].name =~ /^noah-agents-.*/}
9
+ candidates.each do |c|
10
+ require c
11
+ end
12
+ rescue LoadError
13
+ puts "Unable to load #{c}"
14
+ end
15
+
7
16
 
8
17
  module Noah
9
18
  class Agent
@@ -11,9 +20,10 @@ module Noah
11
20
 
12
21
  @@watchers = Noah::Watcher.watch_list
13
22
  @@agents = Noah::Watchers.agents
14
-
23
+
15
24
  def initialize
16
- @logger = LOGGER
25
+ @logger = Noah::Log.logger
26
+ @logger.progname = self.class.name
17
27
  @logger.debug("Initializing with #{@@watchers.size} registered watches")
18
28
  @logger.debug("#{@@agents} agents registered")
19
29
  if EventMachine.reactor_running?
@@ -40,11 +50,26 @@ module Noah
40
50
 
41
51
  def broker(msg)
42
52
  e,m = msg.split("|")
43
- be = Base64.encode64(e).gsub("\n","")
44
- EM::Iterator.new(@@agents).each do |agent, iter|
53
+ # Below isn't being used right now
54
+ #be = Base64.encode64(e).gsub("\n","")
55
+ EM::Iterator.new(@@agents, @@agents.size).each do |agent, iter|
45
56
  agent.send(:notify, e, m, @@watchers.clone)
46
57
  iter.next
47
58
  end
48
59
  end
60
+
61
+ private
62
+ def find_and_register_agents
63
+ candidates = []
64
+ Gem.source_index.find_all {|g| candidates << g[1].name if g[1].name =~ /^noah-agent-.*/}
65
+ candidates.each do |c|
66
+ begin
67
+ require c
68
+ rescue LoadError
69
+ Noah::Log.logger.warn("Unable to load #{c}")
70
+ end
71
+ end
72
+ end
73
+
49
74
  end
50
75
  end
@@ -1,17 +1,41 @@
1
- require 'logger'
2
- require 'logger'
3
-
4
1
  module Noah::Agents
5
2
  module Base
6
- class << self
7
- include EM::Deferrable
8
-
3
+ class <<self
9
4
  PREFIX = "base"
10
5
  NAME = "base-agent"
11
6
  end
12
7
 
13
8
  def self.included(base)
14
9
  Noah::Watchers.register_agent(base)
10
+ base.send :include, EM::Deferrable
11
+ base.send :extend, AgentClassMethods
12
+ end
13
+ end
14
+
15
+ module AgentClassMethods
16
+
17
+ def logger
18
+ Noah::Log.logger.progname = self.name
19
+ Noah::Log.logger
15
20
  end
21
+
22
+ def find_watched_patterns!(watchlist)
23
+ watched_patterns = []
24
+ watchlist.find_all do |w|
25
+ p, ep = Base64.decode64(w).split('|')
26
+ watched_patterns << "#{p}|#{ep}" if ep =~ /^#{self.const_get("PREFIX")}/
27
+ end
28
+ watched_patterns
29
+ end
30
+
31
+ def notify(event, message, watch_list)
32
+ logger.info("Worker Initiated")
33
+ logger.debug("got event - #{event}")
34
+ watched_patterns = find_watched_patterns!(watch_list)
35
+ matches = watched_patterns.find_all {|w| event =~ /^#{w}/}
36
+ logger.debug("Found #{matches.size} matches for #{event}")
37
+ self.callback!(matches, message)
38
+ end
39
+
16
40
  end
17
41
  end
@@ -4,21 +4,14 @@ module Noah::Agents
4
4
  class DummyAgent
5
5
  include Noah::Agents::Base
6
6
 
7
- PREFIX = "dummy"
8
- NAME = "dummy"
7
+ PREFIX = "dummy://"
8
+ NAME = self.name
9
9
 
10
- def self.notify(event, message, watch_list)
11
- logger = LOGGER
12
- logger.info("#{NAME}: Worker initiated")
13
- logger.debug("#{NAME}: got event - #{event}")
14
- matches = watch_list.find_all{|w| event =~ /^#{Base64.decode64(w)}/}
15
- logger.debug("#{NAME}: Found #{matches.size} possible matches for #{event}")
10
+ def self.callback!(matches, message)
16
11
  EM::Iterator.new(matches).each do |watch, iter|
17
- p, ep = Base64.decode64(watch).split("|")
18
- if ep =~ /^#{PREFIX}/
19
- logger.info("#{NAME}: Sending message to: #{ep} for pattern: #{p}")
20
- logger.debug("#{NAME}: message received: #{message}")
21
- end
12
+ p, ep = watch.split("|")
13
+ logger.info("Sending message to: #{ep} for pattern: #{p}")
14
+ logger.debug("message received: #{message}")
22
15
  iter.next
23
16
  end
24
17
  end
@@ -4,27 +4,20 @@ module Noah::Agents
4
4
  class HttpAgent
5
5
  include Noah::Agents::Base
6
6
 
7
- PREFIX = "http"
8
- NAME = "http"
7
+ PREFIX = "http://"
8
+ NAME = self.name
9
9
 
10
- def self.notify(event, message, watch_list)
11
- logger = LOGGER
12
- logger.info("#{NAME}: Worker initiated")
13
- logger.debug("#{NAME}: got event - #{event}")
14
- matches = watch_list.find_all{|w| event =~ /^#{Base64.decode64(w)}/}
15
- logger.debug("#{PREFIX}: Found #{matches.size} possible matches for #{event}")
16
- EM::Iterator.new(matches).each do |watch, iter|
17
- p, ep = Base64.decode64(watch).split("|")
18
- if ep =~ /^#{PREFIX}/
19
- logger.info("#{NAME}: Sending message to (#{ep}) for pattern (#{p})")
20
- http = EM::HttpRequest.new(ep, :connection_timeout => 2, :inactivity_timeout => 4).post :body => message
21
- http.callback {
22
- logger.info("#{NAME}: Message posted to #{ep} successfully")
23
- }
24
- http.errback {
25
- logger.error("#{NAME}: Something went wrong with #{ep}")
26
- }
27
- end
10
+ def self.callback!(matches, message)
11
+ EM::Iterator.new(matches, 100).each do |watch, iter|
12
+ p, ep = watch.split("|")
13
+ logger.info("Sending message to (#{ep}) for pattern (#{p})")
14
+ http = EM::HttpRequest.new(ep, :connection_timeout => 2, :inactivity_timeout => 4).post :body => message
15
+ http.callback {
16
+ logger.info("Message posted to #{ep} successfully")
17
+ }
18
+ http.errback {
19
+ logger.error("Something went wrong with #{ep}")
20
+ }
28
21
  iter.next
29
22
  end
30
23
  end
@@ -1,6 +1,6 @@
1
1
  class Noah::App
2
2
  # Application URIs
3
- get '/a/:appname/:config/?' do |appname, config|
3
+ get '/applications/:appname/:config/?' do |appname, config|
4
4
  app = Noah::Application.find(:name => appname).first
5
5
  if app.nil?
6
6
  halt 404
@@ -10,7 +10,7 @@ class Noah::App
10
10
  end
11
11
  end
12
12
 
13
- get '/a/:appname/?' do |appname|
13
+ get '/applications/:appname/?' do |appname|
14
14
  app = Noah::Application.find(:name => appname).first
15
15
  if app.nil?
16
16
  halt 404
@@ -19,7 +19,7 @@ class Noah::App
19
19
  end
20
20
  end
21
21
 
22
- put '/a/:appname/watch' do |appname|
22
+ put '/applications/:appname/watch' do |appname|
23
23
  required_params = ["endpoint"]
24
24
  data = JSON.parse(request.body.read)
25
25
  (data.keys.sort == required_params.sort) ? (a = Noah::Application.find(:name => appname).first) : (raise "Missing Parameters")
@@ -27,7 +27,7 @@ class Noah::App
27
27
  w.to_json
28
28
  end
29
29
 
30
- put '/a/:appname/?' do |appname|
30
+ put '/applications/:appname/?' do |appname|
31
31
  required_params = ["name"]
32
32
  data = JSON.parse(request.body.read)
33
33
  if data.keys.sort == required_params.sort && data['name'] == appname
@@ -45,7 +45,7 @@ class Noah::App
45
45
  end
46
46
  end
47
47
 
48
- delete '/a/:appname/?' do |appname|
48
+ delete '/applications/:appname/?' do |appname|
49
49
  app = Noah::Application.find(:name => appname).first
50
50
  if app.nil?
51
51
  halt 404
@@ -58,7 +58,7 @@ class Noah::App
58
58
  end
59
59
  end
60
60
 
61
- get '/a/?' do
61
+ get '/applications/?' do
62
62
  apps = []
63
63
  Noah::Application.all.sort.each {|a| apps << a.to_hash}
64
64
  if apps.empty?
@@ -6,7 +6,7 @@ class Noah::App
6
6
  :string => "text/plain"
7
7
  }
8
8
  # Configuration URIs
9
- get '/c/:appname/:element/?' do |appname, element|
9
+ get '/configurations/:appname/:element/?' do |appname, element|
10
10
  a = Noah::Application.find(:name => appname).first
11
11
  if a.nil?
12
12
  halt 404
@@ -17,7 +17,7 @@ class Noah::App
17
17
  end
18
18
  end
19
19
 
20
- get '/c/:appname/?' do |appname|
20
+ get '/configurations/:appname/?' do |appname|
21
21
  config = []
22
22
  a = Noah::Application.find(:name => appname).first
23
23
  if a.nil?
@@ -28,7 +28,7 @@ class Noah::App
28
28
  end
29
29
  end
30
30
 
31
- get '/c/?' do
31
+ get '/configurations/?' do
32
32
  configs = []
33
33
  Noah::Configuration.all.sort.each {|c| configs << c.to_hash}
34
34
  if configs.empty?
@@ -38,7 +38,7 @@ class Noah::App
38
38
  end
39
39
  end
40
40
 
41
- put '/c/:configname/watch' do |configname|
41
+ put '/configurations/:configname/watch' do |configname|
42
42
  required_params = ["endpoint"]
43
43
  data = JSON.parse(request.body.read)
44
44
  (data.keys.sort == required_params.sort) ? (c = Noah::Configuration.find(:name => configname).first) : (raise "Missing Parameters")
@@ -46,7 +46,7 @@ class Noah::App
46
46
  w.to_json
47
47
  end
48
48
 
49
- put '/c/:appname/:element?' do |appname, element|
49
+ put '/configurations/:appname/:element?' do |appname, element|
50
50
  app = Noah::Application.find_or_create(:name => appname)
51
51
  config = Noah::Configuration.find_or_create(:name => element, :application_id => app.id)
52
52
  required_params = ["format", "body"]
@@ -63,7 +63,7 @@ class Noah::App
63
63
  end
64
64
  end
65
65
 
66
- delete '/c/:appname/:element?' do |appname, element|
66
+ delete '/configurations/:appname/:element?' do |appname, element|
67
67
  app = Noah::Application.find(:name => appname).first
68
68
  if app
69
69
  config = Noah::Configuration.find(:name=> element, :application_id => app.id).first
data/lib/noah/helpers.rb CHANGED
@@ -22,6 +22,7 @@ module Noah
22
22
  # Custom exceptions
23
23
  e.on [:pattern, :already_provided], "Pattern is already provided"
24
24
  e.on [:pattern, :replaces_existing], "Pattern would overwrite existing"
25
+ e.on [:path, :reserved_path], "Path is reserved"
25
26
  end
26
27
  error_messages.first
27
28
  end
@@ -2,7 +2,7 @@ class Noah::App
2
2
  # Host URIs
3
3
 
4
4
  # GET named {Service} for named {Host}
5
- get '/h/:hostname/:servicename/?' do |hostname, servicename|
5
+ get '/hosts/:hostname/:servicename/?' do |hostname, servicename|
6
6
  h = host_service(hostname, servicename)
7
7
  if h.nil?
8
8
  halt 404
@@ -14,7 +14,7 @@ class Noah::App
14
14
  # GET named {Host}
15
15
  # @param :hostname name of {Host}
16
16
  # @return [JSON] representation of {Host}
17
- get '/h/:hostname/?' do |hostname|
17
+ get '/hosts/:hostname/?' do |hostname|
18
18
  h = host(:name => hostname)
19
19
  if h.nil?
20
20
  halt 404
@@ -24,7 +24,7 @@ class Noah::App
24
24
  end
25
25
 
26
26
  # GET all {Hosts}
27
- get '/h/?' do
27
+ get '/hosts/?' do
28
28
  hosts.map {|h| h.to_hash}
29
29
  if hosts.size == 0
30
30
  halt 404
@@ -33,7 +33,7 @@ class Noah::App
33
33
  end
34
34
  end
35
35
 
36
- put '/h/:hostname/watch' do |hostname|
36
+ put '/hosts/:hostname/watch' do |hostname|
37
37
  required_params = ["endpoint"]
38
38
  data = JSON.parse(request.body.read)
39
39
  (data.keys.sort == required_params.sort) ? (h = Noah::Host.find(:name => hostname).first) : (raise "Missing Parameters")
@@ -41,7 +41,7 @@ class Noah::App
41
41
  w.to_json
42
42
  end
43
43
 
44
- put '/h/:hostname/?' do |hostname|
44
+ put '/hosts/:hostname/?' do |hostname|
45
45
  required_params = ["name", "status"]
46
46
  data = JSON.parse(request.body.read)
47
47
  (data.keys.sort == required_params.sort && data['name'] == hostname) ? (host = Noah::Host.find_or_create(:name => data['name'], :status => data['status'])) : (raise "Missing Parameters")
@@ -53,7 +53,7 @@ class Noah::App
53
53
  end
54
54
  end
55
55
 
56
- delete '/h/:hostname/?' do |hostname|
56
+ delete '/hosts/:hostname/?' do |hostname|
57
57
  host = Noah::Host.find(:name => hostname).first
58
58
  if host
59
59
  services = []
data/lib/noah/log.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'logger'
2
+ module Noah::Log
3
+ class <<self
4
+ attr_accessor :logger
5
+ end
6
+ end
data/lib/noah/models.rb CHANGED
@@ -2,6 +2,7 @@ require 'ohm'
2
2
  require 'ohm/contrib'
3
3
  module Noah
4
4
  class Model < Ohm::Model
5
+
5
6
  def self.inherited(model)
6
7
 
7
8
  model.send :include, Ohm::Timestamping
@@ -9,6 +10,9 @@ module Noah
9
10
  model.send :include, Ohm::Callbacks
10
11
  model.send :include, Ohm::ExtraValidations
11
12
 
13
+ model.send :attribute, :tags
14
+ model.send :index, :tag
15
+
12
16
  # removing this as it's simply redundant
13
17
  # model.after :save, :notify_via_redis_save
14
18
  model.after :create, :notify_via_redis_create
@@ -21,10 +25,30 @@ module Noah
21
25
 
22
26
  module ModelClassMethods
23
27
 
28
+ def self.included(base)
29
+ Noah::RegisteredModels.register_model(base)
30
+ end
31
+
24
32
  def is_new?
25
33
  self.created_at == self.updated_at
26
34
  end
27
35
 
36
+ def tag(tags = self.tags)
37
+ tags.to_s.split(/\s*,\s*/).uniq
38
+ end
39
+
40
+ def link!(path)
41
+ base_pattern = "#{self.patternize_me}"
42
+ path.nil? ? (raise ArgumentError, "Must provide a path") : p=path
43
+
44
+ begin
45
+ l = Link.new :path => p, :source => base_pattern
46
+ l.valid? ? l.save : (raise "#{l.errors}")
47
+ l.name
48
+ rescue Exception => e
49
+ e.message
50
+ end
51
+ end
28
52
 
29
53
  def watch!(opts={:endpoint => nil, :pattern => nil})
30
54
  base_pattern = "#{self.patternize_me}"
@@ -39,11 +63,11 @@ module Noah
39
63
  e.message
40
64
  end
41
65
  end
42
-
66
+
43
67
  protected
44
68
  def patternize_me
45
69
  name.match(/^\//) ? n = name.gsub(/^\//, '') : n = name
46
- "//noah/#{self.class_to_lower}/#{n}"
70
+ "//noah/#{self.class_to_lower}s/#{n}"
47
71
  end
48
72
 
49
73
  def stash_name
@@ -53,6 +77,7 @@ module Noah
53
77
  def class_to_lower
54
78
  self.class.to_s.gsub(/(.*)::(\w)/,'\2').downcase
55
79
  end
80
+
56
81
  def dbnum
57
82
  o = Ohm.options.first
58
83
  return "0" if o.nil?
@@ -60,6 +85,15 @@ module Noah
60
85
  o[:db].nil? ? "#{o[:url].split('/').last}" : "#{o[:db]}"
61
86
  end
62
87
 
88
+ def before_update
89
+ return if new?
90
+ tag(read_remote(:tags)).map(&Tag).each {|t| t.decr :total}
91
+ end
92
+
93
+ def after_save
94
+ tag.map(&Tag).each {|t| t.incr :total }
95
+ end
96
+
63
97
  ["create", "update", "delete"].each do |meth|
64
98
  class_eval do
65
99
  define_method("notify_via_redis_#{meth}".to_sym) do
@@ -78,7 +112,21 @@ module Noah
78
112
  end
79
113
 
80
114
  end
115
+
116
+ class RegisteredModels
117
+ @@models = []
118
+ def self.register_model(model)
119
+ @@models << model
120
+ end
121
+
122
+ def self.models
123
+ @@models
124
+ end
125
+ end
126
+
81
127
  end
128
+
129
+ require File.join(File.dirname(__FILE__), 'models','tags')
82
130
  require File.join(File.dirname(__FILE__), 'models','hosts')
83
131
  require File.join(File.dirname(__FILE__), 'models','services')
84
132
  require File.join(File.dirname(__FILE__), 'models','applications')