ffwd 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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