noah 0.2.1-jruby → 0.3-jruby

Sign up to get free protection for your applications and to get access to all the features.
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')