Skip to content

Commit

Permalink
Merge pull request #1186 from fluent/deprecated-parameter
Browse files Browse the repository at this point in the history
config_param options to specify deprecated/obsoleted parameters
  • Loading branch information
tagomoris authored and repeatedly committed Sep 5, 2016
1 parent c804a5b commit 5f0c0b9
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 9 deletions.
27 changes: 24 additions & 3 deletions lib/fluent/config/configure_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ def merge_for_finalized(other)
merged
end

def option_value_type!(name, opts, key, klass)
if opts.has_key?(key) && !opts[key].is_a?(klass)
raise ArgumentError, "#{name}: #{key} must be a #{klass}, but #{opts[key].class}"
end
end

def parameter_configuration(name, *args, &block)
name = name.to_sym

Expand All @@ -145,16 +151,27 @@ def parameter_configuration(name, *args, &block)

type = opts[:type]
if block && type
raise ArgumentError, "#{self.name}: both of block and type cannot be specified"
raise ArgumentError, "#{name}: both of block and type cannot be specified"
end

begin
type = :string if type.nil?
block ||= Configurable.lookup_type(type)
rescue ConfigError
# override error message
raise ArgumentError, "#{self.name}: unknown config_argument type `#{type}'"
raise ArgumentError, "#{name}: unknown config_argument type `#{type}'"
end

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

if opts.has_key?(:default)
config_set_default(name, opts[:default])
Expand All @@ -164,6 +181,10 @@ def parameter_configuration(name, *args, &block)
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

Expand Down Expand Up @@ -218,7 +239,7 @@ def desc(description)

def config_section(name, *args, &block)
unless block_given?
raise ArgumentError, "#{self.name}: config_section requires block parameter"
raise ArgumentError, "#{name}: config_section requires block parameter"
end
name = name.to_sym

Expand Down
3 changes: 3 additions & 0 deletions lib/fluent/config/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ class ConfigError < StandardError

class ConfigParseError < ConfigError
end

class ObsoletedParameterError < ConfigError
end
end
15 changes: 15 additions & 0 deletions lib/fluent/config/section.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def self.generate(proxy, conf, logger, plugin_class, stack = [])
logger.error "config error in:\n#{conf}"
raise ConfigError, "'<#{proxy.name} ARG>' section requires argument" + section_stack
end
# argument should NOT be deprecated... (argument always has a value: '')
end

proxy.params.each_pair do |name, defval|
Expand All @@ -112,6 +113,20 @@ def self.generate(proxy, conf, logger, plugin_class, stack = [])
conf[opts[:alias].to_s]
end
section_params[varname] = self.instance_exec(val, opts, name, &block)

# Source of definitions of deprecated/obsoleted:
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features
#
# Deprecated: These deprecated features can still be used, but should be used with caution
# because they are expected to be removed entirely sometime in the future.
# Obsoleted: These obsolete features have been entirely removed from JavaScript and can no longer be used.
if opts[:deprecated]
logger.warn "'#{name}' parameter is deprecated: #{opts[:deprecated]}"
end
if opts[:obsoleted]
logger.error "config error in:\n#{conf}" if logger
raise ObsoletedParameterError, "'#{name}' parameter is already removed: #{opts[:obsoleted]}" + section_stack
end
end
unless section_params.has_key?(varname)
logger.error "config error in:\n#{conf}"
Expand Down
5 changes: 2 additions & 3 deletions lib/fluent/plugin/out_forward.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ def initialize

attr_reader :nodes

# backward compatibility
config_param :port, :integer, default: DEFAULT_LISTEN_PORT
config_param :host, :string, default: nil
config_param :port, :integer, default: LISTEN_PORT, deprecated: "User <server> host xxx </server> instead."
config_param :host, :string, default: nil, deprecated: "Use <server> port xxx </server> instead."

attr_accessor :extend_internal_protocol

Expand Down
271 changes: 271 additions & 0 deletions test/config/test_configurable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,195 @@ class Example5
config_param :secret_param2, :string, secret: true
end
end

class Example6
include Fluent::Configurable
config_param :obj1, :hash, default: {}
config_param :obj2, :array, default: []
end

module Overwrite
class Base
include Fluent::Configurable

config_param :name, :string, alias: :fullname
config_param :bool, :bool, alias: :flag
config_section :detail, required: false, multi: false, alias: "information" do
config_param :address, :string, default: "x"
end
end

class Required < Base
config_section :detail, required: true do
config_param :address, :string, default: "x"
end
end

class Multi < Base
config_section :detail, multi: true do
config_param :address, :string, default: "x"
end
end

class Alias < Base
config_section :detail, alias: "information2" do
config_param :address, :string, default: "x"
end
end

class DefaultOptions < Base
config_section :detail do
config_param :address, :string, default: "x"
end
end

class DetailAddressDefault < Base
config_section :detail do
config_param :address, :string, default: "y"
end
end

class AddParam < Base
config_section :detail do
config_param :phone_no, :string
end
end

class AddParamOverwriteAddress < Base
config_section :detail do
config_param :address, :string, default: "y"
config_param :phone_no, :string
end
end
end

module Final
# Show what is allowed in finalized sections
# InheritsFinalized < Finalized < Base
class Base
include Fluent::Configurable
config_section :appendix, multi: false, final: false do
config_param :code, :string
config_param :name, :string
config_param :address, :string, default: ""
end
end

class Finalized < Base
# to non-finalized section
# subclass can change type (code)
# add default value (name)
# change default value (address)
# add field (age)
config_section :appendix, final: true do
config_param :code, :integer
config_set_default :name, "y"
config_set_default :address, "-"
config_param :age, :integer, default: 10
end
end

class InheritsFinalized < Finalized
# to finalized section
# subclass can add default value (code)
# change default value (age)
# add field (phone_no)
config_section :appendix do
config_set_default :code, 2
config_set_default :age, 0
config_param :phone_no, :string
end
end

# Show what is allowed/prohibited for finalized sections
class FinalizedBase
include Fluent::Configurable
config_section :appendix, param_name: :apd, init: false, required: true, multi: false, alias: "options", final: true do
config_param :name, :string
end
end

class FinalizedBase2
include Fluent::Configurable
config_section :appendix, param_name: :apd, init: false, required: false, multi: false, alias: "options", final: true do
config_param :name, :string
end
end

# subclass can change init with adding default values
class OverwriteInit < FinalizedBase2
config_section :appendix, init: true do
config_set_default :name, "moris"
config_param :code, :integer, default: 0
end
end

# subclass cannot change type (name)
class Subclass < FinalizedBase
config_section :appendix do
config_param :name, :integer
end
end

# subclass cannot change param_name
class OverwriteParamName < FinalizedBase
config_section :appendix, param_name: :adx do
end
end

# subclass cannot change final (section)
class OverwriteFinal < FinalizedBase
config_section :appendix, final: false do
config_param :name, :integer
end
end

# subclass cannot change required
class OverwriteRequired < FinalizedBase
config_section :appendix, required: false do
end
end

# subclass cannot change multi
class OverwriteMulti < FinalizedBase
config_section :appendix, multi: true do
end
end

# subclass cannot change alias
class OverwriteAlias < FinalizedBase
config_section :appendix, alias: "options2" do
end
end
end

module OverwriteDefaults
class Owner
include Fluent::Configurable
config_set_default :key1, "V1"
config_section :buffer do
config_set_default :size_of_something, 1024
end
end

class SubOwner < Owner
config_section :buffer do
config_set_default :size_of_something, 2048
end
end

class FlatChild
include Fluent::Configurable
attr_accessor :owner
config_param :key1, :string, default: "v1"
end
end
class UnRecommended
include Fluent::Configurable
attr_accessor :log
config_param :key1, :string, default: 'deprecated', deprecated: "key1 will be removed."
config_param :key2, :string, default: 'obsoleted', obsoleted: "key2 has been removed."
end
end

module Fluent::Config
Expand Down Expand Up @@ -740,5 +929,87 @@ def assert_secret_param(key, value)
end
end
end
sub_test_case 'non-required options for config_param' do
test 'desc must be a string if specified' do
assert_raise ArgumentError.new("key: desc must be a String, but Symbol") do
class InvalidDescClass
include Fluent::Configurable
config_param :key, :string, default: '', desc: :invalid_description
end
end
end
test 'alias must be a symbol if specified' do
assert_raise ArgumentError.new("key: alias must be a Symbol, but String") do
class InvalidAliasClass
include Fluent::Configurable
config_param :key, :string, default: '', alias: 'yay'
end
end
end
test 'deprecated must be a string if specified' do
assert_raise ArgumentError.new("key: deprecated must be a String, but TrueClass") do
class InvalidDeprecatedClass
include Fluent::Configurable
config_param :key, :string, default: '', deprecated: true
end
end
end
test 'obsoleted must be a string if specified' do
assert_raise ArgumentError.new("key: obsoleted must be a String, but TrueClass") do
class InvalidObsoletedClass
include Fluent::Configurable
config_param :key, :string, default: '', obsoleted: true
end
end
end
test 'value_type for hash must be a symbol' do
assert_raise ArgumentError.new("key: value_type must be a Symbol, but String") do
class InvalidValueTypeOfHashClass
include Fluent::Configurable
config_param :key, :hash, value_type: 'yay'
end
end
end
test 'value_type for array must be a symbol' do
assert_raise ArgumentError.new("key: value_type must be a Symbol, but String") do
class InvalidValueTypeOfArrayClass
include Fluent::Configurable
config_param :key, :array, value_type: 'yay'
end
end
end
end
sub_test_case 'enum parameters' do
test 'list must be specified as an array of symbols'
end
sub_test_case 'deprecated/obsoleted parameters' do
test 'both cannot be specified at once' do
assert_raise ArgumentError.new("param1: both of deprecated and obsoleted cannot be specified at once") do
class Buggy1
include Fluent::Configurable
config_param :param1, :string, default: '', deprecated: 'yay', obsoleted: 'foo!'
end
end
end

test 'warned if deprecated parameter is configured' do
obj = ConfigurableSpec::UnRecommended.new
obj.log = Fluent::Test::TestLogger.new
obj.configure(Fluent::Config::Element.new('ROOT', '', {'key1' => 'yay'}, []))

assert_equal 'yay', obj.key1
first_log = obj.log.logs.first
assert{ first_log && first_log.include?("[warn]") && first_log.include?("'key1' parameter is deprecated: key1 will be removed.") }
end

test 'error raised if obsoleted parameter is configured' do
obj = ConfigurableSpec::UnRecommended.new
obj.log = Fluent::Test::TestLogger.new

assert_raise Fluent::ObsoletedParameterError.new("'key2' parameter is already removed: key2 has been removed.") do
obj.configure(Fluent::Config::Element.new('ROOT', '', {'key2' => 'yay'}, []))
end
end
end
end
end
Loading

0 comments on commit 5f0c0b9

Please sign in to comment.