Skip to content

Commit 0d3f43e

Browse files
committed
config: fix duplicate config file loading in config_include_dir
Signed-off-by: Shizuo Fujita <fujita@clear-code.com>
1 parent a22ce7f commit 0d3f43e

6 files changed

Lines changed: 44 additions & 21 deletions

File tree

lib/fluent/config.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module Config
2626
# @param additional_config [String] config which is added to last of config body
2727
# @param use_v1_config [Bool] config is formatted with v1 or not
2828
# @return [Fluent::Config]
29-
def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil)
29+
def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil, on_file_parsed: nil)
3030
if type == :guess
3131
config_file_ext = File.extname(config_path)
3232
if config_file_ext == '.yaml' || config_file_ext == '.yml'
@@ -35,7 +35,7 @@ def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_c
3535
end
3636

3737
if type == :yaml || type == :yml
38-
return Fluent::Config::YamlParser.parse(config_path)
38+
return Fluent::Config::YamlParser.parse(config_path, on_file_parsed: on_file_parsed)
3939
end
4040

4141
config_fname = File.basename(config_path)
@@ -49,10 +49,10 @@ def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_c
4949
s
5050
end
5151

52-
Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config)
52+
Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config, on_file_parsed: on_file_parsed)
5353
end
5454

55-
def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1)
55+
def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1, on_file_parsed: nil)
5656
parser = if fname =~ /\.rb$/ || syntax == :ruby
5757
:ruby
5858
elsif v1_config.nil?
@@ -68,7 +68,7 @@ def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1)
6868
case parser
6969
when :v1
7070
require 'fluent/config/v1_parser'
71-
V1Parser.parse(str, fname, basepath, Kernel.binding)
71+
V1Parser.parse(str, fname, basepath, Kernel.binding, on_file_parsed: on_file_parsed)
7272
when :v0
7373
# TODO: show deprecated message in v1
7474
require 'fluent/config/parser'

lib/fluent/config/v1_parser.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,18 @@ module Config
2727
class V1Parser < LiteralParser
2828
ELEMENT_NAME = /[a-zA-Z0-9_]+/
2929

30-
def self.parse(data, fname, basepath = Dir.pwd, eval_context = nil)
30+
def self.parse(data, fname, basepath = Dir.pwd, eval_context = nil, on_file_parsed: nil)
3131
ss = StringScanner.new(data)
32-
ps = V1Parser.new(ss, basepath, fname, eval_context)
32+
ps = V1Parser.new(ss, basepath, fname, eval_context, on_file_parsed: on_file_parsed)
3333
ps.parse!
3434
end
3535

36-
def initialize(strscan, include_basepath, fname, eval_context)
36+
def initialize(strscan, include_basepath, fname, eval_context, on_file_parsed: nil)
3737
super(strscan, eval_context)
3838
@include_basepath = include_basepath
3939
@fname = fname
4040
@logger = defined?($log) ? $log : nil
41+
@on_file_parsed = on_file_parsed
4142
end
4243

4344
def parse!
@@ -138,6 +139,8 @@ def parse_element(root_element, elem_name, attrs = {}, elems = [])
138139
end
139140
end
140141

142+
@on_file_parsed&.call(File.join(@include_basepath, @fname)) if root_element
143+
141144
return attrs, elems
142145
end
143146

@@ -166,7 +169,7 @@ def eval_include(attrs, elems, uri)
166169
data = File.read(entry)
167170
data.force_encoding('UTF-8')
168171
ss = StringScanner.new(data)
169-
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
172+
V1Parser.new(ss, basepath, fname, @eval_context, on_file_parsed: @on_file_parsed).parse_element(true, nil, attrs, elems)
170173
}
171174
else
172175
require 'open-uri'
@@ -175,7 +178,7 @@ def eval_include(attrs, elems, uri)
175178
data = u.open { |f| f.read }
176179
data.force_encoding('UTF-8')
177180
ss = StringScanner.new(data)
178-
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
181+
V1Parser.new(ss, basepath, fname, @eval_context, on_file_parsed: @on_file_parsed).parse_element(true, nil, attrs, elems)
179182
end
180183
rescue SystemCallError => e
181184
cpe = ConfigParseError.new("include error #{uri} - #{e}")

lib/fluent/config/yaml_parser.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
module Fluent
2222
module Config
2323
module YamlParser
24-
def self.parse(path)
24+
def self.parse(path, on_file_parsed: nil)
2525
context = Kernel.binding
2626

2727
unless context.respond_to?(:use_nil)
@@ -48,7 +48,7 @@ def self.parse(path)
4848
end
4949
end
5050

51-
s = Fluent::Config::YamlParser::Loader.new(context).load(Pathname.new(path))
51+
s = Fluent::Config::YamlParser::Loader.new(context, on_file_parsed: on_file_parsed).load(Pathname.new(path))
5252
Fluent::Config::YamlParser::Parser.new(s).build.to_element
5353
end
5454
end

lib/fluent/config/yaml_parser/loader.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ class Loader
3030
FLUENT_STR_TAG = 'tag:fluent/s'.freeze
3131
SHOVEL = '<<'.freeze
3232

33-
def initialize(context = Kernel.binding)
33+
def initialize(context = Kernel.binding, on_file_parsed: nil)
3434
@context = context
3535
@current_path = nil
36+
@on_file_parsed = on_file_parsed
3637
end
3738

3839
# @param [String] path
@@ -55,9 +56,13 @@ def load(path)
5556
Fluent::Config::YamlParser::FluentValue::StringValue.new(val, @context)
5657
end
5758

58-
path.open do |f|
59+
config = path.open do |f|
5960
visitor.accept(Psych.parse(f))
6061
end
62+
63+
@on_file_parsed&.call(path.to_s)
64+
65+
config
6166
end
6267

6368
def eval_include(path, parent)

lib/fluent/supervisor.rb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
require 'open3'
1919
require 'pathname'
2020
require 'find'
21+
require 'set'
2122

2223
require 'fluent/config'
2324
require 'fluent/counter'
@@ -796,18 +797,20 @@ def configure(supervisor: false)
796797
$log.warn('the value "-" for `inline_config` is deprecated. See https://github.com/fluent/fluentd/issues/2711')
797798
@inline_config = STDIN.read
798799
end
800+
parsed_files = Set.new
799801
@conf = Fluent::Config.build(
800802
config_path: @config_path,
801803
encoding: @conf_encoding,
802804
additional_config: @inline_config,
803805
use_v1_config: @use_v1_config,
804806
type: @config_file_type,
807+
on_file_parsed: ->(path) { parsed_files << path },
805808
)
806809
@system_config = build_system_config(@conf)
807810

808811
$log.info :supervisor, 'parsing config file is succeeded', path: @config_path
809812

810-
build_additional_configurations do |additional_conf|
813+
build_additional_configurations(parsed_files) do |additional_conf|
811814
@conf += additional_conf
812815
end
813816

@@ -854,6 +857,7 @@ def setup_global_logger(supervisor: false)
854857
additional_config: @inline_config,
855858
use_v1_config: @use_v1_config,
856859
type: @config_file_type,
860+
on_file_parsed: nil,
857861
)
858862
system_config = build_system_config(conf)
859863

@@ -1088,15 +1092,17 @@ def reload_config
10881092
$log.debug('worker got SIGUSR2')
10891093

10901094
begin
1095+
parsed_files = Set.new
10911096
conf = Fluent::Config.build(
10921097
config_path: @config_path,
10931098
encoding: @conf_encoding,
10941099
additional_config: @inline_config,
10951100
use_v1_config: @use_v1_config,
10961101
type: @config_file_type,
1102+
on_file_parsed: ->(path) { parsed_files << path },
10971103
)
10981104

1099-
build_additional_configurations do |additional_conf|
1105+
build_additional_configurations(parsed_files) do |additional_conf|
11001106
conf += additional_conf
11011107
end
11021108

@@ -1206,7 +1212,7 @@ def build_system_config(conf)
12061212
system_config
12071213
end
12081214

1209-
def build_additional_configurations
1215+
def build_additional_configurations(parsed_files)
12101216
if @system_config.config_include_dir&.empty?
12111217
$log.info :supervisor, 'configuration include directory is disabled'
12121218
return
@@ -1218,11 +1224,17 @@ def build_additional_configurations
12181224
next unless supported_suffixes.include?(File.extname(path))
12191225
# NOTE: both types of normal config (.conf) and YAML will be loaded.
12201226
# Thus, it does not care whether @config_path is .conf or .yml.
1227+
if parsed_files.include?(path)
1228+
$log.info :supervisor, 'skip auto loading, it was already loaded', path: path
1229+
next
1230+
end
1231+
12211232
$log.info :supervisor, 'loading additional configuration file', path: path
12221233
yield Fluent::Config.build(config_path: path,
12231234
encoding: @conf_encoding,
12241235
use_v1_config: @use_v1_config,
1225-
type: :guess)
1236+
type: :guess,
1237+
on_file_parsed: nil)
12261238
end
12271239
rescue Errno::ENOENT
12281240
$log.info :supervisor, 'inaccessible include directory was specified', path: @system_config.config_include_dir

test/test_supervisor.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,8 @@ def test_stop_parallel_old_supervisor_after_delay
10851085
stub.proxy(Fluent::Config).build
10861086
stub(Fluent::Config).build(config_path: "/etc/fluent/fluent.conf", encoding: "utf-8",
10871087
additional_config: anything, use_v1_config: anything,
1088-
type: anything) { config_element('ROOT', '', {}, [c]) }
1088+
type: anything,
1089+
on_file_parsed: anything) { config_element('ROOT', '', {}, [c]) }
10891090
sources.each do |type|
10901091
config = <<~EOF
10911092
<source>
@@ -1111,7 +1112,8 @@ def test_stop_parallel_old_supervisor_after_delay
11111112
stub.proxy(Fluent::Config).build
11121113
stub(Fluent::Config).build(config_path: "/etc/fluent/fluent.conf", encoding: "utf-8",
11131114
additional_config: anything, use_v1_config: anything,
1114-
type: anything) { config_element('ROOT', '', {}, [c]) }
1115+
type: anything,
1116+
on_file_parsed: anything) { config_element('ROOT', '', {}, [c]) }
11151117
sources.each do |type|
11161118
config = <<~EOF
11171119
config:
@@ -1139,7 +1141,8 @@ def test_stop_parallel_old_supervisor_after_delay
11391141
stub.proxy(Fluent::Config).build
11401142
stub(Fluent::Config).build(config_path: "/etc/fluent/fluent.conf", encoding: "utf-8",
11411143
additional_config: anything, use_v1_config: anything,
1142-
type: anything) { config_element('ROOT', '', {}, [c]) }
1144+
type: anything,
1145+
on_file_parsed: anything) { config_element('ROOT', '', {}, [c]) }
11431146
sources.each do |type|
11441147
if yaml
11451148
config = <<~EOF

0 commit comments

Comments
 (0)