em-langrove 0.0.4.5
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.
- data/.rspec +1 -0
- data/.rvmrc +62 -0
- data/.watchr +27 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +61 -0
- data/Rakefile +24 -0
- data/bin/langrove +3 -0
- data/functional/config/boot.rb +64 -0
- data/functional/config/daemons.yml +13 -0
- data/functional/config/environment.rb +28 -0
- data/functional/config/environments/development.rb +0 -0
- data/functional/config/environments/production.rb +0 -0
- data/functional/config/environments/test.rb +0 -0
- data/functional/lib/client/socket_to_file.rb +47 -0
- data/functional/lib/daemon/datagram.rb +21 -0
- data/functional/lib/protocol/socket_to_file.rb +55 -0
- data/functional/libexec/daemon.rb +68 -0
- data/functional/tmp/README +1 -0
- data/lib/langrove/_base.rb +28 -0
- data/lib/langrove/adaptor/base.rb +2 -0
- data/lib/langrove/adaptor_base.rb +116 -0
- data/lib/langrove/client/base.rb +2 -0
- data/lib/langrove/client/datagram.rb +25 -0
- data/lib/langrove/client_base.rb +92 -0
- data/lib/langrove/daemon/base.rb +2 -0
- data/lib/langrove/daemon_base.rb +281 -0
- data/lib/langrove/ext/class_loader.rb +148 -0
- data/lib/langrove/ext/config_item.rb +34 -0
- data/lib/langrove/ext/config_loader.rb +16 -0
- data/lib/langrove/ext/fake_logger.rb +8 -0
- data/lib/langrove/ext/find.rb +90 -0
- data/lib/langrove/ext/persistable.rb +103 -0
- data/lib/langrove/ext/string.rb +35 -0
- data/lib/langrove/ext.rb +7 -0
- data/lib/langrove/handler/base.rb +2 -0
- data/lib/langrove/handler_base.rb +148 -0
- data/lib/langrove/job/base.rb +1 -0
- data/lib/langrove/job_base.rb +24 -0
- data/lib/langrove/protocol/base.rb +2 -0
- data/lib/langrove/protocol/syslog.rb +32 -0
- data/lib/langrove/protocol_base.rb +32 -0
- data/lib/langrove/version.rb +3 -0
- data/lib/langrove.rb +1 -0
- data/spec/functional/daemon/datagram_spec.rb +121 -0
- data/spec/langrove/adaptor_base_spec.rb +63 -0
- data/spec/langrove/client/datagram_spec.rb +1 -0
- data/spec/langrove/client_base_spec.rb +5 -0
- data/spec/langrove/daemon_base_spec.rb +154 -0
- data/spec/langrove/ext/class_loader_spec.rb +83 -0
- data/spec/langrove/ext/config_item_spec.rb +81 -0
- data/spec/langrove/ext/config_loader_spec.rb +5 -0
- data/spec/langrove/ext/fake_logger_spec.rb +0 -0
- data/spec/langrove/ext/find_spec.rb +53 -0
- data/spec/langrove/ext/persistable_spec.rb +117 -0
- data/spec/langrove/ext/string_spec.rb +16 -0
- data/spec/langrove/handler_base_spec.rb +103 -0
- data/spec/langrove/job_base_spec.rb +28 -0
- data/spec/langrove/protocol/syslog_spec.rb +45 -0
- data/spec/langrove/protocol_base_spec.rb +6 -0
- data/spec/todo_spec.rb +12 -0
- data/tmp/README +2 -0
- metadata +203 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'resque'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# require 'updated_puppet_state'
|
5
|
+
|
6
|
+
module LanGrove class Persistable
|
7
|
+
|
8
|
+
def initialize( notifies = [] )
|
9
|
+
|
10
|
+
@notifies = notifies
|
11
|
+
|
12
|
+
@notifies.each do |worker|
|
13
|
+
|
14
|
+
Object.const_set(
|
15
|
+
|
16
|
+
worker.camelize, Class.new
|
17
|
+
|
18
|
+
) ### ??unless defined already??
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_hash( hash_instance, from_file )
|
25
|
+
#
|
26
|
+
# <hash_instance> as String (name of) variable storing the Hash
|
27
|
+
#
|
28
|
+
|
29
|
+
@logger.debug "loading from: #{from_file}" if @logger
|
30
|
+
|
31
|
+
#
|
32
|
+
# get the instance variable (late bind)
|
33
|
+
#
|
34
|
+
hash = self.instance_variable_get( hash_instance.to_sym )
|
35
|
+
hash ||= {}
|
36
|
+
|
37
|
+
begin
|
38
|
+
|
39
|
+
#
|
40
|
+
# load file contents, merge into hash and
|
41
|
+
# store it at the instance variable
|
42
|
+
#
|
43
|
+
persisted = YAML.load_file( from_file )
|
44
|
+
hash.merge!( persisted ) if persisted.is_a?( Hash )
|
45
|
+
self.instance_variable_set( hash_instance.to_sym, hash )
|
46
|
+
|
47
|
+
#
|
48
|
+
# set flag to 'already in storage'
|
49
|
+
#
|
50
|
+
@stored = true
|
51
|
+
|
52
|
+
rescue Exception => e
|
53
|
+
@logger.error "FAILED loading from #{from_file} #{e}" if @logger
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def store_hash( hash_instance, to_file )
|
60
|
+
#
|
61
|
+
# <hash_instance> as String (name of) variable storing the Hash
|
62
|
+
#
|
63
|
+
|
64
|
+
if @stored != nil && @stored
|
65
|
+
|
66
|
+
@logger.debug "storing to: #{to_file} skipped - no change"
|
67
|
+
return
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
@logger.debug "storing to: #{to_file}"
|
72
|
+
|
73
|
+
#
|
74
|
+
# get the instance variable (late bind)
|
75
|
+
#
|
76
|
+
hash = self.instance_variable_get( hash_instance.to_sym )
|
77
|
+
|
78
|
+
begin
|
79
|
+
|
80
|
+
File.open(to_file, 'w') do |f|
|
81
|
+
|
82
|
+
YAML::dump( hash, f )
|
83
|
+
@stored = true
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
#@notifies.each do |worker|
|
88
|
+
#
|
89
|
+
# Resque.enqueue(
|
90
|
+
#
|
91
|
+
# Object.const_get( worker.camelize ), to_file
|
92
|
+
#
|
93
|
+
# )
|
94
|
+
#
|
95
|
+
#end
|
96
|
+
|
97
|
+
rescue Exception => e
|
98
|
+
@logger.error "FAILED storing to: #{to_file} #{e}" if @logger
|
99
|
+
@stored = false
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end; end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# extend ruby String class
|
2
|
+
|
3
|
+
class String
|
4
|
+
#
|
5
|
+
# from the rails inflector
|
6
|
+
# (de-camelize)
|
7
|
+
#
|
8
|
+
# ie. CamelThing becomes camel_thing
|
9
|
+
#
|
10
|
+
def underscore
|
11
|
+
gsub(/::/, '/').
|
12
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
13
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
14
|
+
tr("-", "_").
|
15
|
+
downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# unless already defined
|
20
|
+
#
|
21
|
+
end unless String.method_defined?(:underscore)
|
22
|
+
|
23
|
+
class String
|
24
|
+
#
|
25
|
+
# from the rails inflector
|
26
|
+
# (camelize)
|
27
|
+
#
|
28
|
+
# ie. CamelThing becomes camel_thing
|
29
|
+
#
|
30
|
+
def camelize(first_letter_in_uppercase = :upper)
|
31
|
+
s = gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
32
|
+
s[0...1] = s[0...1].downcase unless first_letter_in_uppercase == :upper
|
33
|
+
s
|
34
|
+
end
|
35
|
+
end unless String.method_defined?(:camelize)
|
data/lib/langrove/ext.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'langrove'
|
2
|
+
|
3
|
+
module LanGrove::Handler class Base
|
4
|
+
|
5
|
+
#
|
6
|
+
# One handler exists in the daemon with
|
7
|
+
# the primary purpose of housing through
|
8
|
+
# an addressable Hash the set of connected
|
9
|
+
# clients,
|
10
|
+
#
|
11
|
+
# In this:
|
12
|
+
#
|
13
|
+
# but, NOT YET
|
14
|
+
#
|
15
|
+
attr_writer :clients
|
16
|
+
|
17
|
+
#
|
18
|
+
# The protocol defininition per the config is
|
19
|
+
# loaded by this Handler, but not instanciated.
|
20
|
+
#
|
21
|
+
# This definition is then exposed,
|
22
|
+
#
|
23
|
+
# By this:
|
24
|
+
#
|
25
|
+
attr_reader :protocol
|
26
|
+
|
27
|
+
def start_daemon
|
28
|
+
|
29
|
+
#
|
30
|
+
# OVERRIDE
|
31
|
+
#
|
32
|
+
# To prepare the Handler in any necessary
|
33
|
+
# ways before the thread is handed over to
|
34
|
+
# the socket listener, (or thing),
|
35
|
+
#
|
36
|
+
# The daemon has just started.
|
37
|
+
#
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop_daemon
|
42
|
+
|
43
|
+
#
|
44
|
+
# OVERRIDE
|
45
|
+
#
|
46
|
+
# To perfom any necessties before process
|
47
|
+
# termination,
|
48
|
+
#
|
49
|
+
# The daemon has received a signal to stop.
|
50
|
+
#
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def periodic
|
55
|
+
|
56
|
+
#
|
57
|
+
# Call periodic on all clients
|
58
|
+
# in the collection
|
59
|
+
#
|
60
|
+
|
61
|
+
@clients.each do |key, value|
|
62
|
+
|
63
|
+
if value == 1 then
|
64
|
+
|
65
|
+
key.periodic
|
66
|
+
|
67
|
+
next
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
value.periodic
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def connect( client )
|
78
|
+
|
79
|
+
#
|
80
|
+
# A client has connected at the Adaptor
|
81
|
+
#
|
82
|
+
# It should be inserted into the collection
|
83
|
+
# of clients maintained here.
|
84
|
+
#
|
85
|
+
@logger.debug "Client::#{client} registers with Handler#{self}"
|
86
|
+
|
87
|
+
if client.respond_to?( :unique_key ) then
|
88
|
+
|
89
|
+
@clients[ client.unique_key ] = client
|
90
|
+
return
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
@clients[ client ] = 1
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
def disconnect( client )
|
99
|
+
|
100
|
+
#
|
101
|
+
# A client has disconnected
|
102
|
+
#
|
103
|
+
# It should be removed from the collection.
|
104
|
+
#
|
105
|
+
|
106
|
+
#
|
107
|
+
# TODO: There will likely be a callback
|
108
|
+
# in the EM::Connection superclass
|
109
|
+
# that can be used here.
|
110
|
+
#
|
111
|
+
# Client::Base extends EM::Connection
|
112
|
+
#
|
113
|
+
|
114
|
+
@logger.info( "TODO: implement #{self.classname}disconnect()" )
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def initialize( config_hash, daemon_name, logger )
|
119
|
+
|
120
|
+
@config = config_hash
|
121
|
+
@daemon_name = daemon_name
|
122
|
+
@logger = logger
|
123
|
+
|
124
|
+
@clients = {}
|
125
|
+
|
126
|
+
begin
|
127
|
+
|
128
|
+
@logger.info "TODO: fall back to default Handler::Base"
|
129
|
+
|
130
|
+
@my_config = @config[ :daemons ][ @daemon_name ][ :handler ]
|
131
|
+
|
132
|
+
rescue
|
133
|
+
|
134
|
+
error = "Missing config item for daemon: #{@daemon_name}"
|
135
|
+
|
136
|
+
@logger.error "EXIT: #{error}"
|
137
|
+
|
138
|
+
raise LanGrove::DaemonConfigException.new(
|
139
|
+
|
140
|
+
"Missing config item for daemon: #{@daemon_name}"
|
141
|
+
|
142
|
+
)
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end; end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'langrove/job_base'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# no spec
|
3
|
+
#
|
4
|
+
module LanGrove
|
5
|
+
|
6
|
+
module Job
|
7
|
+
|
8
|
+
class Base
|
9
|
+
|
10
|
+
def initialize( config, queue_name, logger)
|
11
|
+
|
12
|
+
logger.info ( "starting unimplemented queuer") unless logger.nil?
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing( symbol, *args, &block )
|
17
|
+
puts "#{self}.#{symbol}( #{args} )" unless @parameter == :silent
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'langrove'
|
3
|
+
|
4
|
+
module LanGrove::Protocol class Syslog
|
5
|
+
|
6
|
+
def decode( message )
|
7
|
+
|
8
|
+
#
|
9
|
+
# eg:
|
10
|
+
#
|
11
|
+
# <NN>Apr 4 11:00:06 fw.school1950.gp-online.net puppet[29206]: Autoloaded file blahblahblah
|
12
|
+
#
|
13
|
+
|
14
|
+
pass = message.split('>')[1].split()
|
15
|
+
time = DateTime.parse(pass[0..2].join(' '))
|
16
|
+
hostname = pass[3]
|
17
|
+
message = pass[4..-1].join(' ').split(': ',2)
|
18
|
+
|
19
|
+
hostname.gsub!( /vlan[\d]*\./, '')
|
20
|
+
|
21
|
+
@decoded = {
|
22
|
+
:timestamp => time, # DateTime object
|
23
|
+
:hostname => hostname, # without prepended vlanN
|
24
|
+
:tag => message[0], # includes[PID]
|
25
|
+
:event => message[1] # everything after the colon after the tag
|
26
|
+
}
|
27
|
+
|
28
|
+
return @decoded
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end; end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'langrove'
|
2
|
+
|
3
|
+
module LanGrove::Protocol
|
4
|
+
|
5
|
+
class Base
|
6
|
+
|
7
|
+
def initialize( place_mark_protocol_config, logger )
|
8
|
+
|
9
|
+
@logger = logger
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def decode( data )
|
14
|
+
|
15
|
+
#
|
16
|
+
# OVERRIDE
|
17
|
+
#
|
18
|
+
# To decode the data ahead of passing it
|
19
|
+
# into the <Handler>.receive() function.
|
20
|
+
#
|
21
|
+
|
22
|
+
{
|
23
|
+
|
24
|
+
:data => data
|
25
|
+
|
26
|
+
}
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/langrove.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'langrove/_base'
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'langrove'
|
2
|
+
|
3
|
+
describe 'A daemon' do
|
4
|
+
|
5
|
+
#
|
6
|
+
# HINT: tail -f functional/log/development.log
|
7
|
+
#
|
8
|
+
# To see this test in action.
|
9
|
+
#
|
10
|
+
|
11
|
+
#
|
12
|
+
# Use the demos in ./functional dir for integration tests
|
13
|
+
#
|
14
|
+
# Note: This uses the init.d style start|stop functionality
|
15
|
+
# as provided by DaemonKit
|
16
|
+
#
|
17
|
+
# Therefore, bugs that may exist in DaemonKit could be
|
18
|
+
# exposed here.
|
19
|
+
#
|
20
|
+
# I have not directly ovbserved any thus far.
|
21
|
+
#
|
22
|
+
|
23
|
+
before :all do
|
24
|
+
|
25
|
+
@daemon_name = 'datagram'
|
26
|
+
|
27
|
+
#
|
28
|
+
# cd - to get the rvm environment up
|
29
|
+
#
|
30
|
+
@daemon_root = File.expand_path("../../../../functional", __FILE__)
|
31
|
+
@daemon_stub = "./bin/#{@daemon_name}"
|
32
|
+
|
33
|
+
#
|
34
|
+
# Daemon is configured with Handler::SocketToFile
|
35
|
+
#
|
36
|
+
# The test sends a message to the daemon and then
|
37
|
+
# verifies the presence of the file.
|
38
|
+
#
|
39
|
+
@file = "#{@daemon_root}/tmp/datagram.txt"
|
40
|
+
@mesg = "Hello Datagram To File"
|
41
|
+
|
42
|
+
#
|
43
|
+
# remove the file ahead of testing
|
44
|
+
#
|
45
|
+
`rm -f #{@file}`
|
46
|
+
|
47
|
+
#
|
48
|
+
# call shell to start daemon
|
49
|
+
#
|
50
|
+
|
51
|
+
`cd #{@daemon_root} && #{@daemon_stub} start`
|
52
|
+
|
53
|
+
#
|
54
|
+
# give it a moment to start
|
55
|
+
#
|
56
|
+
sleep 1
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
after :all do
|
61
|
+
|
62
|
+
#
|
63
|
+
# call shell to stop daemon
|
64
|
+
#
|
65
|
+
`cd #{@daemon_root} && #{@daemon_stub} stop`
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'running a server' do
|
70
|
+
|
71
|
+
it 'receives a message' do
|
72
|
+
|
73
|
+
require "eventmachine"
|
74
|
+
|
75
|
+
class Sender < EventMachine::Connection
|
76
|
+
|
77
|
+
def send( data )
|
78
|
+
|
79
|
+
send_datagram( data, '127.0.0.1', 12701 )
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
EM.run do
|
86
|
+
|
87
|
+
sender = nil
|
88
|
+
|
89
|
+
EM.add_periodic_timer(1) do
|
90
|
+
|
91
|
+
sender.send( "#{@file}|#{@mesg}" )
|
92
|
+
EM.stop
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
EM.open_datagram_socket "127.0.0.1", 0, Sender do |connected|
|
97
|
+
|
98
|
+
sender = connected
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Give the daemon a moment to write the file
|
106
|
+
#
|
107
|
+
sleep 1
|
108
|
+
|
109
|
+
File.file?( @file ).should == true
|
110
|
+
|
111
|
+
File.open( @file, 'r' ).each_line do |line|
|
112
|
+
|
113
|
+
line.should == @mesg
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'langrove'
|
2
|
+
|
3
|
+
describe LanGrove::Adaptor::Base do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
|
7
|
+
@logger = LanGrove::FakeLogger.new
|
8
|
+
|
9
|
+
@extendhandler = 'ExtendedHandler'
|
10
|
+
|
11
|
+
@config = {
|
12
|
+
|
13
|
+
:iface => '111.111.111.111',
|
14
|
+
|
15
|
+
:port => 11111,
|
16
|
+
|
17
|
+
:connector => @extendhandler,
|
18
|
+
|
19
|
+
:transport => 'udp'
|
20
|
+
}
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
it 'assigns the session layer protocol as udp' do
|
27
|
+
|
28
|
+
subject = LanGrove::Adaptor::Base.new( @config, @logger )
|
29
|
+
subject.instance_variable_get( :@em_server_call ).should == :open_datagram_socket
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'assigns the session layer protocol as tcp by default' do
|
34
|
+
|
35
|
+
@config.delete :transport
|
36
|
+
|
37
|
+
subject = LanGrove::Adaptor::Base.new( @config, @logger )
|
38
|
+
|
39
|
+
subject.instance_variable_get( :@em_server_call ).should == :start_server
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
pending 'may need to override default connection handler' do
|
44
|
+
|
45
|
+
LanGrove::Adaptor.const_set( @extendhandler, Class.new )
|
46
|
+
|
47
|
+
subject = LanGrove::Adaptor::Base.new( @config, @logger )
|
48
|
+
connector = subject.instance_variable_get( :@handler )
|
49
|
+
|
50
|
+
connector.should == LanGrove::Adaptor.const_get( @extendhandler )
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
pending 'assigns defaults' do
|
55
|
+
|
56
|
+
subject = LanGrove::Adaptor::Base.new( {}, @logger )
|
57
|
+
connector = subject.instance_variable_get( :@connector )
|
58
|
+
|
59
|
+
connector.should == LanGrove::Adaptor::SocketHandler
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'langrove/client/datagram'
|