rumx 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/History.md +28 -0
  2. data/README.md +8 -6
  3. data/examples/bean_hash/README +2 -0
  4. data/examples/bean_hash/config.ru +9 -0
  5. data/examples/bean_hash/my_bean.rb +44 -0
  6. data/examples/bean_list/my_bean.rb +3 -3
  7. data/examples/embedded/my_bean.rb +3 -2
  8. data/examples/hash/README +2 -0
  9. data/examples/hash/config.ru +9 -0
  10. data/examples/hash/my_bean.rb +30 -0
  11. data/examples/list/my_bean.rb +5 -2
  12. data/examples/monitor_script/README +8 -0
  13. data/examples/monitor_script/rumx_attributes +67 -0
  14. data/examples/simple/config.ru +3 -1
  15. data/examples/simple/my_other_bean.rb +11 -0
  16. data/examples/timer/README +1 -1
  17. data/examples/timer/my_bean.rb +2 -1
  18. data/examples/timer_hash/README +2 -0
  19. data/examples/timer_hash/config.ru +9 -0
  20. data/examples/timer_hash/my_bean.rb +29 -0
  21. data/lib/rumx.rb +5 -0
  22. data/lib/rumx/attribute.rb +26 -17
  23. data/lib/rumx/attribute_info.rb +12 -0
  24. data/lib/rumx/bean.rb +146 -248
  25. data/lib/rumx/beans.rb +2 -0
  26. data/lib/rumx/beans/error.rb +1 -1
  27. data/lib/rumx/beans/hash.rb +34 -0
  28. data/lib/rumx/beans/timer.rb +2 -2
  29. data/lib/rumx/beans/timer_and_error.rb +1 -1
  30. data/lib/rumx/beans/timer_hash.rb +9 -0
  31. data/lib/rumx/hash_attribute.rb +39 -0
  32. data/lib/rumx/hash_bean.rb +55 -0
  33. data/lib/rumx/list_attribute.rb +65 -0
  34. data/lib/rumx/list_bean.rb +52 -0
  35. data/lib/rumx/server.rb +65 -69
  36. data/lib/rumx/server/views/attribute_value_tag.haml +3 -3
  37. data/lib/rumx/server/views/content_attributes.haml +4 -4
  38. data/lib/rumx/server/views/content_operations.haml +2 -2
  39. data/lib/rumx/server/views/tree_bean_attributes.haml +0 -4
  40. data/lib/rumx/server/views/tree_bean_operations.haml +2 -2
  41. data/lib/rumx/type.rb +15 -7
  42. metadata +21 -3
  43. data/lib/rumx/server/views/content_attribute.haml +0 -35
data/History.md CHANGED
@@ -1,6 +1,34 @@
1
1
  Rumx Changelog
2
2
  =====================
3
3
 
4
+ 0.1.0
5
+
6
+ - Removed the following methods and the equivalient writers and accessors to hopefully make the commands more consistent:
7
+
8
+ OLD: bean_list_reader :foo, :string, 'Description'
9
+ NEW: bean_reader :foo, :list, 'Description', :list_type => :string
10
+
11
+ OLD: bean_list_attr_reader :foo, :string, 'Description'
12
+ NEW: bean_attr_reader :foo, :list, 'Description', :list_type => :string, :allow_write => true #Use allow_write if the accessing of list elements is different from the list.
13
+
14
+ OLD: bean_embed :foo, 'Description'
15
+ NEW: bean_reader :foo, :bean, 'Description'
16
+
17
+ OLD: bean_attr_embed :foo, 'Description'
18
+ NEW: bean_attr_reader :foo, :bean, 'Description'
19
+
20
+ OLD: bean_embed_list :foo, 'Description'
21
+ NEW: bean_reader :foo, :list, 'Description', :list_type => :bean
22
+
23
+ OLD: bean_attr_embed_list :foo, 'Description'
24
+ NEW: bean_attr_reader :foo, :list, 'Description', :list_type => :bean
25
+
26
+ - Added Hash type
27
+
28
+ - A lot of restructuring of the code so it isn't quite as repetitive for the bean iteration and such.
29
+
30
+ - Added example/monitor_script for an example script that could be used with a tool like munin or hyperic.
31
+
4
32
  0.0.8
5
33
 
6
34
  - Added /attributes query which can retrieve attributes for multiple beans in one call.
data/README.md CHANGED
@@ -6,7 +6,9 @@ http://github.com/ClarityServices/rumx
6
6
 
7
7
  Ruby Management Extensions
8
8
 
9
- Allows you to easily implement management interfaces for your Ruby application.
9
+ Allows you to easily implement management interfaces for your Ruby application by adding
10
+ Rumx beans. A Rumx bean is an object that allows external access to specified attributes
11
+ and operations. It is basically equivalent to a JMX MBean.
10
12
 
11
13
  ## Install:
12
14
 
@@ -51,8 +53,8 @@ Note that all Rumx::Bean public methods are prefixed with "bean_" to help avoid
51
53
  You create a tree of beans under Rumx::Bean.root. For instance, you might create a tree for the bean above with the following commands:
52
54
 
53
55
  my_folder = Rumx::Beans::Folder.new
54
- Rumx::Bean.root.bean_add_child(:my_folder, my_folder)
55
- my_folder.bean_add_child(:my_bean, MyBean.new)
56
+ Rumx::Bean.root.bean_add_child(:MyFolder, my_folder)
57
+ my_folder.bean_add_child(:MyBean, MyBean.new)
56
58
 
57
59
  Rumx includes a Sinatra server app called Rumx::Server. You could startup a server by creating the following config.ru and running "rackup -p 4567"
58
60
 
@@ -87,8 +89,10 @@ Refer to the timer example for more information.
87
89
 
88
90
  ## TODO
89
91
 
92
+ I'm rewriting the list logic. List stuff will soon be deprecated.
93
+
90
94
  Figure out the "NameError - uninitialized constant Rack::File:" error that occurs frequently on startup and seems related
91
- to the tree not displaying correctly. Works okay with refresh.
95
+ to the tree not displaying correctly. Works okay with refresh. (Current workaround is to require 'rack/file in server.rb)
92
96
 
93
97
  Api doc non-existent.
94
98
 
@@ -103,8 +107,6 @@ Allow validations in attribute declarations?
103
107
 
104
108
  New types :date and :datetime?
105
109
 
106
- Build in optional authentication or just let user extend Rumx::Server?
107
-
108
110
  Railtie it?
109
111
 
110
112
  ## Author
@@ -0,0 +1,2 @@
1
+ 1) Execute 'rackup -p 4567'
2
+ 2) Browse to http://localhost:4567, expand the tree and view/update the attributes and operations
@@ -0,0 +1,9 @@
1
+ # Allow examples to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
+
4
+ require 'rubygems'
5
+ require 'rumx'
6
+ require 'my_bean'
7
+
8
+ Rumx::Bean.root.bean_add_child(:MyBean, MyBean.new)
9
+ run Rumx::Server
@@ -0,0 +1,44 @@
1
+ require 'rumx'
2
+
3
+ class MyEntryBean
4
+ include Rumx::Bean
5
+
6
+ bean_attr_accessor :my_int, :integer, 'My integer'
7
+ bean_attr_reader :my_string, :string, 'My string'
8
+
9
+ def initialize(my_int, my_string)
10
+ @my_int, @my_string = my_int, my_string
11
+ end
12
+ end
13
+
14
+ class MyBean
15
+ include Rumx::Bean
16
+
17
+ bean_attr_reader :entries, :hash, 'My entries', :hash_type => :bean
18
+
19
+ bean_operation :put_entry, :void, 'Put entry into hash', [
20
+ [ :key, :symbol, 'Hash key'],
21
+ [ :my_int, :integer, 'An integer argument' ],
22
+ [ :my_string, :string, 'A string argument' ]
23
+ ]
24
+
25
+ bean_operation :remove_entry, :void, 'Remove entry from hash', [
26
+ [ :key, :symbol, 'Hash key']
27
+ ]
28
+
29
+ def initialize
30
+ @entries = {:foo => MyEntryBean.new(1, '#1')}
31
+ end
32
+
33
+ def put_entry(key, my_int, my_string)
34
+ @entries[key] = MyEntryBean.new(my_int, my_string)
35
+ return my_string
36
+ end
37
+
38
+ def remove_entry(key)
39
+ removed = @entries.delete(key)
40
+ return 'None' unless removed
41
+ return removed.my_string
42
+ end
43
+ end
44
+
@@ -14,9 +14,9 @@ end
14
14
  class MyBean
15
15
  include Rumx::Bean
16
16
 
17
- bean_attr_reader :greeting, :string, 'My greeting'
18
-
19
- bean_attr_embed_list :entries, 'My entries'
17
+ bean_attr_reader :greeting, :string, 'My greeting'
18
+ # old bean_attr_embed_list :entries, 'My entries'
19
+ bean_attr_reader :entries, :list, 'My entries', :list_type => :bean
20
20
 
21
21
  bean_operation :push_entry, :void, 'Push entry onto entry list', [
22
22
  [ :my_int, :integer, 'An integer argument' ],
@@ -4,8 +4,9 @@ require 'my_embedded_bean'
4
4
  class MyBean
5
5
  include Rumx::Bean
6
6
 
7
- bean_attr_accessor :greeting, :string, 'My greeting'
8
- bean_attr_embed :embedded, 'My embedded bean'
7
+ bean_attr_accessor :greeting, :string, 'My greeting'
8
+ #old bean_attr_embed :embedded, 'My embedded bean'
9
+ bean_attr_reader :embedded, :bean, 'My embedded bean'
9
10
 
10
11
  bean_operation :my_operation, :string, 'My operation', [
11
12
  [ :arg_int, :integer, 'An int argument' ]
@@ -0,0 +1,2 @@
1
+ 1) Execute 'rackup -p 4567'
2
+ 2) Browse to http://localhost:4567, expand the tree and view/update the attributes and operations
@@ -0,0 +1,9 @@
1
+ # Allow examples to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
+
4
+ require 'rubygems'
5
+ require 'rumx'
6
+ require 'my_bean'
7
+
8
+ Rumx::Bean.root.bean_add_child(:MyBean, MyBean.new)
9
+ run Rumx::Server
@@ -0,0 +1,30 @@
1
+ require 'rumx'
2
+
3
+ class MyBean
4
+ include Rumx::Bean
5
+
6
+ bean_attr_reader :messages, :hash, 'Message', :hash_type => :string, :allow_write => true
7
+
8
+ bean_operation :put_message, :string, 'Put message onto message hash', [
9
+ [ :key, :symbol, 'The hash key'],
10
+ [ :message, :string, 'The message' ]
11
+ ]
12
+
13
+ bean_operation :remove_message, :string, 'Remove message from message hash', [
14
+ [ :key, :symbol, 'The hash key']
15
+ ]
16
+
17
+ def initialize
18
+ @messages = {:foo => 'Foo message', :bar => 'Bar message'}
19
+ end
20
+
21
+ def put_message(key, message)
22
+ @messages[key] = message
23
+ return message
24
+ end
25
+
26
+ def remove_message(key)
27
+ @messages.delete(key)
28
+ end
29
+ end
30
+
@@ -3,8 +3,11 @@ require 'rumx'
3
3
  class MyBean
4
4
  include Rumx::Bean
5
5
 
6
- bean_attr_accessor :max_messages, :integer, 'The maximum number of messages to keep'
7
- bean_list_attr_accessor :messages, :string, 'Message', :max_size => :max_messages
6
+ # old bean_attr_accessor :max_messages, :integer, 'The maximum number of messages to keep'
7
+ bean_attr_accessor :max_messages, :integer, 'The maximum number of messages to keep'
8
+ # old bean_list_attr_accessor :messages, :string, 'Message', :max_size => :max_messages
9
+ # Uncomment allow_write part to allow write access to individual messages
10
+ bean_attr_reader :messages, :list, 'Message', :list_type => :string, :max_size => :max_messages#, :allow_write => true
8
11
 
9
12
  bean_operation :push_message, :string, 'Push message onto message list', [
10
13
  [ :message, :string, 'A string argument' ]
@@ -0,0 +1,8 @@
1
+ Startup example/simple and try the following:
2
+
3
+ ./rumx_attributes MyFolder/MyBean
4
+ ./rumx_attributes MyFolder/MyBean MyFolder/MyOtherBean
5
+ ./rumx_attributes bean=MyFolder/MyBean other=MyFolder/MyOtherBean
6
+ # Query params for GETs won't show until the next time you query
7
+ ./rumx_attributes bean=MyFolder/MyBean?my_accessor=42\&my_writer=123.45 other=MyFolder/MyOtherBean
8
+ ./rumx_attributes bean=MyFolder/MyBean other=MyFolder/MyOtherBean
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'net/http'
5
+ require 'optparse'
6
+ require 'cgi'
7
+
8
+ class MyOptions < Hash
9
+ def initialize(argv)
10
+ super
11
+
12
+ opts = OptionParser.new do |opts|
13
+ opts.banner = "Usage: #$0 [options]"
14
+
15
+ # Default values
16
+ self[:host] = 'localhost'
17
+ self[:port] = 4567
18
+ self[:username] = nil
19
+ self[:password] = nil
20
+ self[:format] = 'properties'
21
+ self[:mount] = nil
22
+
23
+ opts.on('-H', '--host [HOST]', "host to hit (defaults to #{self[:host]})") do |val|
24
+ self[:host] = val
25
+ end
26
+
27
+ opts.on('-P', '--port [PORT]', Integer, "port number to hit (defaults to #{self[:port]})") do |val|
28
+ self[:port] = val
29
+ end
30
+
31
+ opts.on('-u', '--username [USERNAME]', "username for basic authentication") do |val|
32
+ self[:username] = val
33
+ end
34
+
35
+ opts.on('-p', '--password [PASSWORD]', "password for basic authentication") do |val|
36
+ self[:password] = val
37
+ end
38
+
39
+ opts.on('-f', '--format [FORMAT]', "format of the returned data (json or properties, defaults to #{self[:format]}") do |val|
40
+ self[:format] = val
41
+ end
42
+
43
+ opts.on('-m', '--mount [PATH]', "path where the Rumx app is mounted") do |val|
44
+ self[:format] = val
45
+ end
46
+ end
47
+
48
+ opts.parse!(argv)
49
+ end
50
+ end
51
+
52
+ options = MyOptions.new(ARGV)
53
+
54
+ # Args can be of the form Myfolder/Subfolder/Foo?reset=true which will expand to <mount>/attributes.<format>?query0=Myfolder/Subfolder/Foo/attributes?reset=true&query1=etc
55
+ path = "/attributes.#{options[:format]}?"
56
+ path = options[:mount] + path if options[:mount]
57
+ ARGV.each_with_index do |query, index|
58
+ path += '&' if index > 0
59
+ path += "query_#{index}=#{CGI.escape(query)}"
60
+ end
61
+
62
+ req = Net::HTTP::Get.new(path)
63
+ req.basic_auth(options[:username], options[:password]) if options[:username]
64
+ res = Net::HTTP.start(options[:host], options[:port]) { |http| http.request(req) }
65
+ if res.kind_of?(Net::HTTPSuccess)
66
+ puts res.body
67
+ end
@@ -3,9 +3,11 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
3
 
4
4
  require 'rubygems'
5
5
  require 'rumx'
6
- require 'my_bean'
6
+ require './my_bean'
7
+ require './my_other_bean'
7
8
 
8
9
  my_folder = Rumx::Beans::Folder.new
9
10
  Rumx::Bean.root.bean_add_child(:MyFolder, my_folder)
10
11
  my_folder.bean_add_child(:MyBean, MyBean.new)
12
+ my_folder.bean_add_child(:MyOtherBean, MyOtherBean.new)
11
13
  run Rumx::Server
@@ -0,0 +1,11 @@
1
+ require 'rumx'
2
+
3
+ class MyOtherBean
4
+ include Rumx::Bean
5
+
6
+ bean_attr_accessor :message, :string, 'A message'
7
+
8
+ def initialize
9
+ @message = "I'm just here to put another bean in the mix"
10
+ end
11
+ end
@@ -1,7 +1,7 @@
1
1
  1) Execute 'rackup -p 4567'
2
2
  2) Browse to http://localhost:4567, expand the tree and view/update the attributes and operations
3
3
  3) Browse to http://localhost:4567/MyBean/timer/attributes.json and refresh the screen every so often.
4
- 4) Browse to http://localhost:4567/MyBean/timer/attributes.json?reset=true and refresh the screen every so often.
4
+ 4) Browse to http://localhost:4567/MyBean/timer/attributes.properties?reset=true and refresh the screen every so often.
5
5
  Note that a tool like munin, nagios, or hyperic could poll this url to monitor the timer and graph the results
6
6
  or create alerts based on exceeding some threshold.
7
7
 
@@ -3,13 +3,14 @@ class MyBean
3
3
 
4
4
  bean_attr_accessor :sleep_time, :float, 'Amount of time in seconds my measured block sleeps'
5
5
  bean_attr_accessor :percent_failure, :integer, 'Percentage of time the measured block will fail'
6
- bean_attr_embed :timer, 'Timer for our sleep action'
7
6
 
8
7
  def initialize
9
8
  @sleep_time = 0.5
10
9
  @percent_failure = 10
11
10
  @timer = Rumx::Beans::TimerAndError.new(:max_errors => 5)
12
11
 
12
+ bean_add_child(:timer, @timer)
13
+
13
14
  Thread.new do
14
15
  while true
15
16
  begin
@@ -0,0 +1,2 @@
1
+ 1) Execute 'rackup -p 4567'
2
+ 2) Browse to http://localhost:4567, expand the tree and view/update the attributes and operations
@@ -0,0 +1,9 @@
1
+ # Allow examples to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
3
+
4
+ require 'rubygems'
5
+ require 'rumx'
6
+ require 'my_bean'
7
+
8
+ Rumx::Bean.root.bean_add_child(:MyBean, MyBean.new)
9
+ run Rumx::Server
@@ -0,0 +1,29 @@
1
+ require 'rumx'
2
+
3
+ class MyBean
4
+ include Rumx::Bean
5
+
6
+ bean_attr_accessor :sleep1, :float, 'Amount of time sleep1 sleeps'
7
+ bean_attr_accessor :sleep2, :float, 'Amount of time sleep2 sleeps'
8
+ bean_attr_accessor :sleep3, :float, 'Amount of time sleep3 sleeps'
9
+
10
+ def initialize
11
+ @sleep1 = 1
12
+ @sleep2 = 2
13
+ @sleep3 = 3
14
+ @timers = Rumx::Beans::TimerHash.new
15
+ bean_add_child(:timers, @timers)
16
+ 100.times do
17
+ Thread.new do
18
+ while true
19
+ @timers[:overall].measure do
20
+ @timers[:sleep1].measure { sleep @sleep1 }
21
+ @timers[:sleep2].measure { sleep @sleep2 }
22
+ @timers[:sleep3].measure { sleep @sleep3 }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
data/lib/rumx.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  require 'rumx/argument'
2
2
  require 'rumx/attribute'
3
+ require 'rumx/attribute_info'
4
+ require 'rumx/list_attribute'
5
+ require 'rumx/hash_attribute'
3
6
  require 'rumx/operation'
4
7
  require 'rumx/bean'
8
+ require 'rumx/list_bean'
9
+ require 'rumx/hash_bean'
5
10
  require 'rumx/type'
6
11
  require 'rumx/server'
7
12
  require 'rumx/beans'
@@ -2,37 +2,46 @@ module Rumx
2
2
  class Attribute
3
3
  attr_reader :name, :type, :description, :allow_read, :allow_write
4
4
 
5
- def initialize(name, type_name, description, allow_read, allow_write, options)
5
+ def initialize(name, type, description, allow_read, allow_write, options)
6
6
  @name = name.to_sym
7
- @type = Type.find(type_name)
7
+ @type = type
8
8
  @description = description
9
- @allow_read = allow_read
10
- @allow_write = allow_write
9
+ # List and hash attributes might set up the object for reading but the individual elements for writing
10
+ @allow_read = options[:allow_read] || allow_read
11
+ @allow_write = options[:allow_write] || allow_write
11
12
  @options = options
12
13
  end
13
14
 
14
15
  def get_value(bean)
15
- return nil unless @allow_read
16
- bean.send(self.name)
16
+ @allow_read ? bean.send(@name) : nil
17
17
  end
18
18
 
19
- def set_value(bean, value)
20
- raise 'Illegal set_value' unless @allow_write
21
- bean.send(self.name.to_s+'=', type.string_to_value(value))
19
+ def each_attribute_info(bean, ancestry, &block)
20
+ yield AttributeInfo.new(self, bean, ancestry+[@name], get_value(bean))
22
21
  end
23
22
 
24
- def get_index_value(obj, index)
25
- return nil unless @allow_read
26
- return obj[index]
27
- end
28
-
29
- def set_index_value(obj, index, value)
30
- raise 'Illegal set_index_value' unless @allow_write
31
- obj[index] = type.string_to_value(value)
23
+ def write?(bean, params)
24
+ if @allow_write
25
+ param_value(params) do |value|
26
+ bean.send(@name.to_s+'=', @type.string_to_value(value))
27
+ return true
28
+ end
29
+ end
30
+ return false
32
31
  end
33
32
 
34
33
  def [](key)
35
34
  @options[key]
36
35
  end
36
+
37
+ protected
38
+
39
+ def param_value(params, &block)
40
+ if params.has_key?(@name)
41
+ yield params[@name]
42
+ elsif params.has_key?(@name.to_s)
43
+ yield params[@name.to_s]
44
+ end
45
+ end
37
46
  end
38
47
  end