daemon-kit 0.1.7.10 → 0.1.7.11

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.
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