noah 0.4-jruby → 0.6.pre-jruby

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Rakefile +2 -69
  2. data/lib/noah.rb +1 -0
  3. data/lib/noah/agent.rb +1 -0
  4. data/lib/noah/agents/base_agent.rb +4 -2
  5. data/lib/noah/agents/http_agent.rb +1 -1
  6. data/lib/noah/agents/https_agent.rb +6 -0
  7. data/lib/noah/app.rb +8 -6
  8. data/lib/noah/exceptions.rb +0 -0
  9. data/lib/noah/linkable.rb +21 -0
  10. data/lib/noah/models.rb +14 -25
  11. data/lib/noah/models/applications.rb +19 -9
  12. data/lib/noah/models/configurations.rb +32 -13
  13. data/lib/noah/models/ephemerals.rb +7 -6
  14. data/lib/noah/models/hosts.rb +11 -5
  15. data/lib/noah/models/link.rb +70 -29
  16. data/lib/noah/models/services.rb +11 -2
  17. data/lib/noah/models/tags.rb +86 -5
  18. data/lib/noah/models/watchers.rb +0 -1
  19. data/lib/noah/{application_routes.rb → routes/applications.rb} +31 -27
  20. data/lib/noah/routes/configurations.rb +77 -0
  21. data/lib/noah/{ephemeral_routes.rb → routes/ephemerals.rb} +5 -5
  22. data/lib/noah/{host_routes.rb → routes/hosts.rb} +16 -1
  23. data/lib/noah/routes/links.rb +16 -0
  24. data/lib/noah/{service_routes.rb → routes/services.rb} +28 -12
  25. data/lib/noah/routes/tags.rb +15 -0
  26. data/lib/noah/{watcher_routes.rb → routes/watchers.rb} +0 -0
  27. data/lib/noah/taggable.rb +30 -0
  28. data/lib/noah/version.rb +1 -1
  29. data/noah.gemspec +5 -4
  30. data/spec/application_spec.rb +3 -3
  31. data/spec/configuration_spec.rb +19 -12
  32. data/spec/host_spec.rb +5 -5
  33. data/spec/noahapp_application_spec.rb +11 -13
  34. data/spec/noahapp_configuration_spec.rb +63 -40
  35. data/spec/noahapp_ephemeral_spec.rb +15 -15
  36. data/spec/noahapp_host_spec.rb +4 -6
  37. data/spec/noahapp_service_spec.rb +8 -7
  38. data/spec/service_spec.rb +2 -2
  39. data/spec/spec_helper.rb +5 -5
  40. data/spec/support/sample_data.rb +87 -0
  41. data/spec/tag_spec.rb +78 -0
  42. data/views/index.haml +7 -1
  43. metadata +335 -311
  44. data/lib/noah/configuration_routes.rb +0 -81
  45. data/lib/noah/models/link_member.rb +0 -18
@@ -3,7 +3,8 @@ module Noah
3
3
  class Host < Model
4
4
  # Host model
5
5
  # @return {Host} a {Host} object
6
-
6
+ include Taggable
7
+ include Linkable
7
8
  attribute :name
8
9
  attribute :status
9
10
  collection :services, Service
@@ -21,9 +22,11 @@ module Noah
21
22
 
22
23
  # @return [Hash] A hash representation of a {Host}
23
24
  def to_hash
24
- arr = []
25
- services.sort.each {|s| arr << s.to_hash}
26
- h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => arr}
25
+ services_hash = Hash.new
26
+ services.sort.each do |svc|
27
+ services_hash["#{svc.name}"] = svc.status
28
+ end
29
+ h = {:name => name, :status => status, :created_at => created_at, :updated_at => updated_at, :services => services_hash}
27
30
  super.merge(h)
28
31
  end
29
32
 
@@ -50,7 +53,10 @@ module Noah
50
53
  # @param [Hash] optional filters for results
51
54
  # @return [Array] Array of {Host} objects
52
55
  def self.all(options = {})
53
- options.empty? ? Noah::Host.all.sort : Noah::Host.find(options).sort
56
+ host_hash = Hash.new
57
+ options.empty? ? hosts=Noah::Host.all.sort : hosts=Noah::Host.find(options).sort
58
+ hosts.each {|x| host_hash["#{x.name}"] = x.to_hash.reject {|k,v| k == :name } }
59
+ host_hash
54
60
  end
55
61
  end
56
62
  end
@@ -1,45 +1,86 @@
1
- require File.join(File.dirname(__FILE__), 'link_member')
2
1
  module Noah
3
2
  class Link < Model
4
3
  attribute :path
5
- list :nodes, LinkMember
6
-
4
+ attribute :nodes
5
+
7
6
  index :path
7
+ index :nodes
8
+
9
+ def nodes
10
+ arr = []
11
+ self.key[:nodes].smembers.each do |node|
12
+ arr << node
13
+ end
14
+ arr
15
+ end
16
+
17
+ def nodes=(node)
18
+ case node.class.to_s
19
+ when "Array"
20
+ node.each do |n|
21
+ self.key[:nodes].sadd(n.key)
22
+ n.links << self
23
+ end
24
+ else
25
+ self.key[:nodes].sadd(node.key)
26
+ node.links << self
27
+ end
28
+ end
8
29
 
9
30
  def validate
10
31
  super
11
32
  assert_present :path
12
33
  end
13
- # Nothing to see yet.
14
- # This will be for creating "overlays" or "link" relationships
15
- # between arbitrary objects or modeling your data the way you want.
16
- #
17
- # Example:
18
- # path = "/myservers"
19
- # path.nodes = ["/applications/myapp","/some/ephemeral/path", "sometag"]
20
- #
21
- # would result in a structure like:
22
- # path/
23
- # applications/
24
- # myapp
25
- # some/ephemeral/path/
26
- # child1
27
- # child2
28
- # child3
29
- # sometag/
30
- # tagged_item1
31
- # tagged_item2
32
- # tagged_item4
33
- # tagged_item5
34
- #
35
- # The idea is to create a blended view across opinionated, tagged and
36
- # ephemeral nodes.
37
- #
38
- # Almost a "choose your own model" thing.
34
+
35
+ def to_hash
36
+ # TODO Holy shit, is this messy or what?
37
+ # Prepopulate instance variables of each object type instead?
38
+ %w[applications configurations hosts services ephemerals].each {|x| instance_variable_set("@#{x}", Hash.new)}
39
+ if nodes.size > 0
40
+ nodes.each do |node|
41
+ rejected_vals = [:created_at, :updated_at, :links, :name]
42
+ n = node_to_class(node)
43
+ cls = class_to_lower(n.class.to_s)
44
+ hsh = instance_variable_get("@#{cls}s")
45
+ # all of this bs is because services are unique per [servicename, hostname]
46
+ # so if I add multiple services just by name to the hash, I'll wipe the previous one
47
+ # a better option would be for services to be named slug style
48
+ hsh["#{n.name}"] = Hash.new unless hsh.has_key?(n.name)
49
+ case cls
50
+ when "service"
51
+ sh = Noah::Host[n.host_id].name
52
+ hsh["#{n.name}"]["#{sh}"] = Hash.new unless hsh["#{n.name}"].has_key?("#{sh}")
53
+ hsh["#{n.name}"]["#{sh}"].merge!({:id => n.id, :status => n.status, :tags => n.to_hash[:tags]})
54
+ when "host"
55
+ hsh["#{n.name}"].merge!({:id => n.id, :status => n.status, :tags => n.to_hash[:tags], :services => n.to_hash[:services]})
56
+ else
57
+ hsh["#{n.name}"].merge!(n.to_hash.reject{|key, value| rejected_vals.member?(key)})
58
+ end
59
+ end
60
+ end
61
+ h = {:name => name, :hosts => @hosts, :services => @services, :applications => @applications, :configurations => @configurations, :ephemerals => @ephemerals, :created_at => created_at, :updated_at => updated_at}
62
+ super.merge(h)
63
+ end
39
64
 
40
65
  def name
41
66
  @name = path
42
67
  end
43
68
 
69
+ class <<self
70
+ def find_or_create(opts={})
71
+ begin
72
+ find(opts).first.nil? ? obj=create(opts) : obj=find(opts).first
73
+ obj
74
+ rescue Exception => e
75
+ e.message
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+ def node_to_class(node)
82
+ node.match(/^Noah::(.*):(\d+)$/)
83
+ Noah.const_get($1).send(:[], $2)
84
+ end
44
85
  end
45
86
  end
@@ -1,7 +1,8 @@
1
1
  module Noah
2
2
 
3
3
  class Service < Model
4
-
4
+ include Taggable
5
+ include Linkable
5
6
  attribute :name
6
7
  attribute :status
7
8
  reference :host, Host
@@ -48,7 +49,15 @@ module Noah
48
49
 
49
50
  class Services
50
51
  def self.all(options = {})
51
- options.empty? ? Service.all.sort : Service.find(options).sort
52
+ service_hash = Hash.new
53
+ options.empty? ? services=Service.all.sort : services=Service.find(options).sort
54
+ services.each do |svc|
55
+ service_hash["#{svc.name}"] = Hash.new unless service_hash.has_key?(svc.name)
56
+ host_name = Noah::Host[svc.host_id].name
57
+ service_hash["#{svc.name}"]["#{host_name}"] = Hash.new
58
+ service_hash["#{svc.name}"]["#{host_name}"].merge!({:id => svc.id, :status => svc.status, :tags => svc.to_hash[:tags], :links => svc.to_hash[:links], :created_at => svc.created_at, :updated_at => svc.updated_at})
59
+ end
60
+ service_hash
52
61
  end
53
62
  end
54
63
  end
@@ -1,13 +1,94 @@
1
1
  module Noah
2
+
2
3
  class Tag < Model
3
- counter :total
4
+ attribute :name
5
+ attribute :members
6
+ index :members
7
+ index :name
8
+
9
+ def validate
10
+ super
11
+ assert_present :name
12
+ assert_unique :name
13
+ end
14
+
15
+ def members=(member)
16
+ self.key[:members].sadd(member.key)
17
+ member.tag! self.name unless member.tags.member?(self)
18
+ end
19
+
20
+ def members
21
+ hsh = Hash.new
22
+ self.key[:members].smembers.each do |member|
23
+ n = node_to_class(member)
24
+ cls = class_to_lower(n.class.to_s)
25
+ hash_key = "#{cls}s".to_sym
26
+ hsh[hash_key] = Array.new unless hsh.has_key?(hash_key)
27
+ hsh[hash_key] << n
28
+ end
29
+ hsh
30
+ end
31
+
32
+ def to_hash
33
+ h = {:name => name, :created_at => created_at, :updated_at => updated_at}
34
+ h.merge!(members_to_hash)
35
+ super.merge(h)
36
+ end
37
+
38
+ class <<self
39
+ def find_or_create(opts={})
40
+ begin
41
+ find(opts).first.nil? ? obj=create(opts) : obj=find(opts).first
42
+ obj
43
+ rescue Exception => e
44
+ e.message
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+ def node_to_class(node)
51
+ node.match(/^Noah::(.*):(\d+)$/)
52
+ Noah.const_get($1).send(:[], $2)
53
+ end
54
+
55
+ def members_to_hash
56
+ new_hash = Hash.new
57
+ members.keys.each {|k| new_hash[k] = Hash.new}
58
+ members.each do |category, member_array|
59
+ rejected_vals = [:created_at, :updated_at, :tags, :name, :host]
60
+ h = new_hash[category]
61
+ member_array.each {|mem| h["#{mem.name}"] = Hash.new unless h.has_key?(mem.name)}
62
+ case category
63
+ when :services
64
+ member_array.each do |s|
65
+ sh = Noah::Host[s.host_id].name
66
+ h["#{s.name}"]["#{sh}"] = Hash.new unless h["#{s.name}"].has_key?(sh)
67
+ h["#{s.name}"]["#{sh}"].merge!(s.to_hash.reject{|k,v| rejected_vals.member?(k)})
68
+ end
69
+ else
70
+ member_array.each do |m|
71
+ h["#{m.name}"].merge!(m.to_hash.reject{|k,v| rejected_vals.member?(k)})
72
+ end
73
+ end
74
+ end
75
+ new_hash
76
+ end
77
+ end
4
78
 
5
- def name
6
- @name = id
79
+ class Tags
80
+ def self.all(options = {})
81
+ tag_hash = Hash.new
82
+ options.empty? ? tags=Tag.all.sort : tags=Tag.find(options).sort
83
+ tags.each {|t| tag_hash["#{t.name}"] = t.to_hash.reject {|k,v| k == :name } }
84
+ tag_hash
7
85
  end
8
86
 
9
- def self.[](id)
10
- super(encode(id)) || create(:id => encode(id))
87
+ class <<self
88
+ def tagged(tag)
89
+ t = Tag.find(:name => tag).first
90
+ t.members
91
+ end
11
92
  end
12
93
  end
13
94
 
@@ -1,4 +1,3 @@
1
- require 'digest/sha1'
2
1
  module Noah
3
2
  class Watcher < Model
4
3
  include WatcherValidations
@@ -2,21 +2,23 @@ class Noah::App
2
2
  # Application URIs
3
3
  get '/applications/:appname/:config/?' do |appname, config|
4
4
  app = Noah::Application.find(:name => appname).first
5
- if app.nil?
6
- halt 404
7
- else
8
- c = Noah::Configuration.find(:name => config, :application_id => app.id).first
9
- c.to_json
10
- end
5
+ (halt 404) if app.nil?
6
+ c = app.configurations.find(:name => config).first
7
+ c.to_json
11
8
  end
12
9
 
13
10
  get '/applications/:appname/?' do |appname|
14
11
  app = Noah::Application.find(:name => appname).first
15
- if app.nil?
16
- halt 404
17
- else
18
- app.to_json
19
- end
12
+ (halt 404) if app.nil?
13
+ app.to_json
14
+ end
15
+
16
+ put '/applications/:appname/tag' do |appname|
17
+ required_params = ["tags"]
18
+ data = JSON.parse(request.body.read)
19
+ (data.keys.sort == required_params.sort) ? (a=Noah::Application.find(:name=>appname).first) : (raise "Missing Parameters")
20
+ a.nil? ? (halt 404) : (a.tag!(data['tags']))
21
+ a.to_json
20
22
  end
21
23
 
22
24
  put '/applications/:appname/watch' do |appname|
@@ -27,6 +29,14 @@ class Noah::App
27
29
  w.to_json
28
30
  end
29
31
 
32
+ put '/applications/:appname/link' do |appname|
33
+ required_params = ["link_name"]
34
+ data = JSON.parse(request.body.read)
35
+ (data.keys.sort == required_params.sort) ? (a = Noah::Application.find(:name => appname).first) : (raise "Missing Parameters")
36
+ a.nil? ? (halt 404) : (a.link! data["link_name"])
37
+ a.to_json
38
+ end
39
+
30
40
  put '/applications/:appname/?' do |appname|
31
41
  required_params = ["name"]
32
42
  data = JSON.parse(request.body.read)
@@ -47,24 +57,18 @@ class Noah::App
47
57
 
48
58
  delete '/applications/:appname/?' do |appname|
49
59
  app = Noah::Application.find(:name => appname).first
50
- if app.nil?
51
- halt 404
52
- else
53
- configurations = []
54
- Noah::Configuration.find(:application_id => app.id).sort.each {|x| configurations << x; x.delete} if app.configurations.size > 0
55
- app.delete
56
- r = {"result" => "success", "action" => "delete", "id" => "#{app.id}", "name" => "#{appname}", "configurations" => "#{configurations.size}"}
57
- r.to_json
58
- end
60
+ (halt 404) if app.nil?
61
+ app.delete
62
+ r = {"result" => "success", "action" => "delete", "id" => "#{app.id}", "name" => "#{appname}"}
63
+ r.to_json
64
+ end
65
+
66
+ delete '/applications/:appname/configurations/:configname/?' do |appname, configname|
59
67
  end
60
68
 
61
69
  get '/applications/?' do
62
- apps = []
63
- Noah::Application.all.sort.each {|a| apps << a.to_hash}
64
- if apps.empty?
65
- halt 404
66
- else
67
- apps.to_json
68
- end
70
+ apps = Noah::Applications.all
71
+ (halt 404) if apps.size == 0
72
+ apps.to_json
69
73
  end
70
74
  end
@@ -0,0 +1,77 @@
1
+ class Noah::App
2
+ content_type_mapping = {
3
+ :yaml => "text/x-yaml",
4
+ :json => "application/json",
5
+ :xml => "text/xml",
6
+ :string => "text/plain"
7
+ }
8
+ # GET the raw data of a configuration object
9
+ get '/configurations/:configname/data/?' do |configname|
10
+ c = Noah::Configuration.find(:name => configname).first
11
+ (halt 404) if c.nil?
12
+ content_type content_type_mapping[c.format.to_sym] if content_type_mapping[c.format.to_sym]
13
+ response.headers['Content-Disposition'] = "attachment; filename=#{configname}"
14
+ c.body
15
+ end
16
+ # GET the JSON representation of a configuration object
17
+ get '/configurations/:configname/?' do |configname|
18
+ c = Noah::Configuration.find(:name => configname).first
19
+ (halt 404) if c.nil?
20
+ c.to_json
21
+ end
22
+ # GET all configurations
23
+ get '/configurations/?' do
24
+ configs = Noah::Configurations.all.to_hash
25
+ (halt 404) if configs.size == 0
26
+ configs.to_json
27
+ end
28
+ # Add configuration object to a custom link hierarchy
29
+ put '/configurations/:configname/link' do |configname|
30
+ required_params = ["link_name"]
31
+ data = JSON.parse(request.body.read)
32
+ (data.keys.sort == required_params.sort) ? (a = Noah::Configuration.find(:name => configname).first) : (raise "Missing Parameters")
33
+ a.nil? ? (halt 404) : (a.link! data["link_name"])
34
+ a.to_json
35
+ end
36
+ # Add a tag to a configuration object
37
+ put '/configurations/:configname/tag' do |configname|
38
+ required_params = ["tags"]
39
+ data = JSON.parse(request.body.read)
40
+ (data.keys.sort == required_params.sort) ? (c=Noah::Configuration.find(:name=>configname).first) : (raise "Missing Parameters")
41
+ c.nil? ? (halt 404) : (c.tag!(data['tags']))
42
+ c.to_json
43
+
44
+ end
45
+ # Add a watch to a configuration object
46
+ put '/configurations/:configname/watch' do |configname|
47
+ required_params = ["endpoint"]
48
+ data = JSON.parse(request.body.read)
49
+ (data.keys.sort == required_params.sort) ? (c = Noah::Configuration.find(:name => configname).first) : (raise "Missing Parameters")
50
+ c.nil? ? (halt 404) : (w = c.watch!(:endpoint => data['endpoint']))
51
+ w.to_json
52
+ end
53
+ # Attach a configuration object to an application object
54
+ put '/configurations/:configname/?' do |configname|
55
+ required_params = ["format", "body"]
56
+ data = JSON.parse(request.body.read)
57
+ data.keys.sort == required_params.sort ? config=Noah::Configuration.find_or_create(:name => configname) : (raise "Missing Parameters")
58
+ config.body = data["body"]
59
+ config.format = data["format"]
60
+ if config.valid?
61
+ config.save
62
+ action = config.is_new? ? "create" : "update"
63
+ r = {"result" => "success","id" => "#{config.id}", "action" => action, "item" => config.name}
64
+ r.to_json
65
+ else
66
+ raise "#{format_errors(config)}"
67
+ end
68
+ end
69
+
70
+ delete '/configurations/:configname/?' do |configname|
71
+ cfg = Noah::Configuration.find(:name => configname).first
72
+ (halt 404) if cfg.nil?
73
+ cfg.delete
74
+ r = {"result" => "success", "id" => cfg.id, "action" => "delete", "affected_applications" => cfg.affected_applications, "item" => cfg.name}
75
+ r.to_json
76
+ end
77
+ end