LanGrove 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.rspec +1 -0
  2. data/.rvmrc +62 -0
  3. data/.watchr +19 -0
  4. data/Gemfile +16 -0
  5. data/Gemfile.lock +61 -0
  6. data/Rakefile +17 -0
  7. data/bin/datagram_example +4 -0
  8. data/config/boot.rb +64 -0
  9. data/config/daemons.yml.tmpl +78 -0
  10. data/config/environment.rb +28 -0
  11. data/config/environments/development.rb +0 -0
  12. data/config/environments/production.rb +0 -0
  13. data/config/environments/test.rb +0 -0
  14. data/lib/adaptor/base.rb +1 -0
  15. data/lib/adaptor/datagram.rb +20 -0
  16. data/lib/adaptor/socket_handler.rb +27 -0
  17. data/lib/adaptor_base.rb +39 -0
  18. data/lib/client/base.rb +1 -0
  19. data/lib/client/puppet_state.rb +74 -0
  20. data/lib/client/radio_state.rb +81 -0
  21. data/lib/client_base.rb +24 -0
  22. data/lib/daemon/base.rb +1 -0
  23. data/lib/daemon/datagram_example.rb +12 -0
  24. data/lib/daemon_base.rb +168 -0
  25. data/lib/ext/config_item.rb +35 -0
  26. data/lib/ext/config_loader.rb +16 -0
  27. data/lib/ext/persistable.rb +103 -0
  28. data/lib/ext/string.rb +35 -0
  29. data/lib/handler/base.rb +1 -0
  30. data/lib/handler/socket_to_file.rb +30 -0
  31. data/lib/handler_base.rb +125 -0
  32. data/lib/jobs/Rakefile +0 -0
  33. data/lib/jobs/jobs.rb +1 -0
  34. data/lib/jobs/updated_puppet_state.rb +17 -0
  35. data/lib/protocol_base.rb +5 -0
  36. data/libexec/daemon.rb +57 -0
  37. data/spec/adaptor/datagram_spec.rb +6 -0
  38. data/spec/adaptor/socket_handler_spec.rb +5 -0
  39. data/spec/adaptor_base_spec.rb +45 -0
  40. data/spec/client_base_spec.rb +5 -0
  41. data/spec/daemon_base_spec.rb +97 -0
  42. data/spec/ext/config_item_spec.rb +77 -0
  43. data/spec/ext/config_loader_spec.rb +5 -0
  44. data/spec/ext/persistable_spec.rb +118 -0
  45. data/spec/ext/string_spec.rb +16 -0
  46. data/spec/functional/datagram_spec.rb +122 -0
  47. data/spec/handler_base_spec.rb +71 -0
  48. data/spec/protocol_base_spec.rb +6 -0
  49. data/spec/todo_spec.rb +13 -0
  50. data/tmp/TMP +0 -0
  51. metadata +97 -0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.2-p0@langrove"
8
+
9
+ #
10
+ # Uncomment following line if you want options to be set only for given project.
11
+ #
12
+ # PROJECT_JRUBY_OPTS=( --1.9 )
13
+
14
+ #
15
+ # First we attempt to load the desired environment directly from the environment
16
+ # file. This is very fast and efficient compared to running through the entire
17
+ # CLI and selector. If you want feedback on which environment was used then
18
+ # insert the word 'use' after --create as this triggers verbose mode.
19
+ #
20
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
22
+ then
23
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
24
+
25
+ if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
26
+ then
27
+ . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
28
+ fi
29
+ else
30
+ # If the environment file has not yet been created, use the RVM CLI to select.
31
+ if ! rvm --create use "$environment_id"
32
+ then
33
+ echo "Failed to create RVM environment '${environment_id}'."
34
+ return 1
35
+ fi
36
+ fi
37
+
38
+ #
39
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
40
+ # it be automatically loaded. Uncomment the following and adjust the filename if
41
+ # necessary.
42
+ #
43
+ # filename=".gems"
44
+ # if [[ -s "$filename" ]]
45
+ # then
46
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
47
+ # fi
48
+
49
+ # If you use bundler, this might be useful to you:
50
+ # if command -v bundle && [[ -s Gemfile ]]
51
+ # then
52
+ # bundle install
53
+ # fi
54
+
55
+ if [[ $- == *i* ]] # check for interactive shells
56
+ then
57
+ echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
58
+ else
59
+ echo "Using: $GEM_HOME" # don't use colors in interactive shells
60
+ fi
61
+
62
+
data/.watchr ADDED
@@ -0,0 +1,19 @@
1
+ def run_spec(file)
2
+ unless File.exist?(file)
3
+ puts "#{file} does not exist"
4
+ return
5
+ end
6
+
7
+ puts "Running #{file}"
8
+ system "rspec #{file}"
9
+ puts
10
+ end
11
+
12
+ watch("spec/.*/*_spec.rb") do |match|
13
+ run_spec match[0]
14
+ end
15
+
16
+ watch("lib/(.*/*).rb") do |match|
17
+ puts match
18
+ run_spec %{spec/#{match[1]}_spec.rb}
19
+ end
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source :gemcutter
2
+ source "http://rubygems.org"
3
+
4
+ gem 'watchr'
5
+ gem 'rspec'
6
+
7
+ # daemon-kit
8
+ gem 'daemon-kit'
9
+ gem 'eventmachine'
10
+ gem 'em-http-request'
11
+ gem 'awesome_print'
12
+
13
+ gem 'eventmachine_httpserver'
14
+
15
+ gem 'resque'
16
+ gem 'rake'
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ remote: http://rubygems.org/
4
+ specs:
5
+ addressable (2.2.7)
6
+ awesome_print (1.0.2)
7
+ daemon-kit (0.1.8.2)
8
+ eventmachine (>= 0.12.10)
9
+ safely (>= 0.3.1)
10
+ diff-lcs (1.1.3)
11
+ em-http-request (0.3.0)
12
+ addressable (>= 2.0.0)
13
+ escape_utils
14
+ eventmachine (>= 0.12.9)
15
+ escape_utils (0.2.4)
16
+ eventmachine (0.12.10)
17
+ eventmachine_httpserver (0.2.1)
18
+ multi_json (1.3.2)
19
+ rack (1.4.1)
20
+ rack-protection (1.2.0)
21
+ rack
22
+ rake (0.8.7)
23
+ redis (2.2.2)
24
+ redis-namespace (1.0.3)
25
+ redis (< 3.0.0)
26
+ resque (1.20.0)
27
+ multi_json (~> 1.0)
28
+ redis-namespace (~> 1.0.2)
29
+ sinatra (>= 0.9.2)
30
+ vegas (~> 0.1.2)
31
+ rspec (2.9.0)
32
+ rspec-core (~> 2.9.0)
33
+ rspec-expectations (~> 2.9.0)
34
+ rspec-mocks (~> 2.9.0)
35
+ rspec-core (2.9.0)
36
+ rspec-expectations (2.9.1)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.9.0)
39
+ safely (0.3.1)
40
+ sinatra (1.3.2)
41
+ rack (~> 1.3, >= 1.3.6)
42
+ rack-protection (~> 1.2)
43
+ tilt (~> 1.3, >= 1.3.3)
44
+ tilt (1.3.3)
45
+ vegas (0.1.11)
46
+ rack (>= 1.0.0)
47
+ watchr (0.7)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ awesome_print
54
+ daemon-kit
55
+ em-http-request
56
+ eventmachine
57
+ eventmachine_httpserver
58
+ rake
59
+ resque
60
+ rspec
61
+ watchr
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift 'lib'
2
+
3
+ desc "Publish a new version to ruby-gems.org"
4
+ task :publish do
5
+ require 'langrove/version'
6
+
7
+ sh "gem build langrove.gemspec"
8
+ sh "gem push langrove-#{LanGrove::Version}.gem"
9
+
10
+ #sh "git tag v#{LanGrove::Version}"
11
+ #sh "git push origin v#{Resque::Version}"
12
+ #sh "git push origin master"
13
+ #sh "git clean -fd"
14
+
15
+ # exec "rake documentation"
16
+
17
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ DAEMON_NAME = File.basename $0
3
+ require File.expand_path('../../config/environment', __FILE__)
4
+ DaemonKit::Application.exec( DAEMON_ROOT + '/libexec/daemon.rb' )
data/config/boot.rb ADDED
@@ -0,0 +1,64 @@
1
+ # Don't change this file!
2
+ # Configure your daemon in config/environment.rb
3
+
4
+ DAEMON_ROOT = "#{File.expand_path(File.dirname(__FILE__))}/.." unless defined?( DAEMON_ROOT )
5
+
6
+ require "rubygems"
7
+ require "bundler/setup"
8
+
9
+ module DaemonKit
10
+ class << self
11
+ def boot!
12
+ unless booted?
13
+ pick_boot.run
14
+ end
15
+ end
16
+
17
+ def booted?
18
+ defined? DaemonKit::Initializer
19
+ end
20
+
21
+ def pick_boot
22
+ (vendor_kit? ? VendorBoot : GemBoot).new
23
+ end
24
+
25
+ def vendor_kit?
26
+ File.exists?( "#{DAEMON_ROOT}/vendor/daemon-kit" )
27
+ end
28
+ end
29
+
30
+ class Boot
31
+ def run
32
+ load_initializer
33
+ DaemonKit::Initializer.run
34
+ end
35
+ end
36
+
37
+ class VendorBoot < Boot
38
+ def load_initializer
39
+ require "#{DAEMON_ROOT}/vendor/daemon-kit/lib/daemon_kit/initializer"
40
+ end
41
+ end
42
+
43
+ class GemBoot < Boot
44
+ def load_initializer
45
+ begin
46
+ require 'rubygems' unless defined?( ::Gem )
47
+ gem 'daemon-kit'
48
+ require 'daemon_kit/initializer'
49
+ rescue ::Gem::LoadError => e
50
+ msg = <<EOF
51
+
52
+ You are missing the daemon-kit gem. Please install the following gem:
53
+
54
+ sudo gem install daemon-kit
55
+
56
+ EOF
57
+ $stderr.puts msg
58
+ exit 1
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ DaemonKit.boot!
@@ -0,0 +1,78 @@
1
+ #
2
+ # Using the daemon stubs in bin/ to spawn daemons from this
3
+ # config file with the following guidelines.
4
+ #
5
+ # 1. Each daemon stub name should correspond to a sub-branch in
6
+ # the daemons branch of the config.
7
+ #
8
+ # 2. The daemons are spawned through a generic DaemonKit based
9
+ # spawner.
10
+ #
11
+ # 3. Daemons log to the log/<daemon_name>.log where daemon_name
12
+ # exactly corresponds to the stub name.
13
+ #
14
+ # 4. Daemons keep a pidfile at log/<daemon_name>.pid, these are
15
+ # used by DaemonKit for init.d style stop|start|restart etc.
16
+ #
17
+ # 5. Daemons are spawned through a generic executer which late
18
+ # binds the daemon runner class. Therefore, each daemon with
19
+ # a stub at
20
+ #
21
+ # bin/<daemon_name>
22
+ #
23
+ # should also have a runner class defined at
24
+ #
25
+ # lib/<daemon_name>.rb
26
+ #
27
+ # which defines the class <DaemonName> with the following:
28
+ #
29
+ # Mandatory
30
+ # =========
31
+ #
32
+ # - initialize( entire_config_hash, daemon_name, logger )
33
+ #
34
+ # To load up and initialize as required.
35
+ #
36
+ # It will be provided with
37
+ #
38
+ # <entire_config_hash> - This entire file as a Hash
39
+ # <daemon_name> - From the stub name in bin/
40
+ # <logger> - An initialized logger
41
+ #
42
+ # - run()
43
+ #
44
+ # The daemons 'main' loop
45
+ #
46
+ # Optional
47
+ # ========
48
+ #
49
+ # - stop_daemon()
50
+ #
51
+ # To properly handle daemon shutdown when the server gets
52
+ # rebooted or daemon gets restarted
53
+ #
54
+ # PENDING
55
+ # PENDING - reload_daemon()
56
+ # PENDING
57
+ # PENDING To reload the daemon after a config change without taking
58
+ # PENDING down any currently connected sockets and such.
59
+ # PENDING
60
+ #
61
+ # 6. Each daemon config should contain reference to a Handler class.
62
+ #
63
+ # PENDING explain that later.
64
+ #
65
+ #
66
+
67
+ daemons:
68
+ datagram_example:
69
+ periodic: 5
70
+ adaptor:
71
+ connection: Datagram
72
+ iface: 127.0.0.1
73
+ port: 12701
74
+ handler:
75
+ collection: Base
76
+ protocol: Base
77
+
78
+
@@ -0,0 +1,28 @@
1
+ ENV["TZ"] = "ZA"
2
+ #ENV['DAEMON_ENV'] ||= 'production'
3
+
4
+ # Boot up
5
+ require File.join(File.dirname(__FILE__), 'boot')
6
+
7
+ # Auto-require default libraries.
8
+ Bundler.require :default, DaemonKit.env
9
+
10
+ DaemonKit::Initializer.run do |config|
11
+
12
+ config.daemon_name = DAEMON_NAME
13
+
14
+ # Force the daemon to be killed after X seconds from asking it to
15
+ # config.force_kill_wait = 30
16
+
17
+ # Log backraces when a thread/daemon dies (Recommended)
18
+ config.backtraces = true
19
+
20
+ #
21
+ # TODO: move log level into per daemon config
22
+ #
23
+ #config.log_level = :debug
24
+ config.log_level = :info
25
+ #config.log_level = :warn
26
+ #config.log_level = :error
27
+
28
+ end
File without changes
File without changes
File without changes
@@ -0,0 +1 @@
1
+ require 'adaptor_base'
@@ -0,0 +1,20 @@
1
+ require 'adaptor/base'
2
+
3
+ module Adaptor
4
+
5
+ class Datagram < Base
6
+
7
+ def listen( collection )
8
+
9
+ @logger.info "starting listen at UDP #{@iface}:#{@port}"
10
+
11
+ EventMachine::open_datagram_socket( @iface, @port,
12
+
13
+ @connector ) do |connection|
14
+
15
+ connection.handler = collection
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require 'eventmachine'
2
+
3
+ module Adaptor
4
+
5
+ class SocketHandler < EM::Connection
6
+
7
+ #
8
+ # The handler collection specified in config
9
+ # is bound to this attribute after connect.
10
+ #
11
+ attr_accessor :handler
12
+ attr_accessor :protocol
13
+
14
+ def receive_data(data)
15
+
16
+ #@handler.message( @protocol.decode( data ) )
17
+ @handler.message( data )
18
+
19
+ #
20
+ # sort out application layer ACKs later
21
+ # currently only datagrams arriving here
22
+ # so it's not necessary
23
+ #
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require 'eventmachine'
2
+
3
+ require 'adaptor/socket_handler'
4
+
5
+ module Adaptor
6
+
7
+ class Base
8
+
9
+ def initialize( config, logger )
10
+
11
+ @config = config
12
+ @logger = logger
13
+
14
+ @iface = '127.0.0.1'
15
+ @port = 12701
16
+ @connector = Adaptor::SocketHandler
17
+
18
+ @iface = @config['iface'] if @config.has_key? 'iface'
19
+ @port = @config['port'] if @config.has_key? 'port'
20
+
21
+ if @config.has_key? 'connector' then
22
+
23
+ #
24
+ # TODO: may need to override default connection handler
25
+ #
26
+
27
+ end
28
+
29
+ end
30
+
31
+ def listen( collection ) # ---> handler
32
+
33
+ raise DaemonConfigException.new( "NotYetExtended: undefined listen()" )
34
+
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1 @@
1
+ require 'client_base'
@@ -0,0 +1,74 @@
1
+ require 'client/abstract/syslog_state_machine'
2
+
3
+ class PuppetState < SyslogStateMachine
4
+
5
+ def initialize( hostname, config, logger )
6
+ super
7
+
8
+ @state[:exit_code] = nil
9
+ @state[:last_run_at] = nil
10
+ @state[:revision] = ''
11
+ @state[:last_run_duration_seconds] = nil
12
+
13
+ end
14
+
15
+ def change_state( date, tag, message )
16
+
17
+ #
18
+ # return true if state changed
19
+ #
20
+
21
+ ### last_started_at
22
+ #
23
+ # run_puppet: obtained lock: beginning run
24
+ #
25
+ if /obtained lock: beginning run/.match( message ) then
26
+
27
+ @state[:last_run_at] = date
28
+ return true
29
+
30
+ end
31
+
32
+ def reset
33
+
34
+ @state[:exit_code] = nil
35
+
36
+ end
37
+
38
+ ### revision
39
+ #
40
+ # puppet-git-rev: 0acbf0a78ed813e31dcc3fe58f9c6e9a30219da4
41
+ #
42
+ if tag == 'puppet-git-rev' then
43
+
44
+ @state[:revision] = message
45
+ return true
46
+
47
+ end
48
+
49
+ ### success
50
+ ### last_run_duration_seconds
51
+ #
52
+ # run_puppet: completed, releasing lock (exit code : 2)
53
+ #
54
+
55
+ if /completed, releasing lock/.match( message ) then
56
+
57
+ @state[:exit_code] = /[\d]+/.match(message)[0]
58
+ @state[:running] = false
59
+
60
+ if @state[:last_run_at] then
61
+ @state[:last_run_duration_seconds] = date - @state[:last_run_at]
62
+ else
63
+ @state[:last_run_duration_seconds] = -1
64
+ end
65
+
66
+ return true
67
+
68
+ end
69
+
70
+ return false
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,81 @@
1
+ require 'client/abstract/syslog_state_machine'
2
+
3
+ class RadioState < SyslogStateMachine
4
+
5
+ def persist_change_state( data )
6
+
7
+ #
8
+ # default product will override with Nano *
9
+ #
10
+ @state[:vendor] = "BST"
11
+ @state[:product] = "Subscriber"
12
+
13
+ @state.merge!( data )
14
+ @state[:last_seen_at] = data[:timestamp].clone
15
+ @state[:last_seen] = data[:timestamp].strftime( '%Y/%m/%d %H:%M:%S')
16
+
17
+
18
+ new_min :rx, :rx_min, :rx_min_at
19
+ new_max :rx, :rx_max, :rx_max_at
20
+
21
+ new_min :tx, :tx_min, :tx_min_at
22
+ new_max :tx, :tx_max, :tx_max_at
23
+
24
+ #
25
+ # flag to store
26
+ #
27
+ @stored = false
28
+
29
+ return true
30
+
31
+ end
32
+
33
+
34
+ def new_min( val, min_val, at )
35
+
36
+ newval = @state[val].to_i
37
+
38
+ if @state.has_key? min_val then
39
+
40
+ minval = @state[min_val]
41
+ begin
42
+
43
+ @state[min_val] = newval
44
+ @state[at] = @state[:timestamp].clone
45
+
46
+ end if minval > newval
47
+
48
+ else
49
+
50
+ @state[min_val] = newval
51
+ @state[at] = @state[:timestamp].clone
52
+
53
+ end
54
+
55
+ end
56
+
57
+
58
+ def new_max( val, max_val, at )
59
+
60
+ newval = @state[val].to_i
61
+
62
+ if @state.has_key? max_val then
63
+
64
+ maxval = @state[max_val]
65
+ begin
66
+
67
+ @state[max_val] = newval
68
+ @state[at] = @state[:timestamp].clone
69
+
70
+ end if maxval < newval
71
+
72
+ else
73
+
74
+ @state[max_val] = newval
75
+ @state[at] = @state[:timestamp].clone
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,24 @@
1
+ require 'ext/persistable'
2
+
3
+ module Client class Base < Persistable
4
+
5
+ #
6
+ # Misnomer.
7
+ #
8
+ #
9
+ # This is not the client,
10
+ #
11
+ #
12
+ # It is the server's perspective of the client,
13
+ #
14
+ # These are generally stored in the daemon's
15
+ # handler collection,
16
+ #
17
+ # Which contains this and all similar clients,
18
+ #
19
+ # Each bonded through the daemon's connection
20
+ # adaptor to the socket that couples them to
21
+ # their actual client..
22
+ #
23
+
24
+ end; end
@@ -0,0 +1 @@
1
+ require 'daemon_base'
@@ -0,0 +1,12 @@
1
+ require 'daemon/base'
2
+
3
+ class DatagramExample < Daemon::Base
4
+
5
+ #
6
+ # Consider tossing this dependancy.
7
+ #
8
+ # Not entirely certain this layer in
9
+ # the abstraction will be useful.
10
+ #
11
+
12
+ end