daemon-kit 0.1.7.10 → 0.1.7.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +5 -0
  2. data/Configuration.txt +8 -0
  3. data/History.txt +13 -1
  4. data/Logging.txt +4 -0
  5. data/Manifest.txt +7 -1
  6. data/PostInstall.txt +1 -1
  7. data/README.rdoc +9 -13
  8. data/Rakefile +22 -30
  9. data/TODO.txt +1 -10
  10. data/app_generators/daemon_kit/daemon_kit_generator.rb +18 -1
  11. data/app_generators/daemon_kit/templates/config/boot.rb +6 -15
  12. data/app_generators/daemon_kit/templates/config/environments/production.rb +3 -0
  13. data/bin/{daemon_kit → daemon-kit} +0 -0
  14. data/config/website.yml +2 -0
  15. data/daemon-kit.gemspec +264 -0
  16. data/daemon_generators/nanite_agent/templates/config/nanite.yml +2 -2
  17. data/daemon_generators/rspec/templates/spec/spec_helper.rb +3 -1
  18. data/daemon_generators/rspec/templates/tasks/rspec.rake +8 -10
  19. data/daemon_generators/test_unit/USAGE +5 -0
  20. data/daemon_generators/test_unit/templates/tasks/test_unit.rake +7 -0
  21. data/daemon_generators/test_unit/templates/test/test.rb +9 -0
  22. data/daemon_generators/test_unit/templates/test/test_helper.rb +6 -0
  23. data/daemon_generators/test_unit/test_unit_generator.rb +51 -0
  24. data/lib/daemon_kit.rb +9 -1
  25. data/lib/daemon_kit/abstract_logger.rb +6 -0
  26. data/lib/daemon_kit/application.rb +1 -0
  27. data/lib/daemon_kit/arguments.rb +5 -0
  28. data/lib/daemon_kit/error_handlers/hoptoad.rb +4 -4
  29. data/lib/daemon_kit/exceptions.rb +7 -0
  30. data/lib/daemon_kit/initializer.rb +25 -11
  31. data/lib/daemon_kit/nanite/agent.rb +26 -5
  32. data/lib/daemon_kit/ruote_workitem.rb +9 -1
  33. data/lib/daemon_kit/tasks/god.rake +1 -1
  34. data/lib/daemon_kit/xmpp.rb +31 -0
  35. data/tasks/cucumber.rake +13 -0
  36. data/tasks/tests.rake +6 -0
  37. data/templates/god/god.erb +2 -2
  38. data/test/test_ruote_generator.rb +8 -2
  39. data/test/test_test_unit_generator.rb +46 -0
  40. metadata +45 -36
@@ -17,8 +17,8 @@
17
17
  # * actors - Comma separated list of actors to load (all ruby files in actors directory by default)
18
18
 
19
19
  defaults: &defaults
20
- username: nanite
21
- password: testing
20
+ user: nanite
21
+ pass: testing
22
22
  host: localhost
23
23
  vhost: /nanite
24
24
  # tag:
@@ -1,3 +1,5 @@
1
+ DAEMON_ENV = 'test' unless defined?( DAEMON_ENV )
2
+
1
3
  begin
2
4
  require 'spec'
3
5
  rescue LoadError
@@ -15,7 +17,7 @@ Spec::Runner.configure do |config|
15
17
  # RSpec uses it's own mocking framework by default. If you prefer to
16
18
  # use mocha, flexmock or RR, uncomment the appropriate line:
17
19
  #
18
- config.mock_with :mocha
20
+ # config.mock_with :mocha
19
21
  # config.mock_with :flexmock
20
22
  # config.mock_with :rr
21
23
  end
@@ -1,21 +1,19 @@
1
1
  begin
2
2
  require 'spec'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'spec'
6
- end
7
- begin
8
3
  require 'spec/rake/spectask'
9
4
  rescue LoadError
10
5
  puts <<-EOS
11
6
  To use rspec for testing you must install rspec gem:
12
7
  gem install rspec
13
8
  EOS
14
- exit(0)
15
9
  end
16
10
 
17
- desc "Run the specs under spec/"
18
- Spec::Rake::SpecTask.new do |t|
19
- t.spec_opts = ['--options', "spec/spec.opts"]
20
- t.spec_files = FileList['spec/**/*_spec.rb']
11
+ begin
12
+ desc "Run the specs under spec/"
13
+ Spec::Rake::SpecTask.new do |t|
14
+ t.spec_opts = ['--options', "spec/spec.opts"]
15
+ t.spec_files = FileList['spec/**/*_spec.rb']
16
+ end
17
+ rescue NameError
18
+ # No loss, warning printed already
21
19
  end
@@ -0,0 +1,5 @@
1
+ Description:
2
+
3
+
4
+ Usage:
5
+
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << "test"
5
+ t.test_files = FileList['test/*_test.rb']
6
+ t.verbose = true
7
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class Test<%= module_name %> < Test::Unit::TestCase
4
+
5
+ def test_missing
6
+ assert false, "daemons should be tested"
7
+ end
8
+ end
9
+
@@ -0,0 +1,6 @@
1
+ DAEMON_ENV = 'test' unless defined?( DAEMON_ENV )
2
+
3
+ require 'test/unit'
4
+
5
+ require File.dirname(__FILE__) + '/../config/environment'
6
+ DaemonKit::Application.running!
@@ -0,0 +1,51 @@
1
+ class TestUnitGenerator < RubiGen::Base
2
+
3
+ attr_reader :gem_name, :module_name
4
+
5
+ def initialize(runtime_args, runtime_options = {})
6
+ super
7
+ @destination_root = File.expand_path(destination_root)
8
+ @gem_name = base_name
9
+ @module_name = @gem_name.camelcase
10
+ extract_options
11
+ end
12
+
13
+ def manifest
14
+ record do |m|
15
+ # Ensure appropriate folder(s) exists
16
+ m.directory 'test'
17
+ m.directory 'tasks'
18
+
19
+ m.template 'test/test.rb', "test/#{gem_name}_test.rb"
20
+ m.template_copy_each %w( test_helper.rb ), 'test'
21
+ m.file_copy_each %w( test_unit.rake ), 'tasks'
22
+ end
23
+ end
24
+
25
+ protected
26
+ def banner
27
+ <<-EOS
28
+ Creates a ...
29
+
30
+ USAGE: #{$0} #{spec.name} name
31
+ EOS
32
+ end
33
+
34
+ def add_options!(opts)
35
+ # opts.separator ''
36
+ # opts.separator 'Options:'
37
+ # For each option below, place the default
38
+ # at the top of the file next to "default_options"
39
+ # opts.on("-a", "--author=\"Your Name\"", String,
40
+ # "Some comment about this option",
41
+ # "Default: none") { |o| options[:author] = o }
42
+ # opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
43
+ end
44
+
45
+ def extract_options
46
+ # for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
47
+ # Templates can access these value via the attr_reader-generated methods, but not the
48
+ # raw instance variable value.
49
+ # @author = options[:author]
50
+ end
51
+ end
@@ -1,6 +1,14 @@
1
1
  # TODO: Strip this out eventually so we can run without rubygems
2
2
  require 'rubygems'
3
3
 
4
+ # Seems in 1.9 we need to load openssl before em or there is failures all around.
5
+ # But we need to consider that people might not have ssl in the first place.
6
+ if RUBY_VERSION >= "1.9"
7
+ begin
8
+ require 'openssl'
9
+ rescue LoadError
10
+ end
11
+ end
4
12
  require 'eventmachine'
5
13
 
6
14
  require File.dirname(__FILE__) + '/daemon_kit/core_ext'
@@ -10,7 +18,7 @@ $:.unshift( File.dirname(__FILE__).to_absolute_path ) unless
10
18
  $:.include?( File.dirname(__FILE__).to_absolute_path )
11
19
 
12
20
  module DaemonKit
13
- VERSION = '0.1.7.10'
21
+ VERSION = '0.1.7.11'
14
22
 
15
23
  autoload :Initializer, 'daemon_kit/initializer'
16
24
  autoload :Application, 'daemon_kit/application'
@@ -63,6 +63,12 @@ module DaemonKit
63
63
  end
64
64
  end
65
65
 
66
+ # Write unformatted message to logging device, mostly useful for Logger interface
67
+ # compatibility and debugging soap4r (possibly others)
68
+ def <<( msg ) #:nodoc:
69
+ self.logger.write( msg ) if self.logger && self.logger.respond_to?( :write )
70
+ end
71
+
66
72
  def debug( msg )
67
73
  add( :debug, msg )
68
74
  end
@@ -104,6 +104,7 @@ module DaemonKit
104
104
  protected
105
105
 
106
106
  def parse_arguments( args )
107
+ Arguments.parser_available = true
107
108
  DaemonKit.arguments = Arguments.new
108
109
  DaemonKit.arguments.parse( args )
109
110
  end
@@ -19,10 +19,15 @@ module DaemonKit
19
19
  'run'
20
20
  ]
21
21
 
22
+ # We don't parse arguments by default
23
+ @parser_available = false
24
+
22
25
  class << self
23
26
 
24
27
  attr_reader :default_command, :commands
25
28
 
29
+ attr_accessor :parser_available
30
+
26
31
  # Parse the argument values and return an array with the command
27
32
  # name, config values and argument values
28
33
  def parse( argv )
@@ -19,8 +19,8 @@ module DaemonKit
19
19
  data = clean_exception( exception )
20
20
 
21
21
  response = begin
22
- http.post( url.path, data.to_yaml, headers )
23
- rescue TimoutError => e
22
+ http.post( url.path, {"notice" => data}.to_yaml, headers )
23
+ rescue TimeoutError => e
24
24
  DaemonKit.logger.error("Timeout while contacting the Hoptoad server.")
25
25
  nil
26
26
  end
@@ -43,8 +43,8 @@ module DaemonKit
43
43
  :error_message => "#{exception.class.name}: #{exception.message}",
44
44
  :backtrace => exception.backtrace,
45
45
  :environment => ENV.to_hash,
46
- :request => [],
47
- :session => []
46
+ :request => {},
47
+ :session => {}
48
48
  }
49
49
 
50
50
  stringify_keys( data )
@@ -5,4 +5,11 @@ module DaemonKit
5
5
 
6
6
  # Raised when no class is registered to process a ruote workitem
7
7
  class MissingParticipant < Exception; end
8
+
9
+ # Raised when the daemon itself cannot be found.
10
+ class DaemonNotFound < Exception
11
+ def initialize( file )
12
+ super "No daemon found at the path '#{file}'"
13
+ end
14
+ end
8
15
  end
@@ -64,7 +64,7 @@ module DaemonKit
64
64
  initializer.after_daemonize
65
65
  end
66
66
 
67
- def self.shutdown( clean = false )
67
+ def self.shutdown( clean = false, do_exit = false )
68
68
  return unless $daemon_kit_shutdown_hooks_ran.nil?
69
69
  $daemon_kit_shutdown_hooks_ran = true
70
70
 
@@ -81,7 +81,8 @@ module DaemonKit
81
81
  log_exceptions if DaemonKit.configuration.backtraces && !clean
82
82
 
83
83
  DaemonKit.logger.warn "Shutting down #{DaemonKit.configuration.daemon_name}"
84
- exit
84
+
85
+ exit if do_exit
85
86
  end
86
87
 
87
88
  def initialize( configuration )
@@ -114,10 +115,10 @@ module DaemonKit
114
115
 
115
116
  if DaemonKit.configuration.user || DaemonKit.configuration.group
116
117
  euid = Process.euid
117
- egid = Process.egid
118
- uid = Process.uid
119
- gid = Process.gid
120
- DaemonKit.logger.info( "DaemonKit dropped privileges to: #{euid} (EUID), #{egid} (EGID), #{uid} (UID), #{gid} (GID)" )
118
+ egid = Process.egid
119
+ uid = Process.uid
120
+ gid = Process.gid
121
+ DaemonKit.logger.info( "DaemonKit dropped privileges to: #{euid} (EUID), #{egid} (EGID), #{uid} (UID), #{gid} (GID)" )
121
122
  end
122
123
  end
123
124
 
@@ -191,7 +192,8 @@ module DaemonKit
191
192
  end
192
193
 
193
194
  def initialize_signal_traps
194
- term_proc = Proc.new { DaemonKit::Initializer.shutdown( true ) }
195
+ # Only exit the process if we're not in the 'test' environment
196
+ term_proc = Proc.new { DaemonKit::Initializer.shutdown( true, DAEMON_ENV != 'test' ) }
195
197
  configuration.trap( 'INT', term_proc )
196
198
  configuration.trap( 'TERM', term_proc )
197
199
  at_exit { DaemonKit::Initializer.shutdown }
@@ -212,7 +214,7 @@ module DaemonKit
212
214
  end
213
215
 
214
216
  def self.log_exceptions
215
- trace_file = File.join( DaemonKit.root, "backtrace-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{Process.pid}.log" )
217
+ trace_file = File.join( DaemonKit.root, 'log', "backtrace-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{Process.pid}.log" )
216
218
  trace_log = Logger.new( trace_file )
217
219
 
218
220
  # Find the last exception
@@ -252,7 +254,7 @@ module DaemonKit
252
254
  attr_accessor :logger
253
255
 
254
256
  # The log level to use, defaults to DEBUG
255
- attr_accessor :log_level
257
+ attr_reader :log_level
256
258
 
257
259
  # Path to the log file, defaults to 'log/<environment>.log'
258
260
  configurable :log_path
@@ -286,7 +288,7 @@ module DaemonKit
286
288
 
287
289
  # Our safety net (#Safety) instance
288
290
  attr_accessor :safety_net
289
-
291
+
290
292
  # :nodoc: Shutdown hooks
291
293
  attr_reader :shutdown_hooks
292
294
 
@@ -326,6 +328,12 @@ module DaemonKit
326
328
  def trap( signal, proc = nil, &block )
327
329
  return if proc.nil? && !block_given?
328
330
 
331
+ # One step towards running on windows, not enough though
332
+ unless Signal.list.include?( signal )
333
+ DaemonKit.logger.warn( "Trapping #{signal} signals not supported on this platform" )
334
+ return
335
+ end
336
+
329
337
  unless @signal_traps.has_key?( signal )
330
338
  set_trap( signal )
331
339
  end
@@ -344,6 +352,12 @@ module DaemonKit
344
352
  @pid_file ||= "#{File.dirname(self.log_path)}/#{self.daemon_name}.pid"
345
353
  end
346
354
 
355
+ # Set the log level
356
+ def log_level=( level )
357
+ @log_level = level
358
+ DaemonKit.logger.level = @log_level if DaemonKit.logger
359
+ end
360
+
347
361
  protected
348
362
 
349
363
  def run_traps( signal )
@@ -430,7 +444,7 @@ module DaemonKit
430
444
  # arguments to be parsed cause they will interfere with the
431
445
  # script encapsulating DaemonKit, like capistrano
432
446
  def own_args?
433
- ![ 'cap' ].include?( File.basename( $0 ) )
447
+ Arguments.parser_available
434
448
  end
435
449
  end
436
450
 
@@ -1,3 +1,24 @@
1
+ module Nanite
2
+ class Agent
3
+
4
+ attr_accessor :init_block
5
+
6
+ def load_actors_with_daemon_kit_changes( &block )
7
+ actors = @options[:actors]
8
+ Dir["#{DaemonKit.root}/lib/actors/*.rb"].each do |actor|
9
+ next if actors && !actors.include?( File.basename(actor, '.rb') )
10
+ Nanite::Log.info( "[setup] loading #{actor}" )
11
+ require actor
12
+ end
13
+
14
+ self.init_block.call( self )
15
+ end
16
+
17
+ alias_method :load_actors_without_daemon_kit_changes, :load_actors
18
+ alias_method :load_actors, :load_actors_with_daemon_kit_changes
19
+ end
20
+ end
21
+
1
22
  module DaemonKit
2
23
  module Nanite
3
24
  # Pull support into a daemon for being a nanite agent.
@@ -29,22 +50,22 @@ module DaemonKit
29
50
  # Ensure graceful shutdown of the connection to the broker
30
51
  DaemonKit.trap('INT') { ::EM.stop }
31
52
  DaemonKit.trap('TERM') { ::EM.stop }
53
+ ::Nanite::Log.logger = DaemonKit.logger
32
54
 
33
55
  # Start our mapper
34
56
  mapper_thread = Thread.new do
35
57
  EM.run do
36
- agent = ::Nanite.start_agent( @config )
37
- block.call( agent ) if block
58
+ agent = ::Nanite::Agent.new( @config )
59
+ agent.init_block = block
60
+ agent.run
38
61
  end
39
62
  end
40
63
 
41
- #block.call if block
42
-
43
64
  mapper_thread.join
44
65
  end
45
66
 
46
67
  private
47
-
68
+
48
69
  # Make sure to fine tune the agent config to be DK friendly
49
70
  def config_agent
50
71
  @config[:root] = DAEMON_ROOT
@@ -42,6 +42,9 @@ module DaemonKit
42
42
 
43
43
  work = parse( workitem )
44
44
 
45
+ # Invalid JSON... mmm
46
+ return if work.nil?
47
+
45
48
  DaemonKit.logger.warn "Processing workitem that has timed out!" if work.timed_out?
46
49
 
47
50
  target, method = parse_command( work )
@@ -94,7 +97,12 @@ module DaemonKit
94
97
  end
95
98
 
96
99
  def parse( workitem )
97
- new( JSON.parse( workitem ) )
100
+ begin
101
+ return new( JSON.parse( workitem ) )
102
+ rescue JSON::ParserError => e
103
+ DaemonKit.logger.error "No valid JSON payload found in #{workitem}"
104
+ return nil
105
+ end
98
106
  end
99
107
  end
100
108
 
@@ -26,7 +26,7 @@ namespace :god do
26
26
  f.write( ERB.new( t ).result( binding ) )
27
27
  end
28
28
 
29
- puts "Monit config generated in config/#{name}.god"
29
+ puts "god config generated in config/#{name}.god"
30
30
  end
31
31
 
32
32
  desc "Load the god file into god"
@@ -0,0 +1,31 @@
1
+ module DaemonKit
2
+ # Thin wrapper around the blather DSL
3
+ class XMPP
4
+ include ::Blather::DSL
5
+
6
+ class << self
7
+
8
+ def run( &block )
9
+ DaemonKit::EM.run
10
+
11
+ xmpp = new
12
+
13
+ xmpp.instance_eval( &block )
14
+
15
+ xmpp.run
16
+ end
17
+ end
18
+
19
+ def initialize
20
+ @config = DaemonKit::Config.load('jabber')
21
+
22
+ jid = if @config.resource
23
+ "#{@config.jabber_id}/#{@config.resource}"
24
+ else
25
+ @config.jabber_id
26
+ end
27
+
28
+ setup jid, @config.password
29
+ end
30
+ end
31
+ end