langrove 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.rspec +1 -0
  2. data/.rvmrc +62 -0
  3. data/.watchr +27 -0
  4. data/Gemfile +16 -0
  5. data/Gemfile.lock +61 -0
  6. data/Rakefile +24 -0
  7. data/functional/.gitignore +1 -0
  8. data/functional/bin/datagram +6 -0
  9. data/functional/config/.gitignore +0 -0
  10. data/functional/config/boot.rb +64 -0
  11. data/functional/config/daemons.yml +12 -0
  12. data/functional/config/environment.rb +28 -0
  13. data/functional/config/environments/development.rb +0 -0
  14. data/functional/config/environments/production.rb +0 -0
  15. data/functional/config/environments/test.rb +0 -0
  16. data/functional/lib/daemon/datagram.rb +21 -0
  17. data/functional/lib/handler/socket_to_file.rb +36 -0
  18. data/functional/lib/protocol/socket_to_file.rb +55 -0
  19. data/functional/libexec/daemon.rb +68 -0
  20. data/functional/log/.gitignore +3 -0
  21. data/functional/tmp/README +1 -0
  22. data/lib/langrove/_base.rb +26 -0
  23. data/lib/langrove/adaptor/base.rb +3 -0
  24. data/lib/langrove/adaptor/datagram.rb +27 -0
  25. data/lib/langrove/adaptor_base.rb +89 -0
  26. data/lib/langrove/client/base.rb +2 -0
  27. data/lib/langrove/client/datagram.rb +25 -0
  28. data/lib/langrove/client_base.rb +114 -0
  29. data/lib/langrove/daemon/base.rb +2 -0
  30. data/lib/langrove/daemon_base.rb +175 -0
  31. data/lib/langrove/ext/class_loader.rb +148 -0
  32. data/lib/langrove/ext/config_item.rb +34 -0
  33. data/lib/langrove/ext/config_loader.rb +16 -0
  34. data/lib/langrove/ext/fake_logger.rb +8 -0
  35. data/lib/langrove/ext/persistable.rb +103 -0
  36. data/lib/langrove/ext/string.rb +35 -0
  37. data/lib/langrove/ext.rb +7 -0
  38. data/lib/langrove/handler/base.rb +2 -0
  39. data/lib/langrove/handler_base.rb +141 -0
  40. data/lib/langrove/protocol/base.rb +2 -0
  41. data/lib/langrove/protocol/syslog.rb +32 -0
  42. data/lib/langrove/protocol_base.rb +32 -0
  43. data/lib/langrove/version.rb +3 -0
  44. data/lib/langrove.rb +1 -0
  45. data/spec/functional/daemon/datagram_spec.rb +115 -0
  46. data/spec/langrove/adaptor/datagram_spec.rb +6 -0
  47. data/spec/langrove/adaptor_base_spec.rb +48 -0
  48. data/spec/langrove/client/datagram_spec.rb +1 -0
  49. data/spec/langrove/client_base_spec.rb +5 -0
  50. data/spec/langrove/daemon_base_spec.rb +101 -0
  51. data/spec/langrove/ext/class_loader_spec.rb +83 -0
  52. data/spec/langrove/ext/config_item_spec.rb +81 -0
  53. data/spec/langrove/ext/config_loader_spec.rb +5 -0
  54. data/spec/langrove/ext/fake_logger_spec.rb +0 -0
  55. data/spec/langrove/ext/persistable_spec.rb +117 -0
  56. data/spec/langrove/ext/string_spec.rb +16 -0
  57. data/spec/langrove/handler_base_spec.rb +57 -0
  58. data/spec/langrove/protocol/syslog_spec.rb +45 -0
  59. data/spec/langrove/protocol_base_spec.rb +6 -0
  60. data/spec/todo_spec.rb +12 -0
  61. data/tmp/README +2 -0
  62. metadata +200 -0
@@ -0,0 +1,141 @@
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 daemon_start
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 daemon_stop
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
+ # TODO: There shall not only be one
58
+ #
59
+ # Changes are pending.
60
+ #
61
+ # OVERRIDE
62
+ #
63
+ # To perform activities at the interval
64
+ # defined in the config.
65
+ #
66
+
67
+ end
68
+
69
+ def initialize( config_hash, daemon_name, logger )
70
+
71
+ @config = config_hash
72
+ @daemon_name = daemon_name
73
+ @logger = logger
74
+
75
+ @my_config = @config[ :daemons ][ @daemon_name ][ :handler ]
76
+
77
+ protocol = 'Base'
78
+
79
+ if @my_config.has_key? :protocol then
80
+
81
+ protocol = @my_config[ :protocol ]
82
+
83
+ end
84
+
85
+ #
86
+ # SIGNIFICANT DECISION
87
+ #
88
+ # - (currently) - There is one >>Instance<< of the protocol
89
+ #
90
+ # - It is an object ( has .new )
91
+ #
92
+ # - All attached socket traffic is directed through it for de/encode
93
+ # -
94
+ # - ?.. ie. multiple TcpClients all routing through the same object..?
95
+ # -
96
+ # - THIS MAY NEED TO CHANGE (thinks & thinks & thinks)
97
+ #
98
+ # - (Thinks) - It may move to the Client::Base so that each attached
99
+ # client is paired with its own instance of the protocol.
100
+ #
101
+ # - For now it wil be instanciated here and binded to each client at
102
+ # connect - to be shared for the decoding. That should be fine for
103
+ # as long as the protocol itself stores no state and is simply a
104
+ # code path (Still, thinks & ...
105
+ #
106
+
107
+ #
108
+ # initialize the protocol specified in config
109
+ #
110
+ # daemons:
111
+ #
112
+ # viking-invasion-early-warning-net_CoreHub_co_uk-D4RK1:
113
+ #
114
+ # adaptor:
115
+ # connection: TriFocalOcularRotisserie
116
+ # lightsource:
117
+ # type: Fire
118
+ # fuel: Peat
119
+ #
120
+ # handler:
121
+ # collection: ScottishCoastalVillages
122
+ # protocol: MedievalLanternMorse <----------
123
+ #
124
+ # Note: This is the application layer protocol
125
+ # and is therefore entirely agnostic of
126
+ # transport and disassociated from the
127
+ # adapter in use.
128
+ #
129
+
130
+ @logger.info "Load definition: Protocol::#{protocol}"
131
+
132
+ @protocol = LanGrove::ClassLoader.create( {
133
+
134
+ :module => 'Protocol',
135
+ :class => protocol
136
+
137
+ } )
138
+
139
+ end
140
+
141
+ end; end
@@ -0,0 +1,2 @@
1
+ module LanGrove::Protocol; end
2
+ require 'langrove/protocol_base'
@@ -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
@@ -0,0 +1,3 @@
1
+ module LanGrove
2
+ Version = VERSION = '0.0.2'
3
+ end
data/lib/langrove.rb ADDED
@@ -0,0 +1 @@
1
+ require 'langrove/_base'
@@ -0,0 +1,115 @@
1
+ require 'langrove'
2
+
3
+ describe 'A daemon' do
4
+
5
+ #
6
+ # Use the demos in ./functional dir for integration tests
7
+ #
8
+ # Note: This uses the init.d style start|stop functionality
9
+ # as provided by DaemonKit
10
+ #
11
+ # Therefore, bugs that may exist in DaemonKit could be
12
+ # exposed here.
13
+ #
14
+ # I have not directly ovbserved any thus far.
15
+ #
16
+
17
+ before :all do
18
+
19
+ @daemon_name = 'datagram'
20
+
21
+ #
22
+ # cd - to get the rvm environment up
23
+ #
24
+ @daemon_root = File.expand_path("../../../../functional", __FILE__)
25
+ @daemon_stub = "./bin/#{@daemon_name}"
26
+
27
+ #
28
+ # Daemon is configured with Handler::SocketToFile
29
+ #
30
+ # The test sends a message to the daemon and then
31
+ # verifies the presence of the file.
32
+ #
33
+ @file = "#{@daemon_root}/tmp/datagram.txt"
34
+ @mesg = "Hello Datagram To File"
35
+
36
+ #
37
+ # remove the file ahead of testing
38
+ #
39
+ `rm -f #{@file}`
40
+
41
+ #
42
+ # call shell to start daemon
43
+ #
44
+
45
+ `cd #{@daemon_root} && #{@daemon_stub} start`
46
+
47
+ #
48
+ # give it a moment to start
49
+ #
50
+ sleep 1
51
+
52
+ end
53
+
54
+ after :all do
55
+
56
+ #
57
+ # call shell to stop daemon
58
+ #
59
+ `cd #{@daemon_root} && #{@daemon_stub} stop`
60
+
61
+ end
62
+
63
+ context 'running a server' do
64
+
65
+ it 'receives a message' do
66
+
67
+ require "eventmachine"
68
+
69
+ class Sender < EventMachine::Connection
70
+
71
+ def send( data )
72
+
73
+ send_datagram( data, '127.0.0.1', 12701 )
74
+
75
+ end
76
+
77
+ end
78
+
79
+ EM.run do
80
+
81
+ sender = nil
82
+
83
+ EM.add_periodic_timer(1) do
84
+
85
+ sender.send( "#{@file}|#{@mesg}" )
86
+ EM.stop
87
+
88
+ end
89
+
90
+ EM.open_datagram_socket "127.0.0.1", 0, Sender do |connected|
91
+
92
+ sender = connected
93
+
94
+ end
95
+
96
+ end
97
+
98
+ #
99
+ # Give the daemon a moment to write the file
100
+ #
101
+ sleep 1
102
+
103
+ File.file?( @file ).should == true
104
+
105
+ File.open( @file, 'r' ).each_line do |line|
106
+
107
+ line.should == @mesg
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,6 @@
1
+ require 'langrove'
2
+
3
+ describe LanGrove::Adaptor::Datagram do
4
+
5
+
6
+ end
@@ -0,0 +1,48 @@
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
+ :client => {
20
+
21
+ :class => 'Base'
22
+
23
+ }
24
+ }
25
+
26
+ end
27
+
28
+ pending 'may need to override default connection handler' do
29
+
30
+ LanGrove::Adaptor.const_set( @extendhandler, Class.new )
31
+
32
+ subject = LanGrove::Adaptor::Base.new( @config, @logger )
33
+ connector = subject.instance_variable_get( :@handler )
34
+
35
+ connector.should be_a( LanGrove::Adaptor.const_get( @extendhandler ) )
36
+
37
+ end
38
+
39
+ pending 'assigns defaults' do
40
+
41
+ subject = LanGrove::Adaptor::Base.new( {}, @logger )
42
+ connector = subject.instance_variable_get( :@connector )
43
+
44
+ connector.should == LanGrove::Adaptor::SocketHandler
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1 @@
1
+ require 'langrove/client/datagram'
@@ -0,0 +1,5 @@
1
+ require 'langrove'
2
+
3
+ describe LanGrove::Client::Base do
4
+
5
+ end
@@ -0,0 +1,101 @@
1
+ require 'langrove'
2
+
3
+ describe LanGrove::Daemon::Base do
4
+
5
+ before :each do
6
+
7
+ @logger = LanGrove::FakeLogger.new :silent
8
+
9
+ @daemon_name = 'pretend_daemon'
10
+
11
+ @adaptor_class = 'Base'
12
+ @collection_class = 'Base'
13
+ @client_class = 'Base'
14
+
15
+ @config = {
16
+
17
+ :daemons => {
18
+
19
+ @daemon_name => {
20
+
21
+ :server => false,
22
+
23
+ :adaptor => {
24
+
25
+ :connection => @adaptor_class,
26
+
27
+ :client => {
28
+
29
+ :class => @client_class
30
+
31
+ }
32
+ },
33
+
34
+ :handler => {
35
+
36
+ :collection => @collection_class
37
+
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ end
44
+
45
+ subject do
46
+
47
+ LanGrove::Daemon::Base.new( @config, @daemon_name, @logger )
48
+
49
+ end
50
+
51
+ it 'requires a logger' do
52
+
53
+ expect {
54
+
55
+ LanGrove::Daemon::Base.new( @config, @daemon_name, nil )
56
+
57
+ }.to raise_error( LanGrove::DaemonConfigException, /Requires a logger/ )
58
+
59
+ end
60
+
61
+ it 'requires a configuration' do
62
+
63
+ expect {
64
+
65
+ LanGrove::Daemon::Base.new( {}, @daemon_name, @logger )
66
+
67
+ }.to raise_error( LanGrove::DaemonConfigException, /Missing config item/ )
68
+
69
+ end
70
+
71
+ it 'latebinds an adaptor by config' do
72
+
73
+ adaptor = subject.instance_variable_get( :@adaptor )
74
+
75
+ adaptor.should be_a( LanGrove::Adaptor.const_get( @adaptor_class ) )
76
+
77
+ end
78
+
79
+ it 'latebinds a handler by config' do
80
+
81
+ handler = subject.instance_variable_get( :@handler )
82
+
83
+ handler.should be_a( LanGrove::Handler.const_get( @collection_class ) )
84
+
85
+ end
86
+
87
+ it 'it schedules periodics'
88
+
89
+ it 'when run, it calls to listen if server is true' do
90
+
91
+ expect {
92
+
93
+ subject.instance_variable_set( :@server, true )
94
+
95
+ subject.run
96
+
97
+ }.to raise_error( LanGrove::DaemonConfigException, "NotYetExtended: undefined listen()" )
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,83 @@
1
+ require 'langrove/ext/class_loader'
2
+ require 'langrove/ext/fake_logger'
3
+
4
+ describe LanGrove::ClassLoader do
5
+
6
+ before :all do
7
+
8
+ @logger = LanGrove::FakeLogger.new :silent
9
+
10
+ end
11
+
12
+ it 'raises on missing class definition file' do
13
+
14
+ expect {
15
+
16
+ LanGrove::ClassLoader.create( {
17
+
18
+ :module => 'Protocol',
19
+ :class => 'MedievalLanternMorse'
20
+
21
+ }, @logger )
22
+
23
+ }.to raise_error(
24
+
25
+ LanGrove::ClassLoaderException,
26
+
27
+ "no such file to load -- protocol/medieval_lantern_morse.rb"
28
+
29
+ )
30
+ end
31
+
32
+ it 'raises on missing ModuleName' do
33
+
34
+ expect {
35
+
36
+ LanGrove::ClassLoader.create( {
37
+
38
+ :class => 'MedievalLanternMorse'
39
+
40
+ }, @logger )
41
+
42
+ }.to raise_error(
43
+
44
+ LanGrove::ClassLoaderException, /:module/
45
+
46
+ )
47
+
48
+ end
49
+
50
+ it 'raises on missing ClassName' do
51
+
52
+ expect {
53
+
54
+ LanGrove::ClassLoader.create( {
55
+
56
+ :module => 'Protocol'
57
+
58
+ }, @logger )
59
+
60
+ }.to raise_error(
61
+
62
+ LanGrove::ClassLoaderException, /:class/
63
+
64
+ )
65
+
66
+ end
67
+
68
+ it 'returns a constantized class definition' do
69
+
70
+ test = LanGrove::ClassLoader.create( {
71
+
72
+ :module => 'Protocol',
73
+ :class => 'Base'
74
+
75
+ }, @logger ).new( nil, @logger )
76
+
77
+ test.should be_a( LanGrove::Protocol::Base )
78
+
79
+ end
80
+
81
+ it 'also works on local implementation'
82
+
83
+ end
@@ -0,0 +1,81 @@
1
+ require 'langrove/ext'
2
+
3
+ describe LanGrove::ConfigItem do
4
+
5
+ before :each do
6
+ @config_hash = {
7
+ 'root' => "3",
8
+ 'BLANK' => "",
9
+ :daemons => {
10
+ 'puppet_log' => {
11
+ :handler => {
12
+ :collection => 'SyslogStateMachines'
13
+ }
14
+ }
15
+ }
16
+ }
17
+ end
18
+
19
+ it 'accesses config items' do
20
+ LanGrove::ConfigItem.get(@config_hash, ['root']).should == '3'
21
+ end
22
+
23
+ it 'accesses nested config items' do
24
+ LanGrove::ConfigItem.get(@config_hash,
25
+
26
+ [:daemons , 'puppet_log', :handler, :collection]
27
+
28
+ ).should == 'SyslogStateMachines'
29
+ end
30
+
31
+ it 'raises a config exception if the key isnt present' do
32
+
33
+ expect {
34
+
35
+ LanGrove::ConfigItem.get(@config_hash, ['NOT'])
36
+
37
+ }.to raise_error( LanGrove::ConfigException, /Missing config item 'NOT'/ )
38
+
39
+ end
40
+
41
+ it 'raises a config exception if the key isnt present' do
42
+
43
+ expect {
44
+
45
+ LanGrove::ConfigItem.get(@config_hash, ['BLANK'])
46
+
47
+ }.to raise_error( LanGrove::ConfigException, /Missing config item 'BLANK'/ )
48
+
49
+ end
50
+
51
+ it 'raises a config exception if the value isnt present' do
52
+
53
+ expect {
54
+
55
+ LanGrove::ConfigItem.get(@config_hash, ['BLANK'], false)
56
+
57
+ }.to_not raise_error( LanGrove::ConfigException, /Missing config item 'BLANK'/ )
58
+
59
+ end
60
+
61
+ it 'raises a config exception if the nested item isnt present' do
62
+
63
+ expect {
64
+
65
+ LanGrove::ConfigItem.get(@config_hash, [ :daemons, 'NEITHER', 'this'])
66
+
67
+ }.to raise_error( LanGrove::ConfigException, /Missing config item 'NEITHER'/ )
68
+
69
+ end
70
+
71
+ it 'does not raise on not mandatory fields' do
72
+
73
+ expect {
74
+
75
+ LanGrove::ConfigItem.get(@config_hash, [ :daemons, 'NEITHER' ], false)
76
+
77
+ }.to_not raise_error( LanGrove::ConfigException )
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,5 @@
1
+ require 'langrove/ext'
2
+
3
+ describe LanGrove::ConfigLoader do
4
+
5
+ end
File without changes