ffwd 0.1.7 → 0.2.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4b630458a10baaf2b380c2fea5d264c0b5899dfb
4
+ data.tar.gz: de1dbbce8ec3bbd5a4d8acd85dc2b7f6c5ef9cfa
5
+ SHA512:
6
+ metadata.gz: 1d32fad236f6af767352403f042f9cf03a5e7133a41081a0d390715467339ed579e0993b853a433dbbc5cae02c433ad44b4bcadea58228e2c68a9983e6f88219
7
+ data.tar.gz: b60bf9c734110e417fd45c9bb8282e9224780146bb2bd403b62d5a315c2ff26d061b8eaa303a266a1fd61f2ecc2dfcdc19ae99b1cf9562b8b222000191e509a0
@@ -25,9 +25,8 @@ require_relative 'ffwd/schema'
25
25
  require_relative 'ffwd/version'
26
26
 
27
27
  module FFWD
28
- DEFAULT_PLUGIN_DIRECTORIES = [
29
- './plugins'
30
- ]
28
+ DEFAULT_PLUGIN_DIRECTORIES = ['./plugins' ]
29
+ DEFAULT_CONFIG_PREFIXES = ['./ffwd.d']
31
30
 
32
31
  def self.load_yaml path
33
32
  return YAML.load_file path
@@ -70,7 +69,7 @@ module FFWD
70
69
  c = load_yaml entry_path
71
70
 
72
71
  if c.nil?
73
- log.warn "Ignoring: #{entry_path} (invalid yaml)"
72
+ log.warning "Ignoring: #{entry_path} (invalid yaml)"
74
73
  next
75
74
  end
76
75
 
@@ -82,6 +81,7 @@ module FFWD
82
81
  @@opts ||= {:debug => false, :config => nil, :config_dir => nil,
83
82
  :list_plugins => false, :list_schemas => false,
84
83
  :dump_config => false, :show_version => false,
84
+ :config_prefixes => DEFAULT_CONFIG_PREFIXES,
85
85
  :config_paths => [],
86
86
  :plugin_directories => DEFAULT_PLUGIN_DIRECTORIES}
87
87
  end
@@ -95,9 +95,15 @@ module FFWD
95
95
  end
96
96
 
97
97
  o.on "-c", "--config <path>", "Load the specified configuration file." do |path|
98
+ puts "WARNING: Deprecated option '-c #{path}'."
99
+ puts " Use positional argument to specify configuration!"
98
100
  opts[:config_paths] << path
99
101
  end
100
102
 
103
+ o.on "-D", "--config-prefix <path>", "Scan for configuration files relative to this directory." do |path|
104
+ opts[:config_prefixes] << path
105
+ end
106
+
101
107
  o.on "-d", "--config-directory <path>", "Load configuration files from the specified directory." do |path|
102
108
  opts[:config_dir] = path
103
109
  end
@@ -132,13 +138,13 @@ module FFWD
132
138
  plugins = {}
133
139
 
134
140
  plugins[:tunnel] = FFWD::Plugin.load_plugins(
135
- log, "Tunnel", config[:tunnel], :tunnel)
141
+ log, "Tunnel", config[:tunnel], :input, :tunnel)
136
142
 
137
143
  plugins[:input] = FFWD::Plugin.load_plugins(
138
- log, "Input", config[:input], :input)
144
+ log, "Input", config[:input], :input, :bind)
139
145
 
140
146
  plugins[:output] = FFWD::Plugin.load_plugins(
141
- log, "Output", config[:output], :output)
147
+ log, "Output", config[:output], :output, :connect)
142
148
 
143
149
  plugins
144
150
  end
@@ -219,8 +225,24 @@ module FFWD
219
225
  puts " https://github.com/spotify/ffwd"
220
226
  end
221
227
 
228
+ def self.match_any_config_path prefixes, path
229
+ return path if File.file? path
230
+
231
+ prefixes.each do |prefix|
232
+ full = File.join prefix, path
233
+ next unless File.file? full
234
+ return full
235
+ end
236
+
237
+ return nil
238
+ end
239
+
222
240
  def self.main args
223
- parse_options args
241
+ positional = parse_options(args)
242
+
243
+ positional.each do |path|
244
+ opts[:config_paths] << path
245
+ end
224
246
 
225
247
  if opts[:show_version]
226
248
  puts "ffwd version: #{FFWD::VERSION}"
@@ -232,7 +254,9 @@ module FFWD
232
254
  config = {}
233
255
 
234
256
  opts[:config_paths].each do |path|
235
- unless File.file? path
257
+ path = match_any_config_path opts[:config_prefixes], path
258
+
259
+ unless path
236
260
  puts "Configuration path does not exist: #{path}"
237
261
  puts ""
238
262
  puts parser.help
@@ -240,7 +264,7 @@ module FFWD
240
264
  end
241
265
 
242
266
  return 0 unless source = load_yaml(path)
243
-
267
+ puts "Loaded: #{path}"
244
268
  merge_configurations config, source
245
269
  end
246
270
 
@@ -23,7 +23,6 @@ require_relative 'logging'
23
23
  require_relative 'plugin_channel'
24
24
  require_relative 'processor'
25
25
  require_relative 'protocol'
26
- require_relative 'statistics'
27
26
  require_relative 'utils'
28
27
 
29
28
  require_relative 'core/emitter'
@@ -31,6 +30,8 @@ require_relative 'core/interface'
31
30
  require_relative 'core/processor'
32
31
  require_relative 'core/reporter'
33
32
 
33
+ require_relative 'statistics/collector'
34
+
34
35
  module FFWD
35
36
  class Core
36
37
  include FFWD::Lifecycle
@@ -46,8 +47,8 @@ module FFWD
46
47
  @core_opts = opts[:core] || {}
47
48
  @processors = FFWD::Processor.load_processors(opts[:processor] || {})
48
49
 
49
- @output_channel = FFWD::PluginChannel.build 'output'
50
- @input_channel = FFWD::PluginChannel.build 'input'
50
+ @output_channel = FFWD::PluginChannel.build 'core.output'
51
+ @input_channel = FFWD::PluginChannel.build 'core.input'
51
52
 
52
53
  @system_channel = Channel.new log, "system_channel"
53
54
 
@@ -66,8 +67,8 @@ module FFWD
66
67
 
67
68
  if @debug_opts
68
69
  @debug = FFWD::Debug.setup @debug_opts
69
- @debug.monitor "core.input", @input_channel, FFWD::Debug::Input
70
- @debug.monitor "core.output", @output_channel, FFWD::Debug::Output
70
+ @debug.monitor @input_channel, FFWD::Debug::Input
71
+ @debug.monitor @output_channel, FFWD::Debug::Output
71
72
  @debug.depend_on self
72
73
  end
73
74
 
@@ -75,7 +76,8 @@ module FFWD
75
76
  @statistics = nil
76
77
 
77
78
  if config = @statistics_opts
78
- @statistics = FFWD::Statistics.setup @emitter, @system_channel, config
79
+ @statistics = FFWD::Statistics::Collector.build(
80
+ @emitter, @system_channel, config)
79
81
  @statistics.depend_on self
80
82
  end
81
83
 
@@ -86,19 +88,19 @@ module FFWD
86
88
 
87
89
  @interface.depend_on self
88
90
 
89
- @input_instances = @input_plugins.map do |plugin|
90
- plugin.setup @interface
91
+ @input_instances = @input_plugins.map do |factory|
92
+ factory.call @interface
91
93
  end
92
94
 
93
- @output_instances = @output_plugins.map do |plugin|
94
- plugin.setup @interface
95
+ @output_instances = @output_plugins.map do |factory|
96
+ factory.call @interface
95
97
  end
96
98
 
97
99
  unless @statistics.nil?
98
100
  reporters = [@input_channel, @output_channel, @processor]
99
101
  reporters += @input_instances.select{|i| FFWD.is_reporter?(i)}
100
102
  reporters += @output_instances.select{|i| FFWD.is_reporter?(i)}
101
- @statistics.register "core", Core::Reporter.new(reporters)
103
+ @statistics.register self, "core", Core::Reporter.new(reporters)
102
104
  end
103
105
 
104
106
  # Make the core-related channels depend on core.
@@ -13,8 +13,6 @@
13
13
  # License for the specific language governing permissions and limitations under
14
14
  # the License.
15
15
 
16
- require_relative '../logging'
17
- require_relative '../utils'
18
16
  require_relative '../metric_emitter'
19
17
  require_relative '../event_emitter'
20
18
 
@@ -25,8 +25,11 @@ module FFWD
25
25
  attr_reader :tunnel_plugins, :statistics, :debug, :processors
26
26
  attr_reader :tags, :attributes
27
27
 
28
- def initialize(input, output, tunnel_plugins, statistics, debug,
29
- processors, opts)
28
+ def initialize(
29
+ input, output,
30
+ tunnel_plugins, statistics, debug,
31
+ processors, opts
32
+ )
30
33
  @input = input
31
34
  @output = output
32
35
  @tunnel_plugins = tunnel_plugins
@@ -38,25 +38,24 @@ module FFWD
38
38
  @emitter = emitter
39
39
  @processors = processors
40
40
  @reporters = reporters
41
-
42
- subs = []
41
+ @subs = []
43
42
 
44
43
  @processors.each do |name, p|
45
44
  p.depend_on input
46
45
  end
47
46
 
48
47
  input.starting do
49
- subs << input.metric_subscribe do |m|
48
+ @subs << input.metric_subscribe do |m|
50
49
  process_metric m
51
50
  end
52
51
 
53
- subs << input.event_subscribe do |e|
52
+ @subs << input.event_subscribe do |e|
54
53
  process_event e
55
54
  end
56
55
  end
57
56
 
58
57
  input.stopping do
59
- subs.each(&:unsubscribe).clear
58
+ @subs.each(&:unsubscribe).clear
60
59
  end
61
60
  end
62
61
 
@@ -17,10 +17,7 @@ require_relative '../lifecycle'
17
17
 
18
18
  module FFWD::Debug
19
19
  class MonitorSession
20
- attr_reader :id
21
-
22
- def initialize id, channel, type
23
- @id = id
20
+ def initialize channel, type
24
21
  @type = type
25
22
  @clients = {}
26
23
 
@@ -31,7 +28,7 @@ module FFWD::Debug
31
28
  data = @type.serialize_event event
32
29
 
33
30
  begin
34
- send JSON.dump(:id => @id, :type => :event, :data => data)
31
+ send JSON.dump(:id => channel.id, :type => :event, :data => data)
35
32
  rescue => e
36
33
  log.error "Failed to serialize event", e
37
34
  return
@@ -42,7 +39,7 @@ module FFWD::Debug
42
39
  data = @type.serialize_metric metric
43
40
 
44
41
  begin
45
- send JSON.dump(:id => @id, :type => :metric, :data => data)
42
+ send JSON.dump(:id => channel.id, :type => :metric, :data => data)
46
43
  rescue => e
47
44
  log.error "Failed to serialize metric", e
48
45
  return
@@ -31,14 +31,15 @@ module FFWD::Debug
31
31
  @host = host
32
32
  @port = port
33
33
  @peer = "#{@host}:#{@port}"
34
+ info = "tcp://#{@peer}"
34
35
 
35
36
  r = FFWD.retry :timeout => rebind_timeout do |attempt|
36
37
  EM.start_server @host, @port, Connection, self
37
- log.info "Bind on tcp://#{@peer} (attempt #{attempt})"
38
+ log.info "Bind on #{info} (attempt #{attempt})"
38
39
  end
39
40
 
40
41
  r.error do |a, t, e|
41
- log.error "Failed to bind tcp://#{@peer} (attempt #{a}), retry in #{t}s", e
42
+ log.warning "Bind on #{info} failed, retry ##{a} in #{t}s: #{e}"
42
43
  end
43
44
 
44
45
  r.depend_on self
@@ -61,21 +62,25 @@ module FFWD::Debug
61
62
  end
62
63
 
63
64
  # Setup monitor hooks for the specified input and output channel.
64
- def monitor id, channel, type
65
- if session = @sessions[id]
66
- log.error "Session already monitored: #{id}"
67
- return
68
- end
65
+ def monitor channel, type
66
+ channel.starting do
67
+ if session = @sessions[channel.id]
68
+ log.error "Session already monitored: #{channel.id}"
69
+ return
70
+ end
69
71
 
70
- session = @sessions[id] = MonitorSession.new id, channel, type
72
+ session = MonitorSession.new channel, type
71
73
 
72
- # provide the session to the already connected clients.
73
- @clients.each do |peer, client|
74
- session.register peer, client
74
+ # provide the session to any already connected clients.
75
+ @clients.each do |peer, client|
76
+ session.register peer, client
77
+ end
78
+
79
+ @sessions[channel.id] = session
75
80
  end
76
81
 
77
82
  channel.stopping do
78
- @sessions.delete id
83
+ @sessions.delete channel.id
79
84
  end
80
85
  end
81
86
  end
@@ -21,7 +21,7 @@ module FFWD
21
21
  attr_accessor :parent
22
22
 
23
23
  def self.new signature, parent, *args
24
- instance = super(signature, *args)
24
+ instance = super(signature, parent, *args)
25
25
 
26
26
  instance.instance_eval do
27
27
  @parent = parent
@@ -28,7 +28,6 @@ module FFWD
28
28
  @options = config[:options]
29
29
  @setup_input_method = load_method @mod, config[:setup_input_method_name]
30
30
  @setup_output_method = load_method @mod, config[:setup_output_method_name]
31
- @setup_tunnel_method = load_method @mod, config[:setup_tunnel_method_name]
32
31
  end
33
32
 
34
33
  def capabilities
@@ -42,10 +41,6 @@ module FFWD
42
41
  capabilities << "output"
43
42
  end
44
43
 
45
- if not @setup_tunnel_method.nil?
46
- capabilities << "tunnel"
47
- end
48
-
49
44
  return capabilities
50
45
  end
51
46
 
@@ -56,7 +51,6 @@ module FFWD
56
51
  def get(kind)
57
52
  return @setup_input_method if kind == :input
58
53
  return @setup_output_method if kind == :output
59
- return @setup_tunnel_method if kind == :tunnel
60
54
  return nil
61
55
  end
62
56
 
@@ -69,16 +63,16 @@ module FFWD
69
63
  end
70
64
 
71
65
  class Setup
72
- attr_reader :name, :config
66
+ attr_reader :config, :name
73
67
 
74
- def initialize name, config, setup
75
- @name = name
68
+ def initialize method, config, name
69
+ @method = method
76
70
  @config = config
77
- @setup = setup
71
+ @name = name
78
72
  end
79
73
 
80
- def setup *args
81
- @setup.call @config, *args
74
+ def call *args
75
+ @method.call(*args)
82
76
  end
83
77
  end
84
78
 
@@ -100,7 +94,6 @@ module FFWD
100
94
 
101
95
  config[:setup_input_method_name] = (opts[:setup_input_method] || :setup_input)
102
96
  config[:setup_output_method_name] = (opts[:setup_output_method] || :setup_output)
103
- config[:setup_tunnel_method_name] = (opts[:setup_tunnel_method] || :setup_tunnel)
104
97
 
105
98
  FFWD::Plugin.discovered[name] = config
106
99
  end
@@ -122,7 +115,7 @@ module FFWD
122
115
  FFWD::Plugin.discovered.clear
123
116
  end
124
117
 
125
- def self.load_plugins log, kind_name, config, kind
118
+ def self.load_plugins log, kind_name, config, kind, m
126
119
  result = []
127
120
 
128
121
  return result if config.nil?
@@ -145,7 +138,19 @@ module FFWD
145
138
  next
146
139
  end
147
140
 
148
- result << Setup.new(name, plugin_config, setup)
141
+ factory = setup.call Hash[plugin_config]
142
+
143
+ unless factory.respond_to? m
144
+ log.error "#{d}: Plugin '#{name}' does not support '#{m.to_s}'"
145
+ next
146
+ end
147
+
148
+ unless factory.respond_to? :config
149
+ log.error "#{d}: Plugin '#{name}' does not support 'config'"
150
+ next
151
+ end
152
+
153
+ result << Setup.new(factory.method(m), factory.config, name)
149
154
  end
150
155
 
151
156
  return result
@@ -50,9 +50,7 @@ module FFWD::Plugin::JSON
50
50
  ])
51
51
  ]
52
52
 
53
- class LineConnection < FFWD::Connection
54
- include FFWD::Logging
55
- include FFWD::Plugin::JSON::Connection
53
+ class LineConnection < FFWD::Plugin::JSON::Connection
56
54
  include EM::Protocols::LineText2
57
55
 
58
56
  def self.plugin_type
@@ -64,10 +62,7 @@ module FFWD::Plugin::JSON
64
62
  end
65
63
  end
66
64
 
67
- class FrameConnection < FFWD::Connection
68
- include FFWD::Logging
69
- include FFWD::Plugin::JSON::Connection
70
-
65
+ class FrameConnection < FFWD::Plugin::JSON::Connection
71
66
  def self.plugin_type
72
67
  "json_frame_in"
73
68
  end
@@ -79,13 +74,18 @@ module FFWD::Plugin::JSON
79
74
 
80
75
  KINDS = {"frame" => FrameConnection, "line" => LineConnection}
81
76
 
82
- def self.setup_input opts, core
83
- kind = (opts[:kind] || DEFAULT_KIND).to_s
84
- raise "No such kind: #{kind}" unless connection = KINDS[kind]
85
- protocol = FFWD.parse_protocol opts[:protocol] || DEFAULT_PROTOCOL[kind]
77
+ def self.setup_input opts
86
78
  opts[:host] ||= DEFAULT_HOST
87
79
  opts[:port] ||= DEFAULT_PORT
88
80
 
81
+ kind = (opts[:kind] || DEFAULT_KIND).to_s
82
+
83
+ unless connection = KINDS[kind]
84
+ raise "No such protocol kind: #{kind}"
85
+ end
86
+
87
+ protocol = FFWD.parse_protocol opts[:protocol] || DEFAULT_PROTOCOL[kind]
88
+
89
89
  if connection == FrameConnection and protocol != FFWD::UDP
90
90
  log.warning "When using :frame kind, you should use the UDP protocol." +
91
91
  " Not #{protocol.family.to_s.upcase}"
@@ -96,14 +96,6 @@ module FFWD::Plugin::JSON
96
96
  "Not #{protocol.family.to_s.upcase}"
97
97
  end
98
98
 
99
- protocol.bind opts, core, log, connection
100
- end
101
-
102
- def self.setup_tunnel opts, core, tunnel
103
- protocol = FFWD.parse_protocol opts[:protocol] || "tcp"
104
- kind = (opts[:kind] || DEFAULT_KIND).to_s
105
- raise "No such kind: #{kind}" unless connection = KINDS[kind]
106
- opts[:port] ||= DEFAULT_PORT
107
- protocol.tunnel opts, core, tunnel, log, connection
99
+ protocol.bind opts, log, connection
108
100
  end
109
101
  end