class Fluent::Config::ConfigureProxy

Attributes

alias[RW]
argument[RW]
configured_in_section[RW]
defaults[RW]
descriptions[RW]
final[RW]
init[RW]
multi[RW]
name[RW]
param_name[RW]
params[RW]
required[RW]
sections[RW]

Public Class Methods

new(name, root: false, param_name: nil, final: nil, init: nil, required: nil, multi: nil, alias: nil, type_lookup:) click to toggle source

#config_param :desc, :string, default: '.…' #config_set_default :buffer_type, :memory

#config_section :default, required: true, multi: false do

config_argument :arg, :string
config_param :required, :bool, default: false
config_param :name, :string
config_param :power, :integer

end

#config_section :child, #param_name: 'children', required: false, multi: true, alias: 'node' do

config_param :name, :string
config_param :power, :integer, default: nil
config_section :item do
  config_param :name
end

end

# File lib/fluent/config/configure_proxy.rb, line 40
def initialize(name, root: false, param_name: nil, final: nil, init: nil, required: nil, multi: nil, alias: nil, type_lookup:)
  @name = name.to_sym
  @final = final

  # For ConfigureProxy of root section, "@name" should be a class name of plugins.
  # Otherwise (like subsections), "@name" should be a name of section, like "buffer", "store".
  # For subsections, name will be used as parameter names (unless param_name exists), so overriding proxy's name
  #   should override "@name".
  @root_section = root

  @param_name = param_name && param_name.to_sym
  @init = init
  @required = required
  @multi = multi
  @alias = binding.local_variable_get(:alias)
  @type_lookup = type_lookup

  raise "init and required are exclusive" if @init && @required

  # specify section name for viewpoint of owner(parent) plugin
  # for buffer plugins: all params are in <buffer> section of owner
  # others: <storage>, <format> (formatter/parser), ...
  @configured_in_section = nil

  @argument = nil # nil: ignore argument
  @params = {}
  @defaults = {}
  @descriptions = {}
  @sections = {}
  @current_description = nil
end

Public Instance Methods

config_argument(name, type = nil, **kwargs, &block) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 307
def config_argument(name, type = nil, **kwargs, &block)
  if @argument
    raise ArgumentError, "#{self.name}: config_argument called twice"
  end
  name, block, opts = parameter_configuration(name, type, **kwargs, &block)

  @argument = [name, block, opts]
  name
end
config_param(name, type = nil, **kwargs, &block) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 317
def config_param(name, type = nil, **kwargs, &block)
  name, block, opts = parameter_configuration(name, type, **kwargs, &block)

  if @current_description
    config_set_desc(name, @current_description)
    @current_description = nil
  end

  @sections.delete(name)
  @params[name] = [block, opts]
  name
end
config_parameter_option_validate!(name, type, **kwargs, &block) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 229
def config_parameter_option_validate!(name, type, **kwargs, &block)
  if type.nil? && !block
    type = :string
  end
  kwargs.each_key do |key|
    case key
    when :default, :alias, :secret, :skip_accessor, :deprecated, :obsoleted, :desc
      # valid for all types
    when :list
      raise ArgumentError, ":list is valid only for :enum type, but #{type}: #{name}" if type != :enum
    when :value_type
      raise ArgumentError, ":value_type is valid only for :hash and :array, but #{type}: #{name}" if type != :hash && type != :array
    when :symbolize_keys
      raise ArgumentError, ":symbolize_keys is valid only for :hash, but #{type}: #{name}" if type != :hash
    else
      raise ArgumentError, "unknown option '#{key}' for configuration parameter: #{name}"
    end
  end
end
config_section(name, **kwargs, &block) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 356
def config_section(name, **kwargs, &block)
  unless block_given?
    raise ArgumentError, "#{name}: config_section requires block parameter"
  end
  name = name.to_sym

  sub_proxy = ConfigureProxy.new(name, type_lookup: @type_lookup, **kwargs)
  sub_proxy.instance_exec(&block)

  @params.delete(name)
  @sections[name] = sub_proxy

  name
end
config_set_default(name, defval) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 330
def config_set_default(name, defval)
  name = name.to_sym

  if @defaults.has_key?(name)
    raise ArgumentError, "#{self.name}: default value specified twice for #{name}"
  end

  @defaults[name] = defval
  nil
end
config_set_desc(name, description) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 341
def config_set_desc(name, description)
  name = name.to_sym

  if @descriptions.has_key?(name)
    raise ArgumentError, "#{self.name}: description specified twice for #{name}"
  end

  @descriptions[name] = description
  nil
end
configured_in(section_name) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 300
def configured_in(section_name)
  if @configured_in_section
    raise ArgumentError, "#{self.name}: configured_in called twice"
  end
  @configured_in_section = section_name.to_sym
end
desc(description) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 352
def desc(description)
  @current_description = description
end
dump_config_definition() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 371
def dump_config_definition
  dumped_config = {}
  if @argument
    argument_name, _block, options = @argument
    options[:required] = !@defaults.key?(argument_name)
    options[:argument] = true
    dumped_config[argument_name] = options
  end
  @params.each do |name, config|
    dumped_config[name] = config[1]
    dumped_config[name][:required] = !@defaults.key?(name)
    dumped_config[name][:default] = @defaults[name] if @defaults.key?(name)
    dumped_config[name][:desc] = @descriptions[name] if @descriptions.key?(name)
  end
  # Overwrite by config_set_default
  @defaults.each do |name, value|
    if @params.key?(name) || (@argument && @argument.first == name)
      dumped_config[name][:default] = value
    else
      dumped_config[name] = { default: value }
    end
  end
  # Overwrite by config_set_desc
  @descriptions.each do |name, value|
    if @params.key?(name)
      dumped_config[name][:desc] = value
    else
      dumped_config[name] = { desc: value }
    end
  end
  @sections.each do |section_name, sub_proxy|
    if dumped_config.key?(section_name)
      dumped_config[section_name].update(sub_proxy.dump_config_definition)
    else
      dumped_config[section_name] = sub_proxy.dump_config_definition
      dumped_config[section_name][:required] = sub_proxy.required?
      dumped_config[section_name][:multi] = sub_proxy.multi?
      dumped_config[section_name][:alias] = sub_proxy.alias
      dumped_config[section_name][:section] = true
    end
  end
  dumped_config
end
final?() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 92
def final?
  !!@final
end
init?() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 80
def init?
  @init.nil? ? false : @init
end
merge(other) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 96
def merge(other) # self is base class, other is subclass
  return merge_for_finalized(other) if self.final?

  [:param_name, :required, :multi, :alias, :configured_in_section].each do |prohibited_name|
    if overwrite?(other, prohibited_name)
      raise ConfigError, "BUG: subclass cannot overwrite base class's config_section: #{prohibited_name}"
    end
  end

  options = {}
  # param_name affects instance variable name, which is just "internal" of each plugins.
  # so it must not be changed. base class's name (or param_name) is always used.
  options[:param_name] = @param_name

  # subclass cannot overwrite base class's definition
  options[:init] = @init.nil? ? other.init : self.init
  options[:required] = @required.nil? ? other.required : self.required
  options[:multi] = @multi.nil? ? other.multi : self.multi
  options[:alias] = @alias.nil? ? other.alias : self.alias
  options[:final] = @final || other.final
  options[:type_lookup] = @type_lookup

  merged = if self.root?
             options[:root] = true
             self.class.new(other.name, options)
           else
             self.class.new(@name, options)
           end

  # configured_in MUST be kept
  merged.configured_in_section = self.configured_in_section || other.configured_in_section

  merged.argument = other.argument || self.argument
  merged.params = self.params.merge(other.params)
  merged.defaults = self.defaults.merge(other.defaults)
  merged.sections = {}
  (self.sections.keys + other.sections.keys).uniq.each do |section_key|
    self_section = self.sections[section_key]
    other_section = other.sections[section_key]
    merged_section = if self_section && other_section
                       self_section.merge(other_section)
                     elsif self_section || other_section
                       self_section || other_section
                     else
                       raise "BUG: both of self and other section are nil"
                     end
    merged.sections[section_key] = merged_section
  end

  merged
end
merge_for_finalized(other) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 148
def merge_for_finalized(other)
  # list what subclass can do for finalized section
  #  * append params/defaults/sections which are missing in superclass
  #  * change default values of superclass
  #  * overwrite init to make it enable to instantiate section objects with added default values

  if other.final == false && overwrite?(other, :final)
    raise ConfigError, "BUG: subclass cannot overwrite finalized base class's config_section"
  end

  [:param_name, :required, :multi, :alias, :configured_in_section].each do |prohibited_name|
    if overwrite?(other, prohibited_name)
      raise ConfigError, "BUG: subclass cannot overwrite base class's config_section: #{prohibited_name}"
    end
  end

  options = {}
  options[:param_name] = @param_name
  options[:init] = @init || other.init
  options[:required] = @required.nil? ? other.required : self.required
  options[:multi] = @multi.nil? ? other.multi : self.multi
  options[:alias] = @alias.nil? ? other.alias : self.alias
  options[:final]  = true
  options[:type_lookup] = @type_lookup

  merged = if self.root?
             options[:root] = true
             self.class.new(other.name, options)
           else
             self.class.new(@name, options)
           end

  merged.configured_in_section = self.configured_in_section || other.configured_in_section

  merged.argument = self.argument || other.argument
  merged.params = other.params.merge(self.params)
  merged.defaults = self.defaults.merge(other.defaults)
  merged.sections = {}
  (self.sections.keys + other.sections.keys).uniq.each do |section_key|
    self_section = self.sections[section_key]
    other_section = other.sections[section_key]
    merged_section = if self_section && other_section
                       other_section.merge(self_section)
                     elsif self_section || other_section
                       self_section || other_section
                     else
                       raise "BUG: both of self and other section are nil"
                     end
    merged.sections[section_key] = merged_section
  end

  merged
end
multi?() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 88
def multi?
  @multi.nil? ? true : @multi
end
option_value_type!(name, opts, key, klass=nil, type: nil) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 211
def option_value_type!(name, opts, key, klass=nil, type: nil)
  if opts.has_key?(key)
    if klass && !opts[key].is_a?(klass)
      raise ArgumentError, "#{name}: #{key} must be a #{klass}, but #{opts[key].class}"
    end
    case type
    when :boolean
      unless opts[key].is_a?(TrueClass) || opts[key].is_a?(FalseClass)
        raise ArgumentError, "#{name}: #{key} must be true or false, but #{opts[key].class}"
      end
    when nil
      # ignore
    else
      raise "unknown type: #{type} for option #{key}"
    end
  end
end
overwrite_defaults(other) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 202
def overwrite_defaults(other) # other is owner plugin's corresponding proxy
  self.defaults = self.defaults.merge(other.defaults)
  self.sections.keys.each do |section_key|
    if other.sections.has_key?(section_key)
      self.sections[section_key].overwrite_defaults(other.sections[section_key])
    end
  end
end
parameter_configuration(name, type = nil, **kwargs, &block) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 249
def parameter_configuration(name, type = nil, **kwargs, &block)
  config_parameter_option_validate!(name, type, **kwargs, &block)

  name = name.to_sym

  if block && type
    raise ArgumentError, "#{name}: both of block and type cannot be specified"
  elsif !block && !type
    type = :string
  end
  opts = {}
  opts[:type] = type
  opts.merge!(kwargs)

  begin
    block ||= @type_lookup.call(type)
  rescue ConfigError
    # override error message
    raise ArgumentError, "#{name}: unknown config_argument type `#{type}'"
  end

  # options for config_param
  option_value_type!(name, opts, :desc, String)
  option_value_type!(name, opts, :alias, Symbol)
  option_value_type!(name, opts, :secret, type: :boolean)
  option_value_type!(name, opts, :deprecated, String)
  option_value_type!(name, opts, :obsoleted, String)
  if type == :enum
    if !opts.has_key?(:list) || !opts[:list].is_a?(Array) || opts[:list].empty? || !opts[:list].all?{|v| v.is_a?(Symbol) }
      raise ArgumentError, "#{name}: enum parameter requires :list of Symbols"
    end
  end
  option_value_type!(name, opts, :symbolize_keys, type: :boolean)
  option_value_type!(name, opts, :value_type, Symbol) # hash, array
  option_value_type!(name, opts, :skip_accessor, type: :boolean)

  if opts.has_key?(:default)
    config_set_default(name, opts[:default])
  end

  if opts.has_key?(:desc)
    config_set_desc(name, opts[:desc])
  end

  if opts[:deprecated] && opts[:obsoleted]
    raise ArgumentError, "#{name}: both of deprecated and obsoleted cannot be specified at once"
  end

  [name, block, opts]
end
required?() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 84
def required?
  @required.nil? ? false : @required
end
root?() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 76
def root?
  @root_section
end
variable_name() click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 72
def variable_name
  @param_name || @name
end

Private Instance Methods

overwrite?(other, attribute_name) click to toggle source
# File lib/fluent/config/configure_proxy.rb, line 417
def overwrite?(other, attribute_name)
  value = instance_variable_get("@#{attribute_name}")
  other_value = other.__send__(attribute_name)
  !value.nil? && !other_value.nil? && value != other_value
end