Add ability to set default vhost limits by pattern
Limits are defined in the instance config:
default_limits.vhosts.1.pattern = ^device
default_limits.vhosts.1.max_connections = 10
default_limits.vhosts.1.max_queues = 10
default_limits.vhosts.2.pattern = ^system
default_limits.vhosts.2.max_connections = 100
default_limits.vhosts.3.pattern = .*
default_limits.vhosts.3.max_connections = 20
default_limits.vhosts.3.max_queues = 20
Where pattern is a regular expression used to match limits to a newly
created vhost, and the limits are non-negative integers. First matching
set of limits is applied, only once, during vhost creation.
This commit is contained in:
parent
41dd54437e
commit
27ebc04dc9
|
|
@ -632,6 +632,7 @@ end}.
|
||||||
%% {default_user, <<"guest">>},
|
%% {default_user, <<"guest">>},
|
||||||
%% {default_pass, <<"guest">>},
|
%% {default_pass, <<"guest">>},
|
||||||
%% {default_permissions, [<<".*">>, <<".*">>, <<".*">>]},
|
%% {default_permissions, [<<".*">>, <<".*">>, <<".*">>]},
|
||||||
|
%% {default_limits, [{vhost, []}]
|
||||||
|
|
||||||
{mapping, "default_vhost", "rabbit.default_vhost", [
|
{mapping, "default_vhost", "rabbit.default_vhost", [
|
||||||
{datatype, string}
|
{datatype, string}
|
||||||
|
|
@ -681,6 +682,70 @@ fun(Conf) ->
|
||||||
[list_to_binary(Configure), list_to_binary(Read), list_to_binary(Write)]
|
[list_to_binary(Configure), list_to_binary(Read), list_to_binary(Write)]
|
||||||
end}.
|
end}.
|
||||||
|
|
||||||
|
{mapping, "default_limits.vhost.$id.pattern", "rabbit.default_limits.vhost", [
|
||||||
|
{include_default, 1},
|
||||||
|
{comment, ".*"},
|
||||||
|
{validators, ["valid_regex"]},
|
||||||
|
{datatype, string}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{mapping, "default_limits.vhost.$id.max_connections", "rabbit.default_limits.vhost", [
|
||||||
|
{include_default, 1},
|
||||||
|
{comment, 1000},
|
||||||
|
{validators, [ "non_zero_positive_integer"]},
|
||||||
|
{datatype, integer}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{mapping, "default_limits.vhost.$id.max_queues", "rabbit.default_limits.vhost", [
|
||||||
|
{include_default, 1},
|
||||||
|
{comment, 100},
|
||||||
|
{validators, [ "non_zero_positive_integer"]},
|
||||||
|
{datatype, integer}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{translation, "rabbit.default_limits.vhost",
|
||||||
|
fun(Conf) ->
|
||||||
|
Prefix = ["default_limits", "vhost"],
|
||||||
|
GetAll = fun(Spec) ->
|
||||||
|
FullSpec = Prefix ++ Spec,
|
||||||
|
lists:filtermap(
|
||||||
|
fun({K, V}) ->
|
||||||
|
case cuttlefish_variable:is_fuzzy_match(K, FullSpec) of
|
||||||
|
true -> [_, _, ID, _] = K,
|
||||||
|
{true, {ID, V}};
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
Conf)
|
||||||
|
end,
|
||||||
|
Get = fun(Spec) -> cuttlefish:conf_get(Prefix ++ Spec, Conf, undefined) end,
|
||||||
|
|
||||||
|
%% Warn about incomplete config
|
||||||
|
SettingIDs = lists:uniq(
|
||||||
|
[ ID || {ID, _} <- GetAll(["$id", "max_connections"]) ] ++
|
||||||
|
[ ID || {ID, _} <- GetAll(["$id", "max_queues"]) ]
|
||||||
|
),
|
||||||
|
[ cuttlefish:invalid(
|
||||||
|
io_lib:format(
|
||||||
|
"default_limits.vhost.~ts.pattern required",
|
||||||
|
[ID]))
|
||||||
|
|| ID <- SettingIDs, Get([ID, "pattern"]) =:= undefined ],
|
||||||
|
|
||||||
|
%% Transform
|
||||||
|
Settings = [ {P, [{<<"max-connections">>, Get([ID, "max_connections"])},
|
||||||
|
{<<"max-queues">>, Get([ID, "max_queues"])}]} ||
|
||||||
|
{ID, P} <- GetAll(["$id", "pattern"]) ],
|
||||||
|
Settings1 = lists:map(fun({P, L}) -> {
|
||||||
|
list_to_binary(P),
|
||||||
|
lists:filter(fun({_, V}) -> V =/= undefined end, L)
|
||||||
|
}
|
||||||
|
end, Settings),
|
||||||
|
case Settings1 of
|
||||||
|
[] -> cuttlefish:unset();
|
||||||
|
_ -> Settings1
|
||||||
|
end
|
||||||
|
end}.
|
||||||
|
|
||||||
%% Tags for default user
|
%% Tags for default user
|
||||||
%%
|
%%
|
||||||
%% For more details about tags, see the documentation for the
|
%% For more details about tags, see the documentation for the
|
||||||
|
|
@ -2320,3 +2385,9 @@ end}.
|
||||||
fun(Int) when is_integer(Int) ->
|
fun(Int) when is_integer(Int) ->
|
||||||
Int >= 1
|
Int >= 1
|
||||||
end}.
|
end}.
|
||||||
|
|
||||||
|
{validator, "valid_regex", "string must be a valid regular expression",
|
||||||
|
fun("") -> false;
|
||||||
|
(String) -> {Res, _ } = re:compile(String),
|
||||||
|
Res =:= ok
|
||||||
|
end}.
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,18 @@ parse_tags(Val) when is_list(Val) ->
|
||||||
[trim_tag(Tag) || Tag <- re:split(ValUnicode, ",", [unicode, {return, list}])]
|
[trim_tag(Tag) || Tag <- re:split(ValUnicode, ",", [unicode, {return, list}])]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec default_limits(vhost:name()) -> proplists:proplist().
|
||||||
|
default_limits(Name) ->
|
||||||
|
AllLimits = application:get_env(rabbit, default_limits, []),
|
||||||
|
VHostLimits = proplists:get_value(vhost, AllLimits, []),
|
||||||
|
Match = lists:search(fun({RE, _}) ->
|
||||||
|
re:run(Name, RE, [{capture, none}]) =:= match
|
||||||
|
end, VHostLimits),
|
||||||
|
case Match of
|
||||||
|
{value, {_, Limits}} -> Limits;
|
||||||
|
_ -> []
|
||||||
|
end.
|
||||||
|
|
||||||
-spec add(vhost:name(), rabbit_types:username()) ->
|
-spec add(vhost:name(), rabbit_types:username()) ->
|
||||||
rabbit_types:ok_or_error(any()).
|
rabbit_types:ok_or_error(any()).
|
||||||
add(VHost, ActingUser) ->
|
add(VHost, ActingUser) ->
|
||||||
|
|
@ -192,11 +204,12 @@ do_add(Name, Metadata, ActingUser) ->
|
||||||
rabbit_log:info("Adding vhost '~ts' (description: '~ts', tags: ~tp)",
|
rabbit_log:info("Adding vhost '~ts' (description: '~ts', tags: ~tp)",
|
||||||
[Name, Description, Tags])
|
[Name, Description, Tags])
|
||||||
end,
|
end,
|
||||||
|
DefaultLimits = default_limits(Name),
|
||||||
VHost = rabbit_misc:execute_mnesia_transaction(
|
VHost = rabbit_misc:execute_mnesia_transaction(
|
||||||
fun () ->
|
fun () ->
|
||||||
case mnesia:wread({rabbit_vhost, Name}) of
|
case mnesia:wread({rabbit_vhost, Name}) of
|
||||||
[] ->
|
[] ->
|
||||||
Row = vhost:new(Name, [], Metadata),
|
Row = vhost:new(Name, DefaultLimits, Metadata),
|
||||||
rabbit_log:debug("Inserting a virtual host record ~tp", [Row]),
|
rabbit_log:debug("Inserting a virtual host record ~tp", [Row]),
|
||||||
ok = mnesia:write(rabbit_vhost, Row, write),
|
ok = mnesia:write(rabbit_vhost, Row, write),
|
||||||
Row;
|
Row;
|
||||||
|
|
@ -208,6 +221,11 @@ do_add(Name, Metadata, ActingUser) ->
|
||||||
fun (VHost1, true) ->
|
fun (VHost1, true) ->
|
||||||
VHost1;
|
VHost1;
|
||||||
(VHost1, false) ->
|
(VHost1, false) ->
|
||||||
|
rabbit_log:info("Applying default limits to vhost '~tp': ~tp", [Name, DefaultLimits]),
|
||||||
|
ok = case DefaultLimits of
|
||||||
|
[] -> ok;
|
||||||
|
_ -> rabbit_vhost_limit:set(Name, DefaultLimits, ActingUser)
|
||||||
|
end,
|
||||||
[begin
|
[begin
|
||||||
Resource = rabbit_misc:r(Name, exchange, ExchangeName),
|
Resource = rabbit_misc:r(Name, exchange, ExchangeName),
|
||||||
rabbit_log:debug("Will declare an exchange ~tp", [Resource]),
|
rabbit_log:debug("Will declare an exchange ~tp", [Resource]),
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,8 @@ parse_set(VHost, Defn, ActingUser) ->
|
||||||
rabbit_misc:format("Could not parse JSON document: ~tp", [Reason])}
|
rabbit_misc:format("Could not parse JSON document: ~tp", [Reason])}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec set(rabbit_types:name(), {binary(), binary()}, rabbit_types:user() | rabbit_types:username()) ->
|
||||||
|
rabbit_runtime_parameters:ok_or_error_string().
|
||||||
set(VHost, Defn, ActingUser) ->
|
set(VHost, Defn, ActingUser) ->
|
||||||
rabbit_runtime_parameters:set_any(VHost, <<"vhost-limits">>,
|
rabbit_runtime_parameters:set_any(VHost, <<"vhost-limits">>,
|
||||||
<<"limits">>, Defn, ActingUser).
|
<<"limits">>, Defn, ActingUser).
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,27 @@ ssl_options.fail_if_no_peer_cert = true",
|
||||||
{socket_writer_gc_threshold_off,
|
{socket_writer_gc_threshold_off,
|
||||||
"socket_writer.gc_threshold = off", [{rabbit, [{writer_gc_threshold, undefined}]}],[]},
|
"socket_writer.gc_threshold = off", [{rabbit, [{writer_gc_threshold, undefined}]}],[]},
|
||||||
|
|
||||||
|
{default_limits_vhost,
|
||||||
|
"
|
||||||
|
default_limits.vhost.a.pattern = .*
|
||||||
|
default_limits.vhost.a.max_queues = 10
|
||||||
|
default_limits.vhost.a.max_connections = 100
|
||||||
|
",
|
||||||
|
[{rabbit, [{default_limits, [{vhost, [
|
||||||
|
{<<".*">>, [{<<"max-connections">>, 100}, {<<"max-queues">>, 10}]}
|
||||||
|
]}]}]}],
|
||||||
|
[]},
|
||||||
|
|
||||||
|
{default_limits_vhost_no_undefined,
|
||||||
|
"
|
||||||
|
default_limits.vhost.a.pattern = .*
|
||||||
|
default_limits.vhost.a.max_queues = 10
|
||||||
|
",
|
||||||
|
[{rabbit, [{default_limits, [{vhost, [
|
||||||
|
{<<".*">>, [{<<"max-queues">>, 10}]}
|
||||||
|
]}]}]}],
|
||||||
|
[]},
|
||||||
|
|
||||||
{default_user_settings,
|
{default_user_settings,
|
||||||
"default_user = guest
|
"default_user = guest
|
||||||
default_pass = guest
|
default_pass = guest
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ all() ->
|
||||||
|
|
||||||
groups() ->
|
groups() ->
|
||||||
ClusterSize1Tests = [
|
ClusterSize1Tests = [
|
||||||
|
vhost_is_created_with_default_limits,
|
||||||
single_node_vhost_deletion_forces_connection_closure,
|
single_node_vhost_deletion_forces_connection_closure,
|
||||||
vhost_failure_forces_connection_closure,
|
vhost_failure_forces_connection_closure,
|
||||||
vhost_creation_idempotency,
|
vhost_creation_idempotency,
|
||||||
|
|
@ -319,6 +320,21 @@ vhost_creation_idempotency(Config) ->
|
||||||
rabbit_ct_broker_helpers:delete_vhost(Config, VHost)
|
rabbit_ct_broker_helpers:delete_vhost(Config, VHost)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
vhost_is_created_with_default_limits(Config) ->
|
||||||
|
VHost = <<"limits-test">>,
|
||||||
|
Pattern = "^limits-.*$",
|
||||||
|
Limits = [{<<"max-connections">>, 10}, {<<"max-queues">>, 1}],
|
||||||
|
Env = [{vhost, [{Pattern, Limits}]}],
|
||||||
|
try
|
||||||
|
?assertEqual(ok, rabbit_ct_broker_helpers:rpc(Config, 0,
|
||||||
|
application, set_env, [rabbit, default_limits, Env])),
|
||||||
|
?assertEqual(ok, rabbit_ct_broker_helpers:add_vhost(Config, VHost)),
|
||||||
|
?assertEqual(Limits, rabbit_ct_broker_helpers:rpc(Config, 0,
|
||||||
|
rabbit_vhost_limit, list, [VHost]))
|
||||||
|
after
|
||||||
|
rabbit_ct_broker_helpers:delete_vhost(Config, VHost)
|
||||||
|
end.
|
||||||
|
|
||||||
parse_tags(Config) ->
|
parse_tags(Config) ->
|
||||||
rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, parse_tags1, [Config]).
|
rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, parse_tags1, [Config]).
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue