fluent-plugin-config-expander 0.0.1

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