isono 0.1.0 → 0.2.0

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.
@@ -0,0 +1,2 @@
1
+ *~
2
+ #*#
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
+ require 'isono/version'
4
+
5
+
6
+ task :gem do
7
+ require 'rubygems'
8
+ require 'rake/gempackagetask'
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.platform = Gem::Platform::RUBY
12
+ s.version = Isono::VERSION
13
+ s.authors = ['axsh Ltd.', 'Masahiro Fujiwara']
14
+ s.email = ['dev@axsh.net', 'm-fujiwara@axsh.net']
15
+ s.homepage = 'http://github.com/axsh/isono'
16
+ s.summary = 'Messaging and agent fabric'
17
+ s.name = 'isono'
18
+ s.require_path = 'lib'
19
+ s.required_ruby_version = '>= 1.8.7'
20
+ s.rubyforge_project = 'isono'
21
+
22
+ s.files = `git ls-files -c`.split("\n")
23
+
24
+ s.bindir='bin'
25
+ s.executables = %w(cli)
26
+
27
+ s.add_dependency "amqp", "0.7.0"
28
+ s.add_dependency "eventmachine", "1.0.0.beta.3"
29
+ s.add_dependency "statemachine", ">= 1.0.0"
30
+ s.add_dependency "log4r"
31
+
32
+ s.add_development_dependency 'bacon'
33
+ s.add_development_dependency 'rake'
34
+ end
35
+
36
+ File.open('isono.gemspec', 'w'){|f| f.write(spec.to_ruby) }
37
+ sh "gem build isono.gemspec"
38
+ end
@@ -2,43 +2,44 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{isono}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["axsh Ltd.", "Masahiro Fujiwara"]
9
- s.date = %q{2010-11-18}
9
+ s.date = %q{2011-05-26}
10
10
  s.default_executable = %q{cli}
11
11
  s.email = ["dev@axsh.net", "m-fujiwara@axsh.net"]
12
12
  s.executables = ["cli"]
13
- s.files = ["bin/cli", "lib/ext/shellwords.rb", "lib/isono.rb", "lib/isono/rack/object_method.rb", "lib/isono/rack/proc.rb", "lib/isono/rack/data_store.rb", "lib/isono/rack/map.rb", "lib/isono/rack/job.rb", "lib/isono/rack/builder.rb", "lib/isono/rack/thread_pass.rb", "lib/isono/logger.rb", "lib/isono/rack.rb", "lib/isono/messaging_client.rb", "lib/isono/resource_manifest.rb", "lib/isono/node.rb", "lib/isono/manifest.rb", "lib/isono/event_delegate_context.rb", "lib/isono/amqp_client.rb", "lib/isono/node_modules/job_channel.rb", "lib/isono/node_modules/base.rb", "lib/isono/node_modules/event_logger.rb", "lib/isono/node_modules/event_channel.rb", "lib/isono/node_modules/node_heartbeat.rb", "lib/isono/node_modules/node_collector.rb", "lib/isono/node_modules/data_store.rb", "lib/isono/node_modules/job_collector.rb", "lib/isono/node_modules/rpc_channel.rb", "lib/isono/node_modules/job_worker.rb", "lib/isono/serializer.rb", "lib/isono/models/node_state.rb", "lib/isono/models/resource_instance.rb", "lib/isono/models/event_log.rb", "lib/isono/models/job_state.rb", "lib/isono/daemonize.rb", "lib/isono/util.rb", "lib/isono/thread_pool.rb", "lib/isono/runner/rpc_server.rb", "lib/isono/runner/agent.rb", "lib/isono/event_observable.rb", "isono.gemspec", "LICENSE", "NOTICE"]
13
+ s.files = [".gitignore", "LICENSE", "NOTICE", "Rakefile", "bin/cli", "isono.gemspec", "lib/ext/shellwords.rb", "lib/isono.rb", "lib/isono/amqp_client.rb", "lib/isono/daemonize.rb", "lib/isono/event_delegate_context.rb", "lib/isono/event_observable.rb", "lib/isono/logger.rb", "lib/isono/manifest.rb", "lib/isono/messaging_client.rb", "lib/isono/models/event_log.rb", "lib/isono/models/job_state.rb", "lib/isono/models/node_state.rb", "lib/isono/models/resource_instance.rb", "lib/isono/node.rb", "lib/isono/node_modules/base.rb", "lib/isono/node_modules/data_store.rb", "lib/isono/node_modules/event_channel.rb", "lib/isono/node_modules/event_logger.rb", "lib/isono/node_modules/job_channel.rb", "lib/isono/node_modules/job_collector.rb", "lib/isono/node_modules/job_worker.rb", "lib/isono/node_modules/node_collector.rb", "lib/isono/node_modules/node_heartbeat.rb", "lib/isono/node_modules/rpc_channel.rb", "lib/isono/rack.rb", "lib/isono/rack/builder.rb", "lib/isono/rack/data_store.rb", "lib/isono/rack/job.rb", "lib/isono/rack/map.rb", "lib/isono/rack/object_method.rb", "lib/isono/rack/proc.rb", "lib/isono/rack/thread_pass.rb", "lib/isono/resource_manifest.rb", "lib/isono/runner/base.rb", "lib/isono/runner/cli.rb", "lib/isono/runner/rpc_server.rb", "lib/isono/serializer.rb", "lib/isono/thread_pool.rb", "lib/isono/util.rb", "lib/isono/version.rb", "spec/amqp_client_spec.rb", "spec/event_observable_spec.rb", "spec/file_channel_spec.rb", "spec/job_channel_spec.rb", "spec/logger_spec.rb", "spec/manifest_spec.rb", "spec/node_spec.rb", "spec/resource_loader_spec.rb", "spec/rpc_channel_spec.rb", "spec/spec_helper.rb", "spec/thread_pool_spec.rb", "spec/util_spec.rb", "tasks/load_resource_manifest.rake"]
14
14
  s.homepage = %q{http://github.com/axsh/isono}
15
15
  s.require_paths = ["lib"]
16
16
  s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
17
- s.rubygems_version = %q{1.3.6}
18
- s.summary = %q{Messageing and agent fabric}
17
+ s.rubyforge_project = %q{isono}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Messaging and agent fabric}
19
20
 
20
21
  if s.respond_to? :specification_version then
21
22
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
23
  s.specification_version = 3
23
24
 
24
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
25
- s.add_runtime_dependency(%q<amqp>, [">= 0.6.7"])
26
- s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<amqp>, ["= 0.7.0"])
27
+ s.add_runtime_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
27
28
  s.add_runtime_dependency(%q<statemachine>, [">= 1.0.0"])
28
29
  s.add_runtime_dependency(%q<log4r>, [">= 0"])
29
30
  s.add_development_dependency(%q<bacon>, [">= 0"])
30
31
  s.add_development_dependency(%q<rake>, [">= 0"])
31
32
  else
32
- s.add_dependency(%q<amqp>, [">= 0.6.7"])
33
- s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
33
+ s.add_dependency(%q<amqp>, ["= 0.7.0"])
34
+ s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
34
35
  s.add_dependency(%q<statemachine>, [">= 1.0.0"])
35
36
  s.add_dependency(%q<log4r>, [">= 0"])
36
37
  s.add_dependency(%q<bacon>, [">= 0"])
37
38
  s.add_dependency(%q<rake>, [">= 0"])
38
39
  end
39
40
  else
40
- s.add_dependency(%q<amqp>, [">= 0.6.7"])
41
- s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
41
+ s.add_dependency(%q<amqp>, ["= 0.7.0"])
42
+ s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
42
43
  s.add_dependency(%q<statemachine>, [">= 1.0.0"])
43
44
  s.add_dependency(%q<log4r>, [">= 0"])
44
45
  s.add_dependency(%q<bacon>, [">= 0"])
@@ -1,14 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Isono
4
- VERSION='0.1.0'
5
-
4
+ require 'isono/version'
5
+ require 'isono/logger'
6
+
6
7
  autoload :Node, 'isono/node'
7
8
  autoload :AmqpClient, 'isono/amqp_client'
8
9
  autoload :Daemonize, 'isono/daemonize'
9
10
  autoload :Util, 'isono/util'
10
11
  autoload :ThreadPool, 'isono/thread_pool'
11
- autoload :Logger, 'isono/logger'
12
12
  autoload :Manifest, 'isono/manifest'
13
13
  autoload :Serializer, 'isono/serializer'
14
14
  autoload :EventObservable, 'isono/event_observable'
@@ -28,7 +28,8 @@ module Isono
28
28
  autoload :JobCollector, 'isono/node_modules/job_collector'
29
29
  end
30
30
  module Runner
31
- autoload :Agent, 'isono/runner/agent'
31
+ autoload :Base, 'isono/runner/base'
32
+ autoload :CLI, 'isono/runner/cli'
32
33
  autoload :RpcServer, 'isono/runner/rpc_server'
33
34
  end
34
35
  module Rack
@@ -71,26 +71,35 @@ module Isono
71
71
  :pass=>broker_uri.password ||default[:pass]
72
72
  }
73
73
  opts.merge!(args) if args.is_a?(Hash)
74
-
75
- @amqp_client = ::AMQP.connect(opts)
76
- @amqp_client.instance_eval {
77
- def settings
78
- @settings
79
- end
80
- }
81
- @amqp_client.callback {
82
- on_connect
83
- if blk
84
- blk.arity == 1 ? blk.call(:success) : blk.call
85
- end
86
- }
87
- @amqp_client.errback {
88
- logger.error("Failed to connect to the broker: #{amqp_server_uri}")
89
- blk.call(:error) if blk && blk.arity == 1
90
- }
91
- # Note: Thread.current[:mq] is utilized in amqp gem.
92
- Thread.current[:mq] = ::MQ.new(@amqp_client)
93
74
 
75
+ prepare_connect {
76
+ @amqp_client = ::AMQP.connect(opts)
77
+ @amqp_client.instance_eval {
78
+ def settings
79
+ @settings
80
+ end
81
+ }
82
+ @amqp_client.connection_status { |t|
83
+ case t
84
+ when :connected
85
+ # here is tried also when reconnected
86
+ on_connect
87
+ when :disconnected
88
+ on_disconnected
89
+ end
90
+ }
91
+ # the block argument is called once at the initial connection.
92
+ @amqp_client.callback {
93
+ after_connect
94
+ if blk
95
+ blk.arity == 1 ? blk.call(self) : blk.call
96
+ end
97
+ }
98
+ @amqp_client.errback {
99
+ logger.error("Failed to connect to the broker: #{amqp_server_uri}")
100
+ blk.call(self) if blk && blk.arity == 1
101
+ }
102
+ }
94
103
  self
95
104
  end
96
105
 
@@ -105,24 +114,50 @@ module Isono
105
114
 
106
115
  def on_connect
107
116
  end
108
-
117
+
118
+ def on_disconnected
119
+ end
120
+
109
121
  def on_close
110
122
  end
111
123
 
124
+ def before_connect
125
+ end
126
+
127
+ def after_connect
128
+ end
129
+
130
+ def before_close
131
+ end
132
+
133
+ def after_close
134
+ end
135
+
112
136
  def close(&blk)
113
137
  return unless connected?
114
138
 
115
- @amqp_client.close {
116
- begin
117
- on_close
118
- blk.call if blk
119
- ensure
120
- @amqp_client = nil
121
- Thread.current[:mq] = nil
122
- end
139
+ prepare_close {
140
+ @amqp_client.close {
141
+ begin
142
+ on_close
143
+ after_close
144
+ blk.call if blk
145
+ ensure
146
+ @amqp_client = nil
147
+ Thread.current[:mq] = nil
148
+ end
149
+ }
123
150
  }
124
151
  end
125
152
 
153
+ # Create new AMQP channel object
154
+ #
155
+ # @note Do not have to close by user. Channel close is performed
156
+ # as part of connection close.
157
+ def create_channel
158
+ MQ.new(@amqp_client)
159
+ end
160
+
126
161
  # Publish a message to the designated exchange.
127
162
  #
128
163
  # @param [String] exname The exchange name
@@ -148,22 +183,16 @@ module Isono
148
183
  }
149
184
  end
150
185
 
151
- def define_queue(queue_name, exchange_name, opts={}, &blk)
152
- q = amq.queue(queue_name, opts)
153
- amq.exchanges.has_key? exchange_name
154
- q.bind( exchange_name, opts ).subscribe &blk
186
+ private
187
+ def prepare_connect(&blk)
188
+ before_connect
189
+ blk.call
155
190
  end
156
191
 
157
-
158
- def identity_queue(unique_id)
159
- amq.direct('identity')
160
- begin
161
- define_queue("ident.#{unique_id}", "identity", {:exclusive=>true, :nowait=>false})
162
- rescue MQ::Error => e
163
- logger.error("The node having same ID already exists: #{unique_id}")
164
- raise e
165
- end
192
+ def prepare_close(&blk)
193
+ before_close
194
+ blk.call
166
195
  end
167
-
196
+
168
197
  end
169
198
  end
@@ -6,16 +6,18 @@ module Isono
6
6
  # Injects +logger+ method to the included class.
7
7
  # The output message from the logger methods starts the module name trailing message body.
8
8
  module Logger
9
+ @rootlogger = Log4r::Logger.new('Isono')
10
+
11
+ def self.initialize(l4r_output=Log4r::StdoutOutputter.new('stdout'))
12
+ # Isono top level logger
13
+ formatter = Log4r::PatternFormatter.new(:depth => 9999, # stack trace depth
14
+ :pattern => "%d %c [%l]: %M",
15
+ :date_format => "%Y/%m/%d %H:%M:%S"
16
+ )
17
+ l4r_output.formatter = formatter
18
+ @rootlogger.outputters = l4r_output
19
+ end
9
20
 
10
- # Isono top level logger
11
- rootlog = Log4r::Logger.new('Isono')
12
- formatter = Log4r::PatternFormatter.new(:depth => 9999, # stack trace depth
13
- :pattern => "%d %c [%l]: %M",
14
- :date_format => "%Y/%m/%d %H:%M:%S"
15
- )
16
- rootlog.add(Log4r::StdoutOutputter.new('stdout', :formatter => formatter))
17
-
18
-
19
21
  def self.included(klass)
20
22
  klass.class_eval {
21
23
 
@@ -45,4 +47,12 @@ module Isono
45
47
  end
46
48
 
47
49
  end
50
+
51
+ # Set STDOUT as the default log output.
52
+ # To replace another log device, put the line below at the top of
53
+ # your code:
54
+ # Isono::Logger.initialize(Log4r::SyslogOutputter.new('mysyslog'))
55
+ # To disable any of log output:
56
+ # Isono::Logger.initialize(Log4r::Outputter.new('null'))
57
+ Logger.initialize
48
58
  end
@@ -25,14 +25,15 @@ module Isono
25
25
 
26
26
  # @param [String] app_root Application root folder
27
27
  # @param [block]
28
- def initialize(app_root, &blk)
28
+ def initialize(app_root='.', &blk)
29
29
  @node_modules = []
30
30
  resolve_abs_app_root(app_root)
31
31
  @config = ConfigStruct.new
32
32
  @config.app_root = app_root
33
33
 
34
34
  instance_eval(&blk) if blk
35
- load_config
35
+
36
+ load_config(@config_path) if @config_path
36
37
  end
37
38
 
38
39
  # Regist a node module class to be initialized/terminated.
@@ -65,7 +66,7 @@ module Isono
65
66
  end
66
67
 
67
68
  def node_id
68
- "#{@node_name}-#{@node_instance_id}"
69
+ "#{@node_name}.#{@node_instance_id}"
69
70
  end
70
71
 
71
72
  def config_path(path=nil)
@@ -79,18 +80,16 @@ module Isono
79
80
  end
80
81
  @config
81
82
  end
82
-
83
83
 
84
- private
85
84
  # load config file and merge up with the config tree.
86
85
  # it will not work when the config_path is nil or the file is missed
87
- def load_config
88
- if @config_path && File.exist?(@config_path)
89
- buf = File.read(@config_path)
90
- eval("#{buf}", binding, @config_path)
91
- end
86
+ def load_config(path)
87
+ return unless File.exist?(path)
88
+ buf = File.read(path)
89
+ eval("#{buf}", binding, path)
92
90
  end
93
91
 
92
+ private
94
93
  def resolve_abs_app_root(app_root_path)
95
94
  pt = Pathname.new(app_root_path)
96
95
  if pt.absolute?
@@ -12,6 +12,7 @@ module Isono
12
12
  include EventObservable
13
13
 
14
14
  def self.inherited(klass)
15
+ super
15
16
  klass.class_eval {
16
17
  include Logger
17
18
  }
@@ -66,46 +67,61 @@ module Isono
66
67
  manifest.node_id
67
68
  end
68
69
 
69
- def on_connect
70
+ def before_connect
70
71
  raise "node_id is not set" if node_id.nil?
71
72
 
72
- #amq.prefetch(1)
73
- identity_queue(node_id)
74
- init_modules
75
-
76
- fire_event(:node_ready, {:node_id=> self.node_id})
77
- logger.info("Started : AMQP Server=#{amqp_server_uri.to_s}, ID=#{node_id}, token=#{boot_token}")
78
- end
79
-
80
- def on_close
81
- term_modules
82
- end
73
+ @value_objects = {}
83
74
 
84
- private
85
-
86
- def init_modules
87
75
  manifest.node_modules.each { |modclass, *args|
88
76
  if !@value_objects.has_key?(modclass)
89
77
  @value_objects[modclass] = vo = ValueObject.new(self, modclass)
90
78
 
91
- if modclass.initialize_hook.is_a?(Proc)
92
- vo.instance_eval(&modclass.initialize_hook)
93
- end
94
-
95
- logger.debug("Initialized #{modclass.to_s}")
79
+ node_hook_proc(:before_connect).call(modclass, *args)
96
80
  end
97
81
  }
98
82
  end
99
83
 
100
- def term_modules
101
- manifest.node_modules.reverse.each { |modclass, *args|
84
+ def after_connect
85
+ setup_identity_queue
86
+
87
+ manifest.node_modules.each &node_hook_proc(:after_connect)
88
+ # TODO: remove initialize_hook
89
+ manifest.node_modules.each &node_hook_proc(:initialize)
90
+
91
+ logger.info("Started : AMQP Server=#{amqp_server_uri.to_s}, ID=#{node_id}, token=#{boot_token}")
92
+ end
93
+
94
+ def before_close
95
+ manifest.node_modules.reverse.each &node_hook_proc(:before_close)
96
+ # TODO: remove terminate_hook
97
+ manifest.node_modules.reverse.each &node_hook_proc(:terminate)
98
+ end
99
+
100
+ def after_close
101
+ manifest.node_modules.reverse.each &node_hook_proc(:after_close)
102
+ end
103
+
104
+ private
105
+
106
+ def node_hook_proc(hook)
107
+ proc { |modclass, *args|
108
+ node_hook = modclass.node_hooks[hook]
109
+ next unless node_hook.is_a?(Proc)
102
110
  vo = @value_objects[modclass]
103
- if vo && modclass.terminate_hook.is_a?(Proc)
104
- vo.instance_eval(&modclass.terminate_hook)
111
+ if vo
112
+ vo.instance_eval(&node_hook)
105
113
  end
106
- logger.info("Terminated #{modclass.to_s}")
107
114
  }
108
115
  end
116
+
117
+ def setup_identity_queue
118
+ amq = create_channel
119
+ amq.errback {
120
+ logger.error("The node has same node ID is running already")
121
+ exit(1)
122
+ }
123
+ amq.queue("ident.#{node_id}", {:exclusive=>true})
124
+ end
109
125
 
110
126
  class ValueObject
111
127
  module DelegateMethods