diff --git a/lib-ee/emqx_license/include/emqx_license.hrl b/lib-ee/emqx_license/include/emqx_license.hrl index 72f862a59..a906b7b4e 100644 --- a/lib-ee/emqx_license/include/emqx_license.hrl +++ b/lib-ee/emqx_license/include/emqx_license.hrl @@ -1,5 +1,5 @@ %%-------------------------------------------------------------------- -%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved. +%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved. %% %% @doc EMQ X License Management CLI. %%-------------------------------------------------------------------- @@ -35,4 +35,5 @@ -define(EXPIRED_DAY, -90). +-define(ERR_EXPIRED, expired). -endif. diff --git a/lib-ee/emqx_license/src/emqx_license.erl b/lib-ee/emqx_license/src/emqx_license.erl index be59c21e7..7af94af3f 100644 --- a/lib-ee/emqx_license/src/emqx_license.erl +++ b/lib-ee/emqx_license/src/emqx_license.erl @@ -3,6 +3,7 @@ %%-------------------------------------------------------------------- -module(emqx_license). +-include("emqx_license.hrl"). -include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("typerefl/include/types.hrl"). @@ -67,19 +68,22 @@ update_key(Value) when is_binary(Value); is_list(Value) -> %%------------------------------------------------------------------------------ check(_ConnInfo, AckProps) -> - #{max_connections := MaxClients} = emqx_license_checker:limits(), - case MaxClients of - 0 -> - ?SLOG(error, #{msg => "Connection rejected due to the license expiration"}), + case emqx_license_checker:limits() of + {ok, #{max_connections := ?ERR_EXPIRED}} -> + ?SLOG(error, #{msg => "connection_rejected_due_to_license_expired"}), {stop, {error, ?RC_QUOTA_EXCEEDED}}; - _ -> + {ok, #{max_connections := MaxClients}} -> case check_max_clients_exceeded(MaxClients) of true -> - ?SLOG(error, #{msg => "Connection rejected due to max clients limitation"}), + ?SLOG(error, #{msg => "connection_rejected_due_to_license_limit_reached"}), {stop, {error, ?RC_QUOTA_EXCEEDED}}; false -> {ok, AckProps} - end + end; + {error, Reason} -> + ?SLOG(error, #{msg => "connection_rejected_due_to_license_not_loaded", + reason => Reason}), + {stop, {error, ?RC_QUOTA_EXCEEDED}} end. %%------------------------------------------------------------------------------ diff --git a/lib-ee/emqx_license/src/emqx_license_checker.erl b/lib-ee/emqx_license/src/emqx_license_checker.erl index 99cc8406e..5571eaada 100644 --- a/lib-ee/emqx_license/src/emqx_license_checker.erl +++ b/lib-ee/emqx_license/src/emqx_license_checker.erl @@ -15,6 +15,7 @@ start_link/2, update/1, dump/0, + purge/0, limits/0]). %% gen_server callbacks @@ -23,11 +24,13 @@ handle_cast/2, handle_info/2]). +-define(LICENSE_TAB, emqx_license). + %%------------------------------------------------------------------------------ %% API %%------------------------------------------------------------------------------ --type limits() :: #{max_connections := non_neg_integer()}. +-type limits() :: #{max_connections := non_neg_integer() | ?ERR_EXPIRED}. -spec start_link(emqx_license_parser:license()) -> {ok, pid()}. start_link(LicenseFetcher) -> @@ -39,21 +42,27 @@ start_link(LicenseFetcher, CheckInterval) -> -spec update(emqx_license_parser:license()) -> ok. update(License) -> - gen_server:call(?MODULE, {update, License}). + gen_server:call(?MODULE, {update, License}, infinity). -spec dump() -> [{atom(), term()}]. dump() -> - gen_server:call(?MODULE, dump). + gen_server:call(?MODULE, dump, infinity). --spec limits() -> limits(). +-spec limits() -> {ok, limits()} | {error, any()}. limits() -> - try ets:lookup(?MODULE, limits) of - [{limits, Limits}] -> Limits; - _ -> default_limits() + try ets:lookup(?LICENSE_TAB, limits) of + [{limits, Limits}] -> {ok, Limits}; + _ -> {error, no_license} catch - error:badarg -> default_limits() + error : badarg -> + {error, no_license} end. +%% @doc Force purge the license table. +-spec purge() -> ok. +purge() -> + gen_server:call(?MODULE, purge, infinity). + %%------------------------------------------------------------------------------ %% gen_server callbacks %%------------------------------------------------------------------------------ @@ -61,7 +70,7 @@ limits() -> init([LicenseFetcher, CheckInterval]) -> case LicenseFetcher() of {ok, License} -> - _ = ets:new(?MODULE, [set, protected, named_table]), + ?LICENSE_TAB = ets:new(?LICENSE_TAB, [set, protected, named_table]), #{} = check_license(License), State = ensure_timer(#{check_license_interval => CheckInterval, license => License}), @@ -72,10 +81,11 @@ init([LicenseFetcher, CheckInterval]) -> handle_call({update, License}, _From, State) -> {reply, check_license(License), State#{license => License}}; - handle_call(dump, _From, #{license := License} = State) -> {reply, emqx_license_parser:dump(License), State}; - +handle_call(purge, _From, State) -> + _ = ets:delete_all_objects(?LICENSE_TAB), + {reply, ok, State}; handle_call(_Req, _From, State) -> {reply, unknown, State}. @@ -116,9 +126,7 @@ warn_evaluation(_License, _NeedRestrict) -> false. warn_expiry(_License, NeedRestrict) -> NeedRestrict. limits(License, false) -> #{max_connections => emqx_license_parser:max_connections(License)}; -limits(_License, true) -> #{max_connections => 0}. - -default_limits() -> #{max_connections => 0}. +limits(_License, true) -> #{max_connections => ?ERR_EXPIRED}. days_left(License) -> DateEnd = emqx_license_parser:expiry_date(License), @@ -138,4 +146,4 @@ small_customer_overexpired(?SMALL_CUSTOMER, DaysLeft) small_customer_overexpired(_CType, _DaysLeft) -> false. apply_limits(Limits) -> - ets:insert(?MODULE, {limits, Limits}). + ets:insert(?LICENSE_TAB, {limits, Limits}). diff --git a/lib-ee/emqx_license/src/emqx_license_schema.erl b/lib-ee/emqx_license/src/emqx_license_schema.erl index 2e3c56e49..bd4a471f4 100644 --- a/lib-ee/emqx_license/src/emqx_license_schema.erl +++ b/lib-ee/emqx_license/src/emqx_license_schema.erl @@ -19,9 +19,13 @@ roots() -> [{license, hoconsc:union( hoconsc:ref(?MODULE, file_license)])}]. fields(key_license) -> - [ {key, string()} + [ {key, #{type => string(), + sensitive => true, %% so it's not logged + desc => "Configure the license as a string" + }} ]; - fields(file_license) -> - [ {file, string()} + [ {file, #{type => string(), + desc => "Path to the license file" + }} ]. diff --git a/lib-ee/emqx_license/test/emqx_license_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_SUITE.erl index 1ca7d265f..908b90569 100644 --- a/lib-ee/emqx_license/test/emqx_license_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_SUITE.erl @@ -153,6 +153,12 @@ t_check_expired(_Config) -> {stop, {error, ?RC_QUOTA_EXCEEDED}}, emqx_license:check(#{}, #{})). +t_check_not_loaded(_Config) -> + ok = emqx_license_checker:purge(), + ?assertEqual( + {stop, {error, ?RC_QUOTA_EXCEEDED}}, + emqx_license:check(#{}, #{})). + %%------------------------------------------------------------------------------ %% Helpers %%------------------------------------------------------------------------------ diff --git a/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl index ad8c39187..0790b8f13 100644 --- a/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl @@ -47,7 +47,7 @@ set_special_configs(_) -> ok. %%------------------------------------------------------------------------------ t_default_limits(_Config) -> - ?assertMatch(#{max_connections := 0}, emqx_license_checker:limits()). + ?assertMatch({error, no_license}, emqx_license_checker:limits()). t_dump(_Config) -> License = mk_license( @@ -86,7 +86,7 @@ t_update(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_update_by_timer(_Config) -> @@ -122,7 +122,7 @@ t_expired_trial(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 0}, + {ok, #{max_connections := expired}}, emqx_license_checker:limits()). t_overexpired_small_client(_Config) -> @@ -142,7 +142,7 @@ t_overexpired_small_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 0}, + {ok, #{max_connections := expired}}, emqx_license_checker:limits()). t_overexpired_medium_client(_Config) -> @@ -162,7 +162,7 @@ t_overexpired_medium_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_recently_expired_small_client(_Config) -> @@ -182,7 +182,7 @@ t_recently_expired_small_client(_Config) -> #{} = emqx_license_checker:update(License), ?assertMatch( - #{max_connections := 123}, + {ok, #{max_connections := 123}}, emqx_license_checker:limits()). t_unknown_calls(_Config) ->