nfagent 0.9.0 → 0.9.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/Manifest.txt CHANGED
@@ -7,8 +7,13 @@ lib/nfagent/encoder.rb
7
7
  lib/nfagent/server.rb
8
8
  lib/nfagent/chunk_handler.rb
9
9
  lib/nfagent/log.rb
10
+ lib/nfagent/info.rb
10
11
  lib/nfagent/event.rb
12
+ lib/nfagent/payload.rb
13
+ lib/nfagent/poller.rb
11
14
  lib/nfagent/chunk.rb
15
+ lib/nfagent/client.rb
16
+ lib/nfagent/client_response.rb
12
17
  lib/nfagent/config.rb
13
18
  lib/nfagent/tail.rb
14
19
  lib/nfagent/submitter.rb
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ $hoe = Hoe.spec('nfagent') do |p|
11
11
  p.post_install_message = 'PostInstall.txt'
12
12
  p.rubyforge_name = p.name
13
13
  p.extra_deps = [
14
- ['svutil','>= 0.0.3'], ['eventmachine', '>= 0.12.8']
14
+ ['svutil','>= 0.0.6'], ['eventmachine', '>= 0.12.8']
15
15
  ]
16
16
  p.extra_dev_deps = [
17
17
  ['newgem', ">= #{::Newgem::VERSION}"]
data/lib/nfagent.rb CHANGED
@@ -4,25 +4,31 @@ $:.unshift(File.dirname(__FILE__)) unless
4
4
  require 'rubygems'
5
5
  require 'svutil'
6
6
 
7
- require 'thread'
8
7
  require 'fileutils'
9
8
  require 'logger'
10
9
  require 'pp'
11
10
  require 'uri'
12
11
  require 'net/http'
13
12
  require 'eventmachine'
13
+ require 'em/timers'
14
+ require 'rbconfig'
14
15
 
15
16
  require 'nfagent/chunk'
17
+ require 'nfagent/client'
18
+ require 'nfagent/client_response'
16
19
  require 'nfagent/chunk_handler'
17
20
  require 'nfagent/submitter'
18
21
  require 'nfagent/encoder'
19
22
  require 'nfagent/config'
20
23
  require 'nfagent/log'
24
+ require 'nfagent/info'
25
+ require 'nfagent/payload'
26
+ require 'nfagent/poller'
21
27
  require 'nfagent/tail'
22
28
  require 'nfagent/event'
23
29
  require 'nfagent/server'
24
30
  require 'nfagent/cli'
25
31
 
26
32
  module NFAgent
27
- VERSION = '0.9.0'
33
+ VERSION = '0.9.5'
28
34
  end
data/lib/nfagent/chunk.rb CHANGED
@@ -26,19 +26,16 @@ module NFAgent
26
26
  (Time.now - @created_at > ::DEFAULT_TIME_OUT) && !@array.empty?
27
27
  end
28
28
 
29
+ # TODO: Is this the right place for compression, encoding and check summing? Perhaps it should go into the submitter to that it can be deferred
29
30
  def dump
30
- payload = Encoder.encode64url(Zlib::Deflate.deflate(@array.join("\n"), Zlib::BEST_COMPRESSION))
31
- checksum = Digest::SHA1.hexdigest(payload)
32
- [ payload, checksum ]
31
+ Payload.new do |payload|
32
+ payload.data = Encoder.encode64url(Zlib::Deflate.deflate(@array.join("\n"), Zlib::BEST_COMPRESSION))
33
+ payload.checksum = Digest::SHA1.hexdigest(payload.data)
34
+ end
33
35
  end
34
36
 
35
37
  def clear
36
38
  @array.clear
37
39
  end
38
-
39
- def submit_to_server
40
- payload, checksum = dump
41
- @submitter.submit(payload, checksum)
42
- end
43
40
  end
44
41
  end
@@ -1,57 +1,36 @@
1
1
  module NFAgent
2
2
  class ChunkHandler
3
3
 
4
+ # TODO: Rename this to Controller later
4
5
  def initialize(chunk_size = 500)
5
- @mutex = Mutex.new
6
- @chunk_size = chunk_size
7
- make_new_chunk
6
+ @chunk = Chunk.new(chunk_size)
8
7
  end
9
8
 
10
- def submit(line)
9
+ def append(line)
11
10
  # if current day is > day of last entry on current_chunk
12
11
  # then submit and reset the chunk before adding the line
13
12
  current_day = Time.now.day
14
- if current_day != current_chunk.created_at.day
13
+ if current_day != @chunk.created_at.day
15
14
  Log.info("Expiring chunk due to date rollover")
16
15
  reset_chunk
17
16
  end
18
- current_chunk << line
17
+ @chunk << line
19
18
  end
20
19
 
21
- def periodically_check_expired
22
- Thread.new do
23
- loop do
24
- check_full_or_expired
25
- sleep 5
26
- end
20
+ def check_full_or_expired
21
+ if @chunk.full? || @chunk.expired?
22
+ reset_chunk
27
23
  end
28
24
  end
29
25
 
30
26
  private
31
- def check_full_or_expired
32
- if current_chunk.full? || current_chunk.expired?
33
- reset_chunk
34
- end
35
- end
36
-
37
27
  def reset_chunk
38
- outgoing_chunk = current_chunk
39
- make_new_chunk
40
- Thread.new do
41
- outgoing_chunk.submit_to_server
42
- end
43
- end
44
-
45
- def make_new_chunk
46
- @mutex.synchronize do
47
- @current_chunk = Chunk.new(@chunk_size)
48
- end
49
- end
50
-
51
- def current_chunk
52
- @mutex.synchronize do
53
- return @current_chunk
54
- end
28
+ submitter = Submitter.new(@chunk.dump)
29
+ submitter.errback { |payload|
30
+ payload.write_to_disk(Config.dump_dir)
31
+ }
32
+ @chunk.clear
33
+ submitter.perform
55
34
  end
56
35
  end
57
36
  end
@@ -0,0 +1,21 @@
1
+ module NFAgent
2
+ class Client
3
+ SERVICE_HOST = "collector.service.netfox.com"
4
+
5
+ def self.post(end_point, data_hash)
6
+ proxy_class = Net::HTTP::Proxy(Config.proxy.host, Config.proxy.port, Config.proxy.user, Config.proxy.password)
7
+ # TODO: Enable SSL
8
+ proxy_class.start(SERVICE_HOST, 80) do |http|
9
+ req = Net::HTTP::Post.new("/#{end_point}")
10
+ req.set_form_data(data_hash.merge("key" => Config.client_key))
11
+ ClientResponse.new do |resp|
12
+ resp.response, resp.message = http.request(req)
13
+ end
14
+ end
15
+ rescue
16
+ ClientResponse.new do |resp|
17
+ resp.message = $!
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module NFAgent
2
+ class ClientResponse
3
+ attr_accessor :response, :message
4
+
5
+ def initialize
6
+ yield self if block_given?
7
+ end
8
+
9
+ def ok?
10
+ Net::HTTPOK === response
11
+ end
12
+ end
13
+ end
@@ -3,6 +3,8 @@ module NFAgent
3
3
  attr_accessor :host, :port, :user, :password
4
4
  end
5
5
 
6
+ RBConfig = Config
7
+
6
8
  class Config < SVUtil::Config
7
9
  @@proxy = Proxy.new
8
10
 
data/lib/nfagent/event.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  module NFAgent
2
2
  class Event < EventMachine::Connection
3
- def initialize(chunk_handler)
3
+ def initialize(chunk_handler, poller)
4
4
  @handler = chunk_handler
5
+ @poller = poller
5
6
  end
6
7
 
7
8
  def post_init
@@ -10,7 +11,7 @@ module NFAgent
10
11
 
11
12
  def receive_data(data)
12
13
  if data && data.length > 2
13
- @handler.submit(data)
14
+ @handler.append(data)
14
15
  end
15
16
  send_data('OK')
16
17
  end
@@ -0,0 +1,26 @@
1
+ module NFAgent
2
+ class Info
3
+ attr_accessor :last_proxy_connection
4
+
5
+ def hostname
6
+ Socket.gethostname
7
+ end
8
+
9
+ def version
10
+ NFAgent::VERSION
11
+ end
12
+
13
+ def host_string
14
+ RBConfig::CONFIG['host']
15
+ end
16
+
17
+ def to_hash
18
+ {
19
+ :hostname => hostname,
20
+ :version => version,
21
+ :host_string => host_string,
22
+ :last_proxy_connection => last_proxy_connection
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,70 @@
1
+
2
+ module NFAgent
3
+ class Payload < Struct.new(:data, :checksum, :filename)
4
+ def initialize
5
+ yield self
6
+ end
7
+
8
+ def attempt
9
+ @attempt || 1
10
+ end
11
+
12
+ def attempt=(value)
13
+ @attempt = value.to_i
14
+ end
15
+
16
+ def increment_attempt!
17
+ @attempt ||= 1
18
+ @attempt += 1
19
+ end
20
+
21
+ def size
22
+ (self.data || "").size + 1
23
+ end
24
+
25
+ def write_to_disk(directory)
26
+ File.open(File.join(directory, "#{self.checksum}-#{self.attempt}"), "w") do |file|
27
+ file << self.data
28
+ end
29
+ end
30
+
31
+ def lock
32
+ return if locked?
33
+ FileUtils.touch(lockfile) if filename
34
+ yield
35
+ FileUtils.rm_f(lockfile) if filename
36
+ end
37
+
38
+ def locked?
39
+ filename && File.exists?(lockfile)
40
+ end
41
+
42
+ def self.read_from_file(filename)
43
+ # Ensure the file is only relative
44
+ filename = File.basename(filename)
45
+ self.new do |payload|
46
+ payload.filename = filename
47
+ payload.checksum, payload.attempt = filename.split("-")
48
+ payload.data = ""
49
+ ref = File.join(Config.dump_dir, filename)
50
+ File.open(ref, "r") do |file|
51
+ payload.data << file.read
52
+ end
53
+ end
54
+ end
55
+
56
+ def destroy!
57
+ FileUtils.rm_f(File.join(Config.dump_dir, self.filename)) if self.filename
58
+ end
59
+
60
+ def try_again_later
61
+ # TODO: Move the file to a new name with a later timetamp
62
+ FileUtils.mv(File.join(Config.dump_dir, self.filename), File.join(Config.dump_dir, "#{self.checksum}-#{self.attempt}"))
63
+ end
64
+
65
+ private
66
+ def lockfile
67
+ File.join(Config.dump_dir, "#{filename}.lock") if filename
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,18 @@
1
+ module NFAgent
2
+ class Poller
3
+ include EM::Deferrable
4
+
5
+ def initialize
6
+ @info = Info.new
7
+ end
8
+
9
+ def send_heartbeat
10
+ payload = @info.to_hash
11
+ Log.info("Polling: #{payload.inspect}")
12
+ response = Client.post(:poller, payload)
13
+ if !response.ok?
14
+ Log.error("Poll Failed: #{response.message}")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,14 +1,26 @@
1
1
  module NFAgent
2
2
  class Server
3
- def initialize
3
+ def run
4
4
  Log.info("Starting up")
5
- Submitter.start_resubmission_thread
6
5
  chunk_handler = ChunkHandler.new
7
- chunk_handler.periodically_check_expired
6
+ poller = Poller.new
8
7
 
9
8
  EM.run {
10
- EM.start_server "0.0.0.0", 10000, Event, chunk_handler
9
+ EM::PeriodicTimer.new(5) do
10
+ chunk_handler.check_full_or_expired
11
+ end
12
+ EM::PeriodicTimer.new(60) do
13
+ Submitter.resubmit_failed_dumps
14
+ end
15
+ EM::PeriodicTimer.new(120) do
16
+ poller.send_heartbeat
17
+ end
18
+ EM.start_server "0.0.0.0", 10000, Event, chunk_handler, poller
11
19
  }
12
20
  end
21
+
22
+ def shutdown
23
+ EM::stop_event_loop
24
+ end
13
25
  end
14
26
  end
@@ -1,59 +1,47 @@
1
1
  module NFAgent
2
2
  class Submitter
3
+ include EM::Deferrable
3
4
  attr_accessor :host
4
5
 
5
- def initialize(key)
6
- @service_host = "collector.service.netfox.com"
7
- @key = key
6
+ def initialize(payload)
7
+ @payload = payload
8
8
  end
9
9
 
10
- def submit(payload, checksum, options = {})
11
- attempt = options[:attempt] || 1
12
- raise "Delaying attempt" unless [ 1, 2, 4, 8, 16 ].include?(attempt)
13
- puts "Submitting Payload: #{checksum}, Attempt #{attempt}, (#{payload.size + 1} bytes)"
14
- proxy_class = Net::HTTP::Proxy(Config.proxy.host, Config.proxy.port, Config.proxy.user, Config.proxy.password)
15
- proxy_class.start(@service_host, 80) do |http|
16
- req = Net::HTTP::Post.new('/collector')
17
- req.set_form_data({ "payload" => payload, "checksum" => checksum, "key" => @key })
18
- response, body = http.request(req)
19
- raise body unless Net::HTTPOK === response
20
- end
21
- rescue
22
- Log.error "Submission Failed: #{$!}"
23
- write_failed_dump(payload, checksum, attempt)
24
- end
25
-
26
- def write_failed_dump(payload, checksum, attempt)
27
- File.open(File.join(Config.dump_dir, "#{checksum}-#{attempt}"), "w") do |file|
28
- file << payload
29
- end
30
- end
31
-
32
- def self.start_resubmission_thread
33
- Thread.new do
34
- loop do
35
- self.resubmit_failed_dumps
36
- sleep 60
10
+ def perform
11
+ @payload.increment_attempt!
12
+ fail(@payload) unless [ 1, 2, 4, 8, 16 ].include?(@payload.attempt)
13
+ Log.info "Submitting Payload: #{@payload.checksum}, Attempt #{@payload.attempt}, (#{@payload.size} bytes)"
14
+ @payload.lock do
15
+ response = Client.post(:collector, "payload" => @payload.data, "checksum" => @payload.checksum)
16
+ if response.ok?
17
+ succeed(@payload)
18
+ else
19
+ Log.error "Submission Failed: #{response.message}"
20
+ fail(@payload)
37
21
  end
38
22
  end
39
23
  end
40
24
 
25
+ # TODO: Change attempt logic
26
+ # Add the next timestamp for when submission should be attenpted again to the end of the filename
41
27
  def self.resubmit_failed_dumps
42
28
  submitter = Submitter.new(Config.client_key)
43
29
  dump_dir = Dir.new(Config.dump_dir)
44
30
  dump_dir.entries.select { |e| not e =~ /^\./ }.each do |entry|
45
- dump_file, attempt = entry.split("-")
46
31
  Log.info "Resubmitting #{entry}"
47
- payload = ""
48
- ref = File.join(dump_dir.path, entry)
49
- File.open(ref, "r") do |file|
50
- payload << file.read
51
- end
52
- FileUtils.rm_f(ref)
53
- attempt = attempt.to_i + 1
54
- if attempt <= 16
55
- submitter.submit(payload, dump_file, :attempt => attempt)
56
- end
32
+ payload = Payload.read_from_file(entry)
33
+ submitter = self.new(payload)
34
+ submitter.callback { |payload|
35
+ payload.destroy!
36
+ }
37
+ submitter.errback { |payload|
38
+ if payload.attempt > 16
39
+ payload.destroy!
40
+ else
41
+ payload.try_again_later
42
+ end
43
+ }
44
+ submitter.perform
57
45
  end
58
46
  end
59
47
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 0
9
- version: 0.9.0
8
+ - 5
9
+ version: 0.9.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Daniel Draper
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-07 00:00:00 +09:30
17
+ date: 2010-07-12 00:00:00 +09:30
18
18
  default_executable: nfagent
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -27,8 +27,8 @@ dependencies:
27
27
  segments:
28
28
  - 0
29
29
  - 0
30
- - 3
31
- version: 0.0.3
30
+ - 6
31
+ version: 0.0.6
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
@@ -96,8 +96,13 @@ files:
96
96
  - lib/nfagent/server.rb
97
97
  - lib/nfagent/chunk_handler.rb
98
98
  - lib/nfagent/log.rb
99
+ - lib/nfagent/info.rb
99
100
  - lib/nfagent/event.rb
101
+ - lib/nfagent/payload.rb
102
+ - lib/nfagent/poller.rb
100
103
  - lib/nfagent/chunk.rb
104
+ - lib/nfagent/client.rb
105
+ - lib/nfagent/client_response.rb
101
106
  - lib/nfagent/config.rb
102
107
  - lib/nfagent/tail.rb
103
108
  - lib/nfagent/submitter.rb