summaryrefslogtreecommitdiff
path: root/deps/rabbit/src/rabbit_vhost_limit.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/rabbit/src/rabbit_vhost_limit.erl')
-rw-r--r--deps/rabbit/src/rabbit_vhost_limit.erl205
1 files changed, 205 insertions, 0 deletions
diff --git a/deps/rabbit/src/rabbit_vhost_limit.erl b/deps/rabbit/src/rabbit_vhost_limit.erl
new file mode 100644
index 0000000000..bee01f3054
--- /dev/null
+++ b/deps/rabbit/src/rabbit_vhost_limit.erl
@@ -0,0 +1,205 @@
+%% This Source Code Form is subject to the terms of the Mozilla Public
+%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
+%%
+%% Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+%%
+
+-module(rabbit_vhost_limit).
+
+-behaviour(rabbit_runtime_parameter).
+
+-include("rabbit.hrl").
+
+-export([register/0]).
+-export([parse_set/3, set/3, clear/2]).
+-export([list/0, list/1]).
+-export([update_limit/4, clear_limit/3, get_limit/2]).
+-export([validate/5, notify/5, notify_clear/4]).
+-export([connection_limit/1, queue_limit/1,
+ is_over_queue_limit/1, would_exceed_queue_limit/2,
+ is_over_connection_limit/1]).
+
+-import(rabbit_misc, [pget/2, pget/3]).
+
+-rabbit_boot_step({?MODULE,
+ [{description, "vhost limit parameters"},
+ {mfa, {rabbit_vhost_limit, register, []}},
+ {requires, rabbit_registry},
+ {enables, recovery}]}).
+
+%%----------------------------------------------------------------------------
+
+register() ->
+ rabbit_registry:register(runtime_parameter, <<"vhost-limits">>, ?MODULE).
+
+validate(_VHost, <<"vhost-limits">>, Name, Term, _User) ->
+ rabbit_parameter_validation:proplist(
+ Name, vhost_limit_validation(), Term).
+
+notify(VHost, <<"vhost-limits">>, <<"limits">>, Limits, ActingUser) ->
+ rabbit_event:notify(vhost_limits_set, [{name, <<"limits">>},
+ {user_who_performed_action, ActingUser}
+ | Limits]),
+ update_vhost(VHost, Limits).
+
+notify_clear(VHost, <<"vhost-limits">>, <<"limits">>, ActingUser) ->
+ rabbit_event:notify(vhost_limits_cleared, [{name, <<"limits">>},
+ {user_who_performed_action, ActingUser}]),
+ %% If the function is called as a part of vhost deletion, the vhost can
+ %% be already deleted.
+ case rabbit_vhost:exists(VHost) of
+ true -> update_vhost(VHost, undefined);
+ false -> ok
+ end.
+
+connection_limit(VirtualHost) ->
+ get_limit(VirtualHost, <<"max-connections">>).
+
+queue_limit(VirtualHost) ->
+ get_limit(VirtualHost, <<"max-queues">>).
+
+
+query_limits(VHost) ->
+ case rabbit_runtime_parameters:list(VHost, <<"vhost-limits">>) of
+ [] -> [];
+ Params -> [ {pget(vhost, Param), pget(value, Param)}
+ || Param <- Params,
+ pget(value, Param) =/= undefined,
+ pget(name, Param) == <<"limits">> ]
+ end.
+
+
+-spec list() -> [{vhost:name(), rabbit_types:infos()}].
+list() ->
+ query_limits('_').
+
+-spec list(vhost:name()) -> rabbit_types:infos().
+list(VHost) ->
+ case query_limits(VHost) of
+ [] -> [];
+ [{VHost, Value}] -> Value
+ end.
+
+-spec is_over_connection_limit(vhost:name()) -> {true, non_neg_integer()} | false.
+
+is_over_connection_limit(VirtualHost) ->
+ case rabbit_vhost_limit:connection_limit(VirtualHost) of
+ %% no limit configured
+ undefined -> false;
+ %% with limit = 0, no connections are allowed
+ {ok, 0} -> {true, 0};
+ {ok, Limit} when is_integer(Limit) andalso Limit > 0 ->
+ ConnectionCount =
+ rabbit_connection_tracking:count_tracked_items_in({vhost, VirtualHost}),
+ case ConnectionCount >= Limit of
+ false -> false;
+ true -> {true, Limit}
+ end;
+ %% any negative value means "no limit". Note that parameter validation
+ %% will replace negative integers with 'undefined', so this is to be
+ %% explicit and extra defensive
+ {ok, Limit} when is_integer(Limit) andalso Limit < 0 -> false;
+ %% ignore non-integer limits
+ {ok, _Limit} -> false
+ end.
+
+-spec would_exceed_queue_limit(non_neg_integer(), vhost:name()) ->
+ {true, non_neg_integer(), non_neg_integer()} | false.
+
+would_exceed_queue_limit(AdditionalCount, VirtualHost) ->
+ case queue_limit(VirtualHost) of
+ undefined ->
+ %% no limit configured
+ false;
+ {ok, 0} ->
+ %% with limit = 0, no queues can be declared (perhaps not very
+ %% useful but consistent with the connection limit)
+ {true, 0, 0};
+ {ok, Limit} when is_integer(Limit) andalso Limit > 0 ->
+ QueueCount = rabbit_amqqueue:count(VirtualHost),
+ case (AdditionalCount + QueueCount) > Limit of
+ false -> false;
+ true -> {true, Limit, QueueCount}
+ end;
+ {ok, Limit} when is_integer(Limit) andalso Limit < 0 ->
+ %% any negative value means "no limit". Note that parameter validation
+ %% will replace negative integers with 'undefined', so this is to be
+ %% explicit and extra defensive
+ false;
+ {ok, _Limit} ->
+ %% ignore non-integer limits
+ false
+ end.
+
+-spec is_over_queue_limit(vhost:name()) -> {true, non_neg_integer()} | false.
+
+is_over_queue_limit(VirtualHost) ->
+ case would_exceed_queue_limit(1, VirtualHost) of
+ {true, Limit, _QueueCount} -> {true, Limit};
+ false -> false
+ end.
+
+%%----------------------------------------------------------------------------
+
+parse_set(VHost, Defn, ActingUser) ->
+ Definition = rabbit_data_coercion:to_binary(Defn),
+ case rabbit_json:try_decode(Definition) of
+ {ok, Term} ->
+ set(VHost, maps:to_list(Term), ActingUser);
+ {error, Reason} ->
+ {error_string,
+ rabbit_misc:format("JSON decoding error. Reason: ~ts", [Reason])}
+ end.
+
+set(VHost, Defn, ActingUser) ->
+ rabbit_runtime_parameters:set_any(VHost, <<"vhost-limits">>,
+ <<"limits">>, Defn, ActingUser).
+
+clear(VHost, ActingUser) ->
+ rabbit_runtime_parameters:clear_any(VHost, <<"vhost-limits">>,
+ <<"limits">>, ActingUser).
+
+update_limit(VHost, Name, Value, ActingUser) ->
+ OldDef = case rabbit_runtime_parameters:list(VHost, <<"vhost-limits">>) of
+ [] -> [];
+ [Param] -> pget(value, Param, [])
+ end,
+ NewDef = [{Name, Value} | lists:keydelete(Name, 1, OldDef)],
+ set(VHost, NewDef, ActingUser).
+
+clear_limit(VHost, Name, ActingUser) ->
+ OldDef = case rabbit_runtime_parameters:list(VHost, <<"vhost-limits">>) of
+ [] -> [];
+ [Param] -> pget(value, Param, [])
+ end,
+ NewDef = lists:keydelete(Name, 1, OldDef),
+ set(VHost, NewDef, ActingUser).
+
+vhost_limit_validation() ->
+ [{<<"max-connections">>, fun rabbit_parameter_validation:integer/2, optional},
+ {<<"max-queues">>, fun rabbit_parameter_validation:integer/2, optional}].
+
+update_vhost(VHostName, Limits) ->
+ rabbit_misc:execute_mnesia_transaction(
+ fun() ->
+ rabbit_vhost:update(VHostName,
+ fun(VHost) ->
+ rabbit_vhost:set_limits(VHost, Limits)
+ end)
+ end),
+ ok.
+
+get_limit(VirtualHost, Limit) ->
+ case rabbit_runtime_parameters:list(VirtualHost, <<"vhost-limits">>) of
+ [] -> undefined;
+ [Param] -> case pget(value, Param) of
+ undefined -> undefined;
+ Val -> case pget(Limit, Val) of
+ undefined -> undefined;
+ %% no limit
+ N when N < 0 -> undefined;
+ N when N >= 0 -> {ok, N}
+ end
+ end
+ end.