fluent-plugin-config-expander 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-config-expander.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012- TAGOMORI Satoshi
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # fluent-plugin-config-expander
2
+
3
+ ## ConfigExpanderInput, ConfigExpanderOutput
4
+
5
+ ConfigExpanderInput and ConfigExpanderOutput plugins provide simple configuration template to write items repeatedly.
6
+ In <config> section, you can write actual configuration for actual input/output plugin, with special directives for loop controls.
7
+
8
+ ## Configuration
9
+
10
+ For both of input and output (for <source> and <match>), you can use 'config_expander' and its 'for' directive like below:
11
+
12
+ <match example.**>
13
+ type config_expander
14
+ <config>
15
+ type forward
16
+ flush_interval 30s
17
+ <for x in 01 02 03>
18
+ <server>
19
+ host worker__x__.local
20
+ port 24224
21
+ </server>
22
+ </for>
23
+ </config>
24
+ </match>
25
+
26
+ Configuration above is equal to below:
27
+
28
+ <match example.**>
29
+ type forward
30
+ flush_interval 30s
31
+ <server>
32
+ host worker01.local
33
+ port 24224
34
+ </server>
35
+ <server>
36
+ host worker02.local
37
+ port 24224
38
+ </server>
39
+ <server>
40
+ host worker03.local
41
+ port 24224
42
+ </server>
43
+ </match>
44
+
45
+ Nested 'for' directive is valid:
46
+
47
+ <match example.**>
48
+ type config_expander
49
+ <config>
50
+ type forward
51
+ flush_interval 30s
52
+ <for x in 01 02 03>
53
+ <for p in 24221 24222 24223 24224
54
+ <server>
55
+ host worker__x__.local
56
+ port __p__
57
+ </server>
58
+ </for>
59
+ </for>
60
+ </config>
61
+ </match>
62
+
63
+ ## TODO
64
+
65
+ * more tests
66
+ * patches welcome!
67
+
68
+ ## Copyright
69
+
70
+ * Copyright (c) 2012- TAGOMORI Satoshi (tagomoris)
71
+ * License
72
+ * Apache License, Version 2.0
73
+
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "fluent-plugin-config-expander"
5
+ gem.version = "0.0.1"
6
+ gem.authors = ["TAGOMORI Satoshi"]
7
+ gem.email = ["tagomoris@gmail.com"]
8
+ gem.description = %q{This plugin provides directives for loop extraction}
9
+ gem.summary = %q{Fluentd plugin to serve some DSL directives in configuration}
10
+ gem.homepage = "https://github.com/tagomoris/fluent-plugin-config-expander"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+
17
+ gem.add_development_dependency "rake"
18
+ gem.add_development_dependency "fluentd"
19
+ gem.add_runtime_dependency "fluentd"
20
+ end
File without changes
@@ -0,0 +1,31 @@
1
+ require 'fluent/config'
2
+
3
+ module Fluent::Config::Expander
4
+ def self.replace(str, mapping)
5
+ mapping.reduce(str){|r,p| str.gsub(p[0], p[1])}
6
+ end
7
+
8
+ def self.expand(element, mapping)
9
+ name = replace(element.name, mapping)
10
+ arg = replace(element.arg, mapping)
11
+ attrs = element.reduce({}){|r,p| r[replace(p.first, mapping)] = replace(p.last, mapping); r}
12
+ elements = []
13
+ element.elements.each do |e|
14
+ if e.name == 'for'
15
+ unless e.arg =~ /^([a-zA-Z0-9]+) in (.+)$/
16
+ raise Fluent::ConfigError, "invalid for tag syntax: <for NAME in ARG1 ARG2 ...>"
17
+ end
18
+ vname = '__' + $1 + '__'
19
+ vargs = $2.split(/ +/).select{|v| v.size > 0}
20
+ vargs.each do |v|
21
+ expanded = expand(e, mapping.merge({vname => v}))
22
+ attrs.update(expanded)
23
+ elements += expanded.elements.map{|xe| expand(xe, mapping)}
24
+ end
25
+ else
26
+ elements.push(expand(e, mapping))
27
+ end
28
+ end
29
+ Fluent::Config::Element.new(name, arg, attrs, elements, [])
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ require_relative 'expander'
2
+
3
+ class Fluent::ConfigExpanderInput < Fluent::Input
4
+ Fluent::Plugin.register_input('config_expander', self)
5
+
6
+ attr_accessor :plugin
7
+
8
+ def expand_config(conf)
9
+ ex = Fluent::Config::Expander.expand(conf, {})
10
+ ex.name = ''
11
+ ex.arg = ''
12
+ ex
13
+ end
14
+
15
+ def configure(conf)
16
+ super
17
+
18
+ configs = conf.elements.select{|e| e.name == 'config'}
19
+ if configs.size != 1
20
+ raise Fluent::ConfigError, "config_expander needs just one <config> ... </config> section"
21
+ end
22
+ ex = expand_config(configs.first)
23
+ @plugin = Fluent::Plugin.new_input(ex['type'])
24
+ @plugin.configure(ex)
25
+ end
26
+
27
+ def start
28
+ @plugin.start
29
+ end
30
+
31
+ def shutdown
32
+ @plugin.shutdown
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'expander'
2
+
3
+ class Fluent::ConfigExpanderOutput < Fluent::Output
4
+ Fluent::Plugin.register_output('config_expander', self)
5
+
6
+ attr_accessor :plugin
7
+
8
+ def expand_config(conf)
9
+ ex = Fluent::Config::Expander.expand(conf, {})
10
+ ex.name = ''
11
+ ex.arg = ''
12
+ ex
13
+ end
14
+
15
+ def configure(conf)
16
+ super
17
+
18
+ configs = conf.elements.select{|e| e.name == 'config'}
19
+ if configs.size != 1
20
+ raise Fluent::ConfigError, "config_expander needs just one <config> ... </config> section"
21
+ end
22
+ ex = expand_config(configs.first)
23
+ @plugin = Fluent::Plugin.new_output(ex['type'])
24
+ @plugin.configure(ex)
25
+ end
26
+
27
+ def start
28
+ @plugin.start
29
+ end
30
+
31
+ def shutdown
32
+ @plugin.shutdown
33
+ end
34
+
35
+ def emit(tag, es, chain)
36
+ @plugin.emit(tag, es, chain)
37
+ end
38
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/plugin/in_config_expander'
26
+ require 'fluent/plugin/out_config_expander'
27
+
28
+ class Test::Unit::TestCase
29
+ end
@@ -0,0 +1,132 @@
1
+ require 'helper'
2
+
3
+ class ConfigExpanderTest < Test::Unit::TestCase
4
+ def setup
5
+ @m = Fluent::Config::Expander
6
+ end
7
+
8
+ def test_replace
9
+ assert_equal nil, @m.replace(nil, {})
10
+ assert_equal "", @m.replace("", {})
11
+ assert_equal "", @m.replace("", {'foo' => 'bar'})
12
+ assert_equal "barbar", @m.replace("foobar", {'foo' => 'bar'})
13
+ assert_equal "foofoo", @m.replace("foobar", {'bar' => 'foo'})
14
+ assert_equal "foobar", @m.replace("foobar", {'hoge' => 'moge'})
15
+ assert_equal "xxbar", @m.replace("foofoobar", {'foo' => 'x'})
16
+ end
17
+
18
+ def test_expand
19
+ e1 = Fluent::Config::Element.new('config', '', {'attr_first'=>'value_first', 'attr_second'=>'__NUM__'}, [], [])
20
+ assert_equal "<config>\n attr_first value_first\n attr_second __NUM__\n</config>\n", e1.to_s
21
+ assert_equal "<config>\n attr_first value_first\n attr_second 24224\n</config>\n", @m.expand(e1, {'__NUM__' => '24224'}).to_s
22
+
23
+ e2 = Fluent::Config::Element.new('server', '', {'host'=> 'test', 'port'=>'__PORT__', 'ext'=>'__PORT__', 'num__PORT__'=>'1'}, [], [])
24
+ assert_equal "<server>\n host test\n port __PORT__\n ext __PORT__\n num__PORT__ 1\n</server>\n", e2.to_s
25
+ assert_equal "<server>\n host test\n port 24224\n ext 24224\n num24224 1\n</server>\n", @m.expand(e2, {'__PORT__' => '24224'}).to_s
26
+
27
+ e3 = Fluent::Config::Element.new('config', 'for __PORT__', {'attr_first'=>'value_first', 'attr_second'=>'__PORT__'}, [e2], [])
28
+ exconf1 = <<EOL
29
+ <config for 24224>
30
+ attr_first value_first
31
+ attr_second 24224
32
+ <server>
33
+ host test
34
+ port 24224
35
+ ext 24224
36
+ num24224 1
37
+ </server>
38
+ </config>
39
+ EOL
40
+ assert_equal exconf1, @m.expand(e3, {'__PORT__' => '24224'}).to_s
41
+
42
+ nonexconf2 = <<EOL
43
+ <config>
44
+ <for portnum in 24221 24222 24223 24224>
45
+ <server>
46
+ host node__nodenum__.local
47
+ port __portnum__
48
+ </server>
49
+ </for>
50
+ </config>
51
+ EOL
52
+ conf2 = Fluent::Config.parse(nonexconf2, 'hoge').elements.first
53
+ assert_equal nonexconf2, conf2.to_s
54
+ exconf2 = <<EOL
55
+ <config>
56
+ <server>
57
+ host node__nodenum__.local
58
+ port 24221
59
+ </server>
60
+ <server>
61
+ host node__nodenum__.local
62
+ port 24222
63
+ </server>
64
+ <server>
65
+ host node__nodenum__.local
66
+ port 24223
67
+ </server>
68
+ <server>
69
+ host node__nodenum__.local
70
+ port 24224
71
+ </server>
72
+ </config>
73
+ EOL
74
+ assert_equal exconf2, @m.expand(conf2, {}).to_s
75
+
76
+ nonexconf3 = <<EOL
77
+ <config>
78
+ type forward
79
+ flush_interval 1s
80
+ <for nodenum in 01 02 >
81
+ <for portnum in 24221 24222 24223 24224>
82
+ <server>
83
+ host node__nodenum__.local
84
+ port __portnum__
85
+ </server>
86
+ </for>
87
+ </for>
88
+ </config>
89
+ EOL
90
+ conf3 = Fluent::Config.parse(nonexconf3, 'hoge').elements.first
91
+ assert_equal nonexconf3, conf3.to_s
92
+ exconf3 = <<EOL
93
+ <config>
94
+ type forward
95
+ flush_interval 1s
96
+ <server>
97
+ host node01.local
98
+ port 24221
99
+ </server>
100
+ <server>
101
+ host node01.local
102
+ port 24222
103
+ </server>
104
+ <server>
105
+ host node01.local
106
+ port 24223
107
+ </server>
108
+ <server>
109
+ host node01.local
110
+ port 24224
111
+ </server>
112
+ <server>
113
+ host node02.local
114
+ port 24221
115
+ </server>
116
+ <server>
117
+ host node02.local
118
+ port 24222
119
+ </server>
120
+ <server>
121
+ host node02.local
122
+ port 24223
123
+ </server>
124
+ <server>
125
+ host node02.local
126
+ port 24224
127
+ </server>
128
+ </config>
129
+ EOL
130
+ assert_equal exconf3, @m.expand(conf3, {}).to_s
131
+ end
132
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+ require_relative '../plugins'
3
+
4
+ class ConfigExpanderInputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ CONFIG = %[
10
+ type config_expander
11
+ <config>
12
+ type config_expander_test
13
+ tag foobar
14
+ <for x in 1 2 3>
15
+ <node>
16
+ attr1 __x__
17
+ </node>
18
+ </for>
19
+ </config>
20
+ ]
21
+ def create_driver(conf=CONFIG)
22
+ Fluent::Test::InputTestDriver.new(Fluent::ConfigExpanderInput).configure(conf)
23
+ end
24
+
25
+ def test_configure
26
+ d = create_driver
27
+ assert_equal 'foobar', d.instance.plugin.tag
28
+ assert_equal 3, d.instance.plugin.nodes.size
29
+ assert_equal ['1','2','3'], d.instance.plugin.nodes.map{|n| n['attr1']}.sort
30
+
31
+ assert_equal false, d.instance.plugin.started
32
+ assert_equal false, d.instance.plugin.stopped
33
+
34
+ d.instance.start()
35
+ assert_equal true, d.instance.plugin.started
36
+ assert_equal false, d.instance.plugin.stopped
37
+
38
+ d.instance.shutdown()
39
+ assert_equal true, d.instance.plugin.stopped
40
+ end
41
+
42
+ end
@@ -0,0 +1,66 @@
1
+ require 'helper'
2
+ require_relative '../plugins'
3
+
4
+ class ConfigExpanderOutputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ CONFIG = %[
10
+ type config_expander
11
+ <config>
12
+ type config_expander_test
13
+ tag foobar
14
+ <for x in 1 2 3>
15
+ <node>
16
+ attr1 __x__
17
+ </node>
18
+ </for>
19
+ </config>
20
+ ]
21
+ def create_driver(conf=CONFIG, tag='test.default')
22
+ Fluent::Test::OutputTestDriver.new(Fluent::ConfigExpanderOutput, tag).configure(conf)
23
+ end
24
+
25
+ def test_configure
26
+ d = create_driver
27
+ assert_equal 'foobar', d.instance.plugin.tag
28
+ assert_equal 3, d.instance.plugin.nodes.size
29
+ assert_equal ['1','2','3'], d.instance.plugin.nodes.map{|n| n['attr1']}.sort
30
+
31
+ assert_equal false, d.instance.plugin.started
32
+ assert_equal false, d.instance.plugin.stopped
33
+
34
+ d.instance.start()
35
+ assert_equal true, d.instance.plugin.started
36
+ assert_equal false, d.instance.plugin.stopped
37
+
38
+ d.instance.shutdown()
39
+ assert_equal true, d.instance.plugin.stopped
40
+ end
41
+
42
+ def test_emit
43
+ d = create_driver
44
+ d.run do
45
+ d.emit({'field' => 'value1'})
46
+ d.emit({'field' => 'value2'})
47
+ d.emit({'field' => 'value3'})
48
+ end
49
+
50
+ emits = d.emits
51
+ assert_equal 3, emits.size
52
+
53
+ assert_equal 'foobar', emits[0][0]
54
+ assert_equal 'value1', emits[0][2]['field']
55
+ assert_equal 'expander', emits[0][2]['over']
56
+
57
+ assert_equal 'foobar', emits[1][0]
58
+ assert_equal 'value2', emits[1][2]['field']
59
+ assert_equal 'expander', emits[1][2]['over']
60
+
61
+ assert_equal 'foobar', emits[2][0]
62
+ assert_equal 'value3', emits[2][2]['field']
63
+ assert_equal 'expander', emits[2][2]['over']
64
+ end
65
+
66
+ end
data/test/plugins.rb ADDED
@@ -0,0 +1,58 @@
1
+ class Fluent::ConfigExpanderTestInput < Fluent::Input
2
+ Fluent::Plugin.register_input('config_expander_test', self)
3
+
4
+ config_param :tag, :string
5
+ attr_accessor :nodes
6
+ attr_accessor :started, :stopped
7
+
8
+ def configure(conf)
9
+ super
10
+ @nodes = []
11
+ conf.elements.each do |e|
12
+ next if e.name != 'node'
13
+ @nodes << {}.merge(e)
14
+ end
15
+ @started = @stopped = false
16
+ end
17
+ def start
18
+ super
19
+ @started = true
20
+ end
21
+ def shutdown
22
+ super
23
+ @stopped = true
24
+ end
25
+ end
26
+
27
+ class Fluent::ConfigExpanderTestOutput < Fluent::Output
28
+ Fluent::Plugin.register_output('config_expander_test', self)
29
+
30
+ config_param :tag, :string
31
+ attr_accessor :nodes
32
+ attr_accessor :started, :stopped
33
+
34
+ def configure(conf)
35
+ super
36
+ @nodes = []
37
+ conf.elements.each do |e|
38
+ next if e.name != 'node'
39
+ @nodes << {}.merge(e)
40
+ end
41
+ @started = @stopped = false
42
+ end
43
+ def start
44
+ super
45
+ @started = true
46
+ end
47
+ def shutdown
48
+ super
49
+ @stopped = true
50
+ end
51
+
52
+ def emit(tag, es, chain)
53
+ es.each do |time, record|
54
+ Fluent::Engine.emit(@tag, time, record.merge({'over' => 'expander'}))
55
+ end
56
+ chain.next
57
+ end
58
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-config-expander
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: fluentd
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: fluentd
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: This plugin provides directives for loop extraction
63
+ email:
64
+ - tagomoris@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - fluent-plugin-config-expander.gemspec
75
+ - lib/fluent/plugin/config_ext.rb
76
+ - lib/fluent/plugin/expander.rb
77
+ - lib/fluent/plugin/in_config_expander.rb
78
+ - lib/fluent/plugin/out_config_expander.rb
79
+ - test/helper.rb
80
+ - test/plugin/test_expander.rb
81
+ - test/plugin/test_in_config_expander.rb
82
+ - test/plugin/test_out_config_expander.rb
83
+ - test/plugins.rb
84
+ homepage: https://github.com/tagomoris/fluent-plugin-config-expander
85
+ licenses: []
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.21
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Fluentd plugin to serve some DSL directives in configuration
108
+ test_files:
109
+ - test/helper.rb
110
+ - test/plugin/test_expander.rb
111
+ - test/plugin/test_in_config_expander.rb
112
+ - test/plugin/test_out_config_expander.rb
113
+ - test/plugins.rb