diff --git a/lib-ee/emqx_license/include/emqx_license.hrl b/lib-ee/emqx_license/include/emqx_license.hrl index 7c530c4b8..19a0cc954 100644 --- a/lib-ee/emqx_license/include/emqx_license.hrl +++ b/lib-ee/emqx_license/include/emqx_license.hrl @@ -14,7 +14,7 @@ "If you already have a paid license, please apply it now.\n" "Or you could visit https://emqx.com/apply-licenses/emqx to get a trial license.\n" "===============================================================================\n" - ). +). -define(EXPIRY_LOG, "\n" @@ -23,7 +23,7 @@ "Please visit https://emqx.com/apply-licenses/emqx or\n" "contact customer services.\n" "======================================================\n" - ). +). -define(OFFICIAL, 1). -define(TRIAL, 0). diff --git a/lib-ee/emqx_license/rebar.config b/lib-ee/emqx_license/rebar.config index b4c604550..1cb5ace88 100644 --- a/lib-ee/emqx_license/rebar.config +++ b/lib-ee/emqx_license/rebar.config @@ -1 +1,3 @@ {deps, [{emqx, {path, "../../apps/emqx"}}]}. + +{project_plugins, [erlfmt]}. diff --git a/lib-ee/emqx_license/src/emqx_license.app.src b/lib-ee/emqx_license/src/emqx_license.app.src index 97e92daa5..7d10277d8 100644 --- a/lib-ee/emqx_license/src/emqx_license.app.src +++ b/lib-ee/emqx_license/src/emqx_license.app.src @@ -1,7 +1,8 @@ -{application,emqx_license, - [{description,"EMQX License"}, - {vsn,"5.0.0"}, - {modules,[]}, - {registered,[emqx_license_sup]}, - {applications,[kernel,stdlib]}, - {mod,{emqx_license_app,[]}}]}. +{application, emqx_license, [ + {description, "EMQX License"}, + {vsn, "5.0.0"}, + {modules, []}, + {registered, [emqx_license_sup]}, + {applications, [kernel, stdlib]}, + {mod, {emqx_license_app, []}} +]}. diff --git a/lib-ee/emqx_license/src/emqx_license.erl b/lib-ee/emqx_license/src/emqx_license.erl index b4698aa0f..c5fc5643e 100644 --- a/lib-ee/emqx_license/src/emqx_license.erl +++ b/lib-ee/emqx_license/src/emqx_license.erl @@ -10,17 +10,20 @@ -behaviour(emqx_config_handler). --export([pre_config_update/3, - post_config_update/5 - ]). +-export([ + pre_config_update/3, + post_config_update/5 +]). --export([load/0, - check/2, - unload/0, - read_license/0, - read_license/1, - update_file/1, - update_key/1]). +-export([ + load/0, + check/2, + unload/0, + read_license/0, + read_license/1, + update_file/1, + update_key/1 +]). -define(CONF_KEY_PATH, [license]). @@ -50,18 +53,20 @@ unload() -> {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}. update_file(Filename) when is_binary(Filename); is_list(Filename) -> Result = emqx_conf:update( - ?CONF_KEY_PATH, - {file, Filename}, - #{rawconf_with_defaults => true, override_to => local}), + ?CONF_KEY_PATH, + {file, Filename}, + #{rawconf_with_defaults => true, override_to => local} + ), handle_config_update_result(Result). -spec update_key(binary() | string()) -> {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}. update_key(Value) when is_binary(Value); is_list(Value) -> Result = emqx_conf:update( - ?CONF_KEY_PATH, - {key, Value}, - #{rawconf_with_defaults => true, override_to => cluster}), + ?CONF_KEY_PATH, + {key, Value}, + #{rawconf_with_defaults => true, override_to => cluster} + ), handle_config_update_result(Result). %%------------------------------------------------------------------------------ @@ -82,8 +87,10 @@ check(_ConnInfo, AckProps) -> {ok, AckProps} end; {error, Reason} -> - ?SLOG(error, #{msg => "connection_rejected_due_to_license_not_loaded", - reason => Reason}), + ?SLOG(error, #{ + msg => "connection_rejected_due_to_license_not_loaded", + reason => Reason + }), {stop, {error, ?RC_QUOTA_EXCEEDED}} end. @@ -98,7 +105,8 @@ post_config_update(_Path, _Cmd, NewConf, _Old, _AppEnvs) -> case read_license(NewConf) of {ok, License} -> {ok, emqx_license_checker:update(License)}; - {error, _} = Error -> Error + {error, _} = Error -> + Error end. %%------------------------------------------------------------------------------ @@ -124,7 +132,6 @@ do_update({file, Filename}, Conf) -> {error, Reason} -> erlang:throw({invalid_license_file, Reason}) end; - do_update({key, Content}, Conf) when is_binary(Content); is_list(Content) -> case emqx_license_parser:parse(Content) of {ok, _License} -> @@ -144,9 +151,10 @@ read_license(#{file := Filename}) -> {ok, Content} -> emqx_license_parser:parse(Content); {error, _} = Error -> Error end; - read_license(#{key := Content}) -> emqx_license_parser:parse(Content). -handle_config_update_result({error, _} = Error) -> Error; -handle_config_update_result({ok, #{post_config_update := #{emqx_license := Result}}}) -> {ok, Result}. +handle_config_update_result({error, _} = Error) -> + Error; +handle_config_update_result({ok, #{post_config_update := #{emqx_license := Result}}}) -> + {ok, Result}. diff --git a/lib-ee/emqx_license/src/emqx_license_checker.erl b/lib-ee/emqx_license/src/emqx_license_checker.erl index 8007ef3ce..add2927e6 100644 --- a/lib-ee/emqx_license/src/emqx_license_checker.erl +++ b/lib-ee/emqx_license/src/emqx_license_checker.erl @@ -10,20 +10,24 @@ -behaviour(gen_server). -define(CHECK_INTERVAL, 5000). --define(EXPIRY_ALARM_CHECK_INTERVAL, 24 * 60* 60). +-define(EXPIRY_ALARM_CHECK_INTERVAL, 24 * 60 * 60). --export([start_link/1, - start_link/2, - update/1, - dump/0, - purge/0, - limits/0]). +-export([ + start_link/1, + start_link/2, + update/1, + dump/0, + purge/0, + limits/0 +]). %% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2]). +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2 +]). -define(LICENSE_TAB, emqx_license). @@ -55,7 +59,7 @@ limits() -> [{limits, Limits}] -> {ok, Limits}; _ -> {error, no_license} catch - error : badarg -> + error:badarg -> {error, no_license} end. @@ -71,10 +75,14 @@ purge() -> init([LicenseFetcher, CheckInterval]) -> case LicenseFetcher() of {ok, License} -> - ?LICENSE_TAB = ets:new(?LICENSE_TAB, [set, protected, named_table, {read_concurrency, true}]), + ?LICENSE_TAB = ets:new(?LICENSE_TAB, [ + set, protected, named_table, {read_concurrency, true} + ]), #{} = check_license(License), - State0 = ensure_check_license_timer(#{check_license_interval => CheckInterval, - license => License}), + State0 = ensure_check_license_timer(#{ + check_license_interval => CheckInterval, + license => License + }), State = ensure_check_expiry_timer(State0), {ok, State}; {error, Reason} -> @@ -100,12 +108,10 @@ handle_info(check_license, #{license := License} = State) -> NewState = ensure_check_license_timer(State), ?tp(debug, emqx_license_checked, #{}), {noreply, NewState}; - handle_info(check_expiry_alarm, #{license := License} = State) -> _ = expiry_early_alarm(License), NewState = ensure_check_expiry_timer(State), {noreply, NewState}; - handle_info(_Msg, State) -> {noreply, State}. @@ -123,7 +129,8 @@ ensure_check_expiry_timer(State) -> State#{expiry_alarm_timer => Ref}. cancel_timer(State, Key) -> - _ = case maps:find(Key, State) of + _ = + case maps:find(Key, State) of {ok, Ref} when is_reference(Ref) -> erlang:cancel_timer(Ref); _ -> ok end, @@ -134,12 +141,15 @@ check_license(License) -> NeedRestrict = need_restrict(License, DaysLeft), Limits = limits(License, NeedRestrict), true = apply_limits(Limits), - #{warn_evaluation => warn_evaluation(License, NeedRestrict), - warn_expiry => warn_expiry(License, NeedRestrict)}. + #{ + warn_evaluation => warn_evaluation(License, NeedRestrict), + warn_expiry => warn_expiry(License, NeedRestrict) + }. warn_evaluation(License, false) -> emqx_license_parser:customer_type(License) == ?EVALUATION_CUSTOMER; -warn_evaluation(_License, _NeedRestrict) -> false. +warn_evaluation(_License, _NeedRestrict) -> + false. warn_expiry(_License, NeedRestrict) -> NeedRestrict. @@ -151,16 +161,19 @@ days_left(License) -> {DateNow, _} = calendar:universal_time(), calendar:date_to_gregorian_days(DateEnd) - calendar:date_to_gregorian_days(DateNow). -need_restrict(License, DaysLeft)-> +need_restrict(License, DaysLeft) -> CType = emqx_license_parser:customer_type(License), Type = emqx_license_parser:license_type(License), - DaysLeft < 0 - andalso (Type =/= ?OFFICIAL) orelse small_customer_over_expired(CType, DaysLeft). + DaysLeft < 0 andalso + (Type =/= ?OFFICIAL) orelse small_customer_over_expired(CType, DaysLeft). -small_customer_over_expired(?SMALL_CUSTOMER, DaysLeft) - when DaysLeft < ?EXPIRED_DAY -> true; -small_customer_over_expired(_CType, _DaysLeft) -> false. +small_customer_over_expired(?SMALL_CUSTOMER, DaysLeft) when + DaysLeft < ?EXPIRED_DAY +-> + true; +small_customer_over_expired(_CType, _DaysLeft) -> + false. apply_limits(Limits) -> ets:insert(?LICENSE_TAB, {limits, Limits}). diff --git a/lib-ee/emqx_license/src/emqx_license_cli.erl b/lib-ee/emqx_license/src/emqx_license_cli.erl index 8d3c03648..7eccdf79a 100644 --- a/lib-ee/emqx_license/src/emqx_license_cli.erl +++ b/lib-ee/emqx_license/src/emqx_license_cli.erl @@ -26,36 +26,41 @@ license(["reload"]) -> #{key := _Key} -> ?PRINT_MSG("License is not configured as a file, please specify file explicitly~n") end; - license(["reload", Filename]) -> case emqx_license:update_file(Filename) of {ok, Warnings} -> ok = print_warnings(Warnings), ok = ?PRINT_MSG("ok~n"); - {error, Reason} -> ?PRINT("Error: ~p~n", [Reason]) + {error, Reason} -> + ?PRINT("Error: ~p~n", [Reason]) end; - license(["update", EncodedLicense]) -> case emqx_license:update_key(EncodedLicense) of {ok, Warnings} -> ok = print_warnings(Warnings), ok = ?PRINT_MSG("ok~n"); - {error, Reason} -> ?PRINT("Error: ~p~n", [Reason]) + {error, Reason} -> + ?PRINT("Error: ~p~n", [Reason]) end; - license(["info"]) -> - lists:foreach(fun({K, V}) when is_binary(V); is_atom(V); is_list(V) -> - ?PRINT("~-16s: ~s~n", [K, V]); - ({K, V}) -> - ?PRINT("~-16s: ~p~n", [K, V]) - end, emqx_license_checker:dump()); - + lists:foreach( + fun + ({K, V}) when is_binary(V); is_atom(V); is_list(V) -> + ?PRINT("~-16s: ~s~n", [K, V]); + ({K, V}) -> + ?PRINT("~-16s: ~p~n", [K, V]) + end, + emqx_license_checker:dump() + ); license(_) -> emqx_ctl:usage( - [ {"license info", "Show license info"}, - {"license reload []", "Reload license from a file specified with an absolute path"}, - {"license update License", "Update license given as a string"} - ]). + [ + {"license info", "Show license info"}, + {"license reload []", + "Reload license from a file specified with an absolute path"}, + {"license update License", "Update license given as a string"} + ] + ). unload() -> ok = emqx_ctl:unregister_command(license). @@ -70,8 +75,10 @@ print_warnings(Warnings) -> print_evaluation_warning(#{warn_evaluation := true}) -> ?PRINT_MSG(?EVALUATION_LOG); -print_evaluation_warning(_) -> ok. +print_evaluation_warning(_) -> + ok. print_expiry_warning(#{warn_expiry := true}) -> ?PRINT_MSG(?EXPIRY_LOG); -print_expiry_warning(_) -> ok. +print_expiry_warning(_) -> + ok. diff --git a/lib-ee/emqx_license/src/emqx_license_installer.erl b/lib-ee/emqx_license/src/emqx_license_installer.erl index a93e55803..9a24c811b 100644 --- a/lib-ee/emqx_license/src/emqx_license_installer.erl +++ b/lib-ee/emqx_license/src/emqx_license_installer.erl @@ -7,14 +7,18 @@ -behaviour(gen_server). --export([start_link/1, - start_link/4]). +-export([ + start_link/1, + start_link/4 +]). %% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2]). +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2 +]). -define(NAME, emqx). -define(INTERVAL, 5000). @@ -35,11 +39,12 @@ start_link(Name, ServerName, Interval, Callback) -> init([Name, Interval, Callback]) -> Pid = whereis(Name), - State = #{interval => Interval, - name => Name, - pid => Pid, - callback => Callback - }, + State = #{ + interval => Interval, + name => Name, + pid => Pid, + callback => Callback + }, {ok, ensure_timer(State)}. handle_call(_Req, _From, State) -> @@ -51,7 +56,6 @@ handle_cast(_Msg, State) -> handle_info({timeout, Timer, check_pid}, #{timer := Timer} = State) -> NewState = check_pid(State), {noreply, ensure_timer(NewState)}; - handle_info(_Msg, State) -> {noreply, State}. @@ -60,7 +64,8 @@ handle_info(_Msg, State) -> %%------------------------------------------------------------------------------ ensure_timer(#{interval := Interval} = State) -> - _ = case State of + _ = + case State of #{timer := Timer} -> erlang:cancel_timer(Timer); _ -> ok end, diff --git a/lib-ee/emqx_license/src/emqx_license_parser.erl b/lib-ee/emqx_license/src/emqx_license_parser.erl index 65618027a..0ba2d8e25 100644 --- a/lib-ee/emqx_license/src/emqx_license_parser.erl +++ b/lib-ee/emqx_license/src/emqx_license_parser.erl @@ -9,40 +9,45 @@ -include_lib("emqx/include/logger.hrl"). -include("emqx_license.hrl"). --define(PUBKEY, <<""" ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbtkdos3TZmSv+D7+X5pc0yfcjum2 -Q1DK6PCWkiQihjvjJjKFzdYzcWOgC6f4Ou3mgGAUSjdQYYnFKZ/9f5ax4g== ------END PUBLIC KEY----- -""">>). +-define(PUBKEY, << + "" + "\n" + "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbtkdos3TZmSv+D7+X5pc0yfcjum2\n" + "Q1DK6PCWkiQihjvjJjKFzdYzcWOgC6f4Ou3mgGAUSjdQYYnFKZ/9f5ax4g==\n" + "-----END PUBLIC KEY-----\n" + "" +>>). --define(LICENSE_PARSE_MODULES, [emqx_license_parser_v20220101 - ]). +-define(LICENSE_PARSE_MODULES, [emqx_license_parser_v20220101]). -type license_data() :: term(). --type customer_type() :: ?SMALL_CUSTOMER | - ?MEDIUM_CUSTOMER | - ?LARGE_CUSTOMER | - ?EVALUATION_CUSTOMER. +-type customer_type() :: + ?SMALL_CUSTOMER + | ?MEDIUM_CUSTOMER + | ?LARGE_CUSTOMER + | ?EVALUATION_CUSTOMER. -type license_type() :: ?OFFICIAL | ?TRIAL. -type license() :: #{module := module(), data := license_data()}. --export_type([license_data/0, - customer_type/0, - license_type/0, - license/0]). +-export_type([ + license_data/0, + customer_type/0, + license_type/0, + license/0 +]). - --export([parse/1, - parse/2, - dump/1, - customer_type/1, - license_type/1, - expiry_date/1, - max_connections/1 - ]). +-export([ + parse/1, + parse/2, + dump/1, + customer_type/1, + license_type/1, + expiry_date/1, + max_connections/1 +]). %%-------------------------------------------------------------------- %% Behaviour @@ -99,7 +104,6 @@ max_connections(#{module := Module, data := LicenseData}) -> do_parse(_Content, _Key, [], Errors) -> {error, lists:reverse(Errors)}; - do_parse(Content, Key, [Module | Modules], Errors) -> try Module:parse(Content, Key) of {ok, LicenseData} -> @@ -107,6 +111,6 @@ do_parse(Content, Key, [Module | Modules], Errors) -> {error, Error} -> do_parse(Content, Key, Modules, [{Module, Error} | Errors]) catch - _Class : Error : Stacktrace -> + _Class:Error:Stacktrace -> do_parse(Content, Key, Modules, [{Module, {Error, Stacktrace}} | Errors]) end. diff --git a/lib-ee/emqx_license/src/emqx_license_parser_v20220101.erl b/lib-ee/emqx_license/src/emqx_license_parser_v20220101.erl index 23231c68f..bafb02d5d 100644 --- a/lib-ee/emqx_license/src/emqx_license_parser_v20220101.erl +++ b/lib-ee/emqx_license/src/emqx_license_parser_v20220101.erl @@ -18,12 +18,14 @@ %% allow it to start from Nov.2021 -define(MIN_START_DATE, 20211101). --export([parse/2, - dump/1, - customer_type/1, - license_type/1, - expiry_date/1, - max_connections/1]). +-export([ + parse/2, + dump/1, + customer_type/1, + license_type/1, + expiry_date/1, + max_connections/1 +]). %%------------------------------------------------------------------------------ %% API @@ -40,25 +42,30 @@ parse(Content, Key) -> {error, Reason} end. -dump(#{type := Type, - customer_type := CType, - customer := Customer, - email := Email, - date_start := DateStart, - max_connections := MaxConns} = License) -> - +dump( + #{ + type := Type, + customer_type := CType, + customer := Customer, + email := Email, + date_start := DateStart, + max_connections := MaxConns + } = License +) -> DateExpiry = expiry_date(License), {DateNow, _} = calendar:universal_time(), Expiry = DateNow > DateExpiry, - [{customer, Customer}, - {email, Email}, - {max_connections, MaxConns}, - {start_at, format_date(DateStart)}, - {expiry_at, format_date(DateExpiry)}, - {type, format_type(Type)}, - {customer_type, CType}, - {expiry, Expiry}]. + [ + {customer, Customer}, + {email, Email}, + {max_connections, MaxConns}, + {start_at, format_date(DateStart)}, + {expiry_at, format_date(DateExpiry)}, + {type, format_type(Type)}, + {customer_type, CType}, + {expiry, Expiry} + ]. customer_type(#{customer_type := CType}) -> CType. @@ -66,7 +73,8 @@ license_type(#{type := Type}) -> Type. expiry_date(#{date_start := DateStart, days := Days}) -> calendar:gregorian_days_to_date( - calendar:date_to_gregorian_days(DateStart) + Days). + calendar:date_to_gregorian_days(DateStart) + Days + ). max_connections(#{max_connections := MaxConns}) -> MaxConns. @@ -82,7 +90,7 @@ do_parse(Content) -> Signature = base64:decode(EncodedSignature), {ok, {Payload, Signature}} catch - _ : _ -> + _:_ -> {error, bad_license_format} end. @@ -91,17 +99,20 @@ verify_signature(Payload, Signature, Key) -> parse_payload(Payload) -> Lines = lists:map( - fun string:trim/1, - string:split(string:trim(Payload), <<"\n">>, all)), + fun string:trim/1, + string:split(string:trim(Payload), <<"\n">>, all) + ), case Lines of [?LICENSE_VERSION, Type, CType, Customer, Email, DateStart, Days, MaxConns] -> - collect_fields([{type, parse_type(Type)}, - {customer_type, parse_customer_type(CType)}, - {customer, {ok, Customer}}, - {email, {ok, Email}}, - {date_start, parse_date_start(DateStart)}, - {days, parse_days(Days)}, - {max_connections, parse_max_connections(MaxConns)}]); + collect_fields([ + {type, parse_type(Type)}, + {customer_type, parse_customer_type(CType)}, + {customer, {ok, Customer}}, + {email, {ok, Email}}, + {date_start, parse_date_start(DateStart)}, + {days, parse_days(Days)}, + {max_connections, parse_max_connections(MaxConns)} + ]); [_Version, _Type, _CType, _Customer, _Email, _DateStart, _Days, _MaxConns] -> {error, invalid_version}; _ -> @@ -155,13 +166,15 @@ parse_int(Str0) -> collect_fields(Fields) -> Collected = lists:foldl( - fun({Name, {ok, Value}}, {FieldValues, Errors}) -> - {[{Name, Value} | FieldValues], Errors}; - ({Name, {error, Reason}}, {FieldValues, Errors}) -> - {FieldValues, [{Name, Reason} | Errors]} - end, - {[], []}, - Fields), + fun + ({Name, {ok, Value}}, {FieldValues, Errors}) -> + {[{Name, Value} | FieldValues], Errors}; + ({Name, {error, Reason}}, {FieldValues, Errors}) -> + {FieldValues, [{Name, Reason} | Errors]} + end, + {[], []}, + Fields + ), case Collected of {FieldValues, []} -> {ok, maps:from_list(FieldValues)}; @@ -171,9 +184,11 @@ collect_fields(Fields) -> format_date({Year, Month, Day}) -> iolist_to_binary( - io_lib:format( - "~4..0w-~2..0w-~2..0w", - [Year, Month, Day])). + io_lib:format( + "~4..0w-~2..0w-~2..0w", + [Year, Month, Day] + ) + ). format_type(?OFFICIAL) -> <<"official">>; format_type(?TRIAL) -> <<"trial">>. diff --git a/lib-ee/emqx_license/src/emqx_license_resources.erl b/lib-ee/emqx_license/src/emqx_license_resources.erl index 79bbc113b..e92780f55 100644 --- a/lib-ee/emqx_license/src/emqx_license_resources.erl +++ b/lib-ee/emqx_license/src/emqx_license_resources.erl @@ -10,18 +10,22 @@ -define(CHECK_INTERVAL, 5000). --export([start_link/0, - start_link/1, - local_connection_count/0, - connection_count/0]). +-export([ + start_link/0, + start_link/1, + local_connection_count/0, + connection_count/0 +]). %% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2, - terminate/2, - code_change/3]). +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3 +]). %%------------------------------------------------------------------------------ %% API @@ -83,14 +87,17 @@ connection_quota_early_alarm({ok, #{max_connections := Max}}) when is_integer(Ma if Count > Max * High -> HighPercent = float_to_binary(High * 100, [{decimals, 0}]), - Message = iolist_to_binary(["License: live connection number exceeds ", HighPercent, "%"]), + Message = iolist_to_binary([ + "License: live connection number exceeds ", HighPercent, "%" + ]), catch emqx_alarm:activate(license_quota, #{high_watermark => HighPercent}, Message); Count < Max * Low -> catch emqx_alarm:deactivate(license_quota); true -> ok end; -connection_quota_early_alarm(_Limits) -> ok. +connection_quota_early_alarm(_Limits) -> + ok. cached_remote_connection_count() -> try ets:lookup(?MODULE, remote_connection_count) of @@ -104,7 +111,8 @@ update_resources() -> ets:insert(?MODULE, {remote_connection_count, remote_connection_count()}). ensure_timer(#{check_peer_interval := CheckInterval} = State) -> - _ = case State of + _ = + case State of #{timer := Timer} -> erlang:cancel_timer(Timer); _ -> ok end, diff --git a/lib-ee/emqx_license/src/emqx_license_schema.erl b/lib-ee/emqx_license/src/emqx_license_schema.erl index 833b84a8a..8b280f55e 100644 --- a/lib-ee/emqx_license/src/emqx_license_schema.erl +++ b/lib-ee/emqx_license/src/emqx_license_schema.erl @@ -14,46 +14,66 @@ -export([roots/0, fields/1, validations/0]). -roots() -> [{license, - hoconsc:mk(hoconsc:union([hoconsc:ref(?MODULE, key_license), - hoconsc:ref(?MODULE, file_license)]), - #{desc => """EMQX Enterprise license. -A license is either a `key` or a `file`. -When `key` and `file` are both configured, `key` is used. - -EMQX by default starts with a trial license. For a different license, -visit https://www.emqx.com/apply-licenses/emqx to apply. -"})} - ]. +roots() -> + [ + {license, + hoconsc:mk( + hoconsc:union([ + hoconsc:ref(?MODULE, key_license), + hoconsc:ref(?MODULE, file_license) + ]), + #{ + desc => + "EMQX Enterprise license.\n" + "A license is either a `key` or a `file`.\n" + "When `key` and `file` are both configured, `key` is used.\n" + "\n" + "EMQX by default starts with a trial license. For a different license,\n" + "visit https://www.emqx.com/apply-licenses/emqx to apply.\n" + } + )} + ]. fields(key_license) -> - [ {key, #{type => string(), - sensitive => true, %% so it's not logged - desc => "Configure the license as a string" - }} - | common_fields()]; + [ + {key, #{ + type => string(), + %% so it's not logged + sensitive => true, + desc => "Configure the license as a string" + }} + | common_fields() + ]; fields(file_license) -> - [ {file, #{type => string(), - desc => "Path to the license file" - }} - | common_fields()]. + [ + {file, #{ + type => string(), + desc => "Path to the license file" + }} + | common_fields() + ]. common_fields() -> [ - {connection_low_watermark, #{type => emqx_schema:percent(), - default => "75%", desc => "" + {connection_low_watermark, #{ + type => emqx_schema:percent(), + default => "75%", + desc => "" }}, - {connection_high_watermark, #{type => emqx_schema:percent(), - default => "80%", desc => "" + {connection_high_watermark, #{ + type => emqx_schema:percent(), + default => "80%", + desc => "" }} ]. validations() -> - [ {check_license_watermark, fun check_license_watermark/1}]. + [{check_license_watermark, fun check_license_watermark/1}]. check_license_watermark(Conf) -> case hocon_maps:get("license.connection_low_watermark", Conf) of - undefined -> true; + undefined -> + true; Low -> High = hocon_maps:get("license.connection_high_watermark", Conf), case High =/= undefined andalso High > Low of diff --git a/lib-ee/emqx_license/src/emqx_license_sup.erl b/lib-ee/emqx_license/src/emqx_license_sup.erl index 23e55efdb..ce1a6a636 100644 --- a/lib-ee/emqx_license/src/emqx_license_sup.erl +++ b/lib-ee/emqx_license/src/emqx_license_sup.erl @@ -13,31 +13,43 @@ -export([init/1]). start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). + supervisor:start_link({local, ?MODULE}, ?MODULE, []). init([]) -> - {ok, {#{strategy => one_for_one, - intensity => 10, - period => 100}, + {ok, + { + #{ + strategy => one_for_one, + intensity => 10, + period => 100 + }, - [#{id => license_checker, - start => {emqx_license_checker, start_link, [fun emqx_license:read_license/0]}, - restart => permanent, - shutdown => 5000, - type => worker, - modules => [emqx_license_checker]}, + [ + #{ + id => license_checker, + start => {emqx_license_checker, start_link, [fun emqx_license:read_license/0]}, + restart => permanent, + shutdown => 5000, + type => worker, + modules => [emqx_license_checker] + }, - #{id => license_resources, - start => {emqx_license_resources, start_link, []}, - restart => permanent, - shutdown => 5000, - type => worker, - modules => [emqx_license_resources]}, + #{ + id => license_resources, + start => {emqx_license_resources, start_link, []}, + restart => permanent, + shutdown => 5000, + type => worker, + modules => [emqx_license_resources] + }, - #{id => license_installer, - start => {emqx_license_installer, start_link, [fun emqx_license:load/0]}, - restart => permanent, - shutdown => 5000, - type => worker, - modules => [emqx_license_installer]} - ]}}. + #{ + id => license_installer, + start => {emqx_license_installer, start_link, [fun emqx_license:load/0]}, + restart => permanent, + shutdown => 5000, + type => worker, + modules => [emqx_license_installer] + } + ] + }}. diff --git a/lib-ee/emqx_license/test/emqx_license_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_SUITE.erl index 87e314112..4744a1cef 100644 --- a/lib-ee/emqx_license/test/emqx_license_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_SUITE.erl @@ -51,8 +51,8 @@ set_special_configs(emqx_license) -> emqx_config:put([license], Config), RawConfig = #{<<"file">> => emqx_license_test_lib:default_license()}, emqx_config:put_raw([<<"license">>], RawConfig); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -60,101 +60,125 @@ set_special_configs(_) -> ok. t_update_file(_Config) -> ?assertMatch( - {error, {invalid_license_file, enoent}}, - emqx_license:update_file("/unknown/path")), + {error, {invalid_license_file, enoent}}, + emqx_license:update_file("/unknown/path") + ), ok = file:write_file("license_with_invalid_content.lic", <<"bad license">>), ?assertMatch( - {error, [_ | _]}, - emqx_license:update_file("license_with_invalid_content.lic")), + {error, [_ | _]}, + emqx_license:update_file("license_with_invalid_content.lic") + ), ?assertMatch( - {ok, #{}}, - emqx_license:update_file(emqx_license_test_lib:default_license())). + {ok, #{}}, + emqx_license:update_file(emqx_license_test_lib:default_license()) + ). t_update_value(_Config) -> ?assertMatch( - {error, [_ | _]}, - emqx_license:update_key("invalid.license")), + {error, [_ | _]}, + emqx_license:update_key("invalid.license") + ), {ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()), ?assertMatch( - {ok, #{}}, - emqx_license:update_key(LicenseValue)). + {ok, #{}}, + emqx_license:update_key(LicenseValue) + ). t_read_license_from_invalid_file(_Config) -> ?assertMatch( - {error, enoent}, - emqx_license:read_license()). + {error, enoent}, + emqx_license:read_license() + ). t_check_exceeded(_Config) -> License = mk_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]), + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), #{} = emqx_license_checker:update(License), ok = lists:foreach( - fun(_) -> - {ok, C} = emqtt:start_link(), - {ok, _} = emqtt:connect(C) - end, - lists:seq(1, 12)), + fun(_) -> + {ok, C} = emqtt:start_link(), + {ok, _} = emqtt:connect(C) + end, + lists:seq(1, 12) + ), ?assertEqual( - {stop, {error, ?RC_QUOTA_EXCEEDED}}, - emqx_license:check(#{}, #{})). + {stop, {error, ?RC_QUOTA_EXCEEDED}}, + emqx_license:check(#{}, #{}) + ). t_check_ok(_Config) -> License = mk_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]), + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), #{} = emqx_license_checker:update(License), ok = lists:foreach( - fun(_) -> - {ok, C} = emqtt:start_link(), - {ok, _} = emqtt:connect(C) - end, - lists:seq(1, 11)), + fun(_) -> + {ok, C} = emqtt:start_link(), + {ok, _} = emqtt:connect(C) + end, + lists:seq(1, 11) + ), ?assertEqual( - {ok, #{}}, - emqx_license:check(#{}, #{})). + {ok, #{}}, + emqx_license:check(#{}, #{}) + ). t_check_expired(_Config) -> License = mk_license( - ["220111", - "1", %% Official customer - "0", %% Small customer - "Foo", - "contact@foo.com", - "20211101", %% Expired long ago - "10", - "10"]), + [ + "220111", + %% Official customer + "1", + %% Small customer + "0", + "Foo", + "contact@foo.com", + %% Expired long ago + "20211101", + "10", + "10" + ] + ), #{} = emqx_license_checker:update(License), ?assertEqual( - {stop, {error, ?RC_QUOTA_EXCEEDED}}, - emqx_license:check(#{}, #{})). + {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(#{}, #{})). + {stop, {error, ?RC_QUOTA_EXCEEDED}}, + emqx_license:check(#{}, #{}) + ). %%------------------------------------------------------------------------------ %% Helpers @@ -163,6 +187,7 @@ t_check_not_loaded(_Config) -> mk_license(Fields) -> EncodedLicense = emqx_license_test_lib:make_license(Fields), {ok, License} = emqx_license_parser:parse( - EncodedLicense, - emqx_license_test_lib:public_key_pem()), + EncodedLicense, + emqx_license_test_lib:public_key_pem() + ), License. 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 9e2da67d9..dcf2a0197 100644 --- a/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl @@ -25,22 +25,20 @@ end_per_suite(_) -> init_per_testcase(t_default_limits, Config) -> ok = emqx_common_test_helpers:stop_apps([emqx_license]), Config; - init_per_testcase(_Case, Config) -> {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), Config. end_per_testcase(t_default_limits, _Config) -> ok = emqx_common_test_helpers:start_apps([emqx_license], fun set_special_configs/1); - end_per_testcase(_Case, _Config) -> ok. set_special_configs(emqx_license) -> Config = #{file => emqx_license_test_lib:default_license()}, emqx_config:put([license], Config); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -51,139 +49,172 @@ t_default_limits(_Config) -> t_dump(_Config) -> License = mk_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]), + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), #{} = emqx_license_checker:update(License), ?assertEqual( - [{customer,<<"Foo">>}, - {email,<<"contact@foo.com">>}, - {max_connections,10}, - {start_at,<<"2022-01-11">>}, - {expiry_at,<<"2295-10-27">>}, - {type,<<"trial">>}, - {customer_type,10}, - {expiry,false}], - emqx_license_checker:dump()). + [ + {customer, <<"Foo">>}, + {email, <<"contact@foo.com">>}, + {max_connections, 10}, + {start_at, <<"2022-01-11">>}, + {expiry_at, <<"2295-10-27">>}, + {type, <<"trial">>}, + {customer_type, 10}, + {expiry, false} + ], + emqx_license_checker:dump() + ). t_update(_Config) -> License = mk_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "123"]), + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "123" + ] + ), #{} = emqx_license_checker:update(License), ?assertMatch( - {ok, #{max_connections := 123}}, - emqx_license_checker:limits()). + {ok, #{max_connections := 123}}, + emqx_license_checker:limits() + ). t_update_by_timer(_Config) -> ?check_trace( - begin - ?wait_async_action( - begin - erlang:send( - emqx_license_checker, - check_license) - end, - #{?snk_kind := emqx_license_checked}, - 1000) - end, - fun(Trace) -> + begin + ?wait_async_action( + begin + erlang:send( + emqx_license_checker, + check_license + ) + end, + #{?snk_kind := emqx_license_checked}, + 1000 + ) + end, + fun(Trace) -> ?assertMatch([_ | _], ?of_kind(emqx_license_checked, Trace)) - end). + end + ). t_expired_trial(_Config) -> {NowDate, _} = calendar:universal_time(), Date10DaysAgo = calendar:gregorian_days_to_date( - calendar:date_to_gregorian_days(NowDate) - 10), + calendar:date_to_gregorian_days(NowDate) - 10 + ), License = mk_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - format_date(Date10DaysAgo), - "1", - "123"]), + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + format_date(Date10DaysAgo), + "1", + "123" + ] + ), #{} = emqx_license_checker:update(License), ?assertMatch( - {ok, #{max_connections := expired}}, - emqx_license_checker:limits()). + {ok, #{max_connections := expired}}, + emqx_license_checker:limits() + ). t_overexpired_small_client(_Config) -> {NowDate, _} = calendar:universal_time(), Date100DaysAgo = calendar:gregorian_days_to_date( - calendar:date_to_gregorian_days(NowDate) - 100), + calendar:date_to_gregorian_days(NowDate) - 100 + ), License = mk_license( - ["220111", - "1", - "0", - "Foo", - "contact@foo.com", - format_date(Date100DaysAgo), - "1", - "123"]), + [ + "220111", + "1", + "0", + "Foo", + "contact@foo.com", + format_date(Date100DaysAgo), + "1", + "123" + ] + ), #{} = emqx_license_checker:update(License), ?assertMatch( - {ok, #{max_connections := expired}}, - emqx_license_checker:limits()). + {ok, #{max_connections := expired}}, + emqx_license_checker:limits() + ). t_overexpired_medium_client(_Config) -> {NowDate, _} = calendar:universal_time(), Date100DaysAgo = calendar:gregorian_days_to_date( - calendar:date_to_gregorian_days(NowDate) - 100), + calendar:date_to_gregorian_days(NowDate) - 100 + ), License = mk_license( - ["220111", - "1", - "1", - "Foo", - "contact@foo.com", - format_date(Date100DaysAgo), - "1", - "123"]), + [ + "220111", + "1", + "1", + "Foo", + "contact@foo.com", + format_date(Date100DaysAgo), + "1", + "123" + ] + ), #{} = emqx_license_checker:update(License), ?assertMatch( - {ok, #{max_connections := 123}}, - emqx_license_checker:limits()). + {ok, #{max_connections := 123}}, + emqx_license_checker:limits() + ). t_recently_expired_small_client(_Config) -> {NowDate, _} = calendar:universal_time(), Date10DaysAgo = calendar:gregorian_days_to_date( - calendar:date_to_gregorian_days(NowDate) - 10), + calendar:date_to_gregorian_days(NowDate) - 10 + ), License = mk_license( - ["220111", - "1", - "0", - "Foo", - "contact@foo.com", - format_date(Date10DaysAgo), - "1", - "123"]), + [ + "220111", + "1", + "0", + "Foo", + "contact@foo.com", + format_date(Date10DaysAgo), + "1", + "123" + ] + ), #{} = emqx_license_checker:update(License), ?assertMatch( - {ok, #{max_connections := 123}}, - emqx_license_checker:limits()). + {ok, #{max_connections := 123}}, + emqx_license_checker:limits() + ). t_unknown_calls(_Config) -> ok = gen_server:cast(emqx_license_checker, some_cast), @@ -197,12 +228,15 @@ t_unknown_calls(_Config) -> mk_license(Fields) -> EncodedLicense = emqx_license_test_lib:make_license(Fields), {ok, License} = emqx_license_parser:parse( - EncodedLicense, - emqx_license_test_lib:public_key_pem()), + EncodedLicense, + emqx_license_test_lib:public_key_pem() + ), License. format_date({Year, Month, Day}) -> lists:flatten( - io_lib:format( - "~4..0w~2..0w~2..0w", - [Year, Month, Day])). + io_lib:format( + "~4..0w~2..0w~2..0w", + [Year, Month, Day] + ) + ). diff --git a/lib-ee/emqx_license/test/emqx_license_cli_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_cli_SUITE.erl index d8fcf8f98..ab7fd2dc8 100644 --- a/lib-ee/emqx_license/test/emqx_license_cli_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_cli_SUITE.erl @@ -35,8 +35,8 @@ set_special_configs(emqx_license) -> emqx_config:put([license], Config), RawConfig = #{<<"file">> => emqx_license_test_lib:default_license()}, emqx_config:put_raw([<<"license">>], RawConfig); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -58,4 +58,3 @@ t_update(_Config) -> _ = emqx_license_cli:license(["update", LicenseValue]), _ = emqx_license_cli:license(["reload"]), _ = emqx_license_cli:license(["update", "Invalid License Value"]). - diff --git a/lib-ee/emqx_license/test/emqx_license_installer_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_installer_SUITE.erl index b38eab358..e92c082be 100644 --- a/lib-ee/emqx_license/test/emqx_license_installer_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_installer_SUITE.erl @@ -33,8 +33,8 @@ end_per_testcase(_Case, _Config) -> set_special_configs(emqx_license) -> Config = #{file => emqx_license_test_lib:default_license()}, emqx_config:put([license], Config); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -42,38 +42,46 @@ set_special_configs(_) -> ok. t_update(_Config) -> ?check_trace( - begin - ?wait_async_action( - begin - Pid0 = spawn_link(fun() -> receive exit -> ok end end), - register(installer_test, Pid0), + begin + ?wait_async_action( + begin + Pid0 = spawn_link(fun() -> + receive + exit -> ok + end + end), + register(installer_test, Pid0), - {ok, _} = emqx_license_installer:start_link( - installer_test, - ?MODULE, - 10, - fun() -> ok end), + {ok, _} = emqx_license_installer:start_link( + installer_test, + ?MODULE, + 10, + fun() -> ok end + ), + {ok, _} = ?block_until( + #{?snk_kind := emqx_license_installer_nochange}, + 100 + ), - {ok, _} = ?block_until( - #{?snk_kind := emqx_license_installer_nochange}, - 100), + Pid0 ! exit, - Pid0 ! exit, + {ok, _} = ?block_until( + #{?snk_kind := emqx_license_installer_noproc}, + 100 + ), - {ok, _} = ?block_until( - #{?snk_kind := emqx_license_installer_noproc}, - 100), - - Pid1 = spawn_link(fun() -> timer:sleep(100) end), - register(installer_test, Pid1) - end, - #{?snk_kind := emqx_license_installer_called}, - 1000) - end, - fun(Trace) -> + Pid1 = spawn_link(fun() -> timer:sleep(100) end), + register(installer_test, Pid1) + end, + #{?snk_kind := emqx_license_installer_called}, + 1000 + ) + end, + fun(Trace) -> ?assertMatch([_ | _], ?of_kind(emqx_license_installer_called, Trace)) - end). + end + ). t_unknown_calls(_Config) -> ok = gen_server:cast(emqx_license_installer, some_cast), diff --git a/lib-ee/emqx_license/test/emqx_license_parser_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_parser_SUITE.erl index 980471b85..2292eabc6 100644 --- a/lib-ee/emqx_license/test/emqx_license_parser_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_parser_SUITE.erl @@ -32,8 +32,8 @@ end_per_testcase(_Case, _Config) -> set_special_configs(emqx_license) -> Config = #{file => emqx_license_test_lib:default_license()}, emqx_config:put([license], Config); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -44,135 +44,170 @@ t_parse(_Config) -> %% invalid version ?assertMatch( - {error, - [{emqx_license_parser_v20220101,invalid_version}]}, - emqx_license_parser:parse( - emqx_license_test_lib:make_license( - ["220101", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10" - ]), - public_key_pem())), + {error, [{emqx_license_parser_v20220101, invalid_version}]}, + emqx_license_parser:parse( + emqx_license_test_lib:make_license( + [ + "220101", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), + public_key_pem() + ) + ), %% invalid field number ?assertMatch( - {error, - [{emqx_license_parser_v20220101,invalid_field_number}]}, - emqx_license_parser:parse( - emqx_license_test_lib:make_license( - ["220111", - "0", - "10", - "Foo", "Bar", - "contact@foo.com", - "20220111", - "100000", - "10" - ]), - public_key_pem())), + {error, [{emqx_license_parser_v20220101, invalid_field_number}]}, + emqx_license_parser:parse( + emqx_license_test_lib:make_license( + [ + "220111", + "0", + "10", + "Foo", + "Bar", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), + public_key_pem() + ) + ), ?assertMatch( - {error, - [{emqx_license_parser_v20220101, - [{type,invalid_license_type}, - {customer_type,invalid_customer_type}, - {date_start,invalid_date}, - {days,invalid_int_value}]}]}, - emqx_license_parser:parse( - emqx_license_test_lib:make_license( - ["220111", - "zero", - "ten", - "Foo", - "contact@foo.com", - "20220231", - "-10", - "10" - ]), - public_key_pem())), + {error, [ + {emqx_license_parser_v20220101, [ + {type, invalid_license_type}, + {customer_type, invalid_customer_type}, + {date_start, invalid_date}, + {days, invalid_int_value} + ]} + ]}, + emqx_license_parser:parse( + emqx_license_test_lib:make_license( + [ + "220111", + "zero", + "ten", + "Foo", + "contact@foo.com", + "20220231", + "-10", + "10" + ] + ), + public_key_pem() + ) + ), ?assertMatch( - {error, - [{emqx_license_parser_v20220101, - [{type,invalid_license_type}, - {customer_type,invalid_customer_type}, - {date_start,invalid_date}, - {days,invalid_int_value}]}]}, - emqx_license_parser:parse( - emqx_license_test_lib:make_license( - ["220111", - "zero", - "ten", - "Foo", - "contact@foo.com", - "2022-02-1st", - "-10", - "10" - ]), - public_key_pem())), + {error, [ + {emqx_license_parser_v20220101, [ + {type, invalid_license_type}, + {customer_type, invalid_customer_type}, + {date_start, invalid_date}, + {days, invalid_int_value} + ]} + ]}, + emqx_license_parser:parse( + emqx_license_test_lib:make_license( + [ + "220111", + "zero", + "ten", + "Foo", + "contact@foo.com", + "2022-02-1st", + "-10", + "10" + ] + ), + public_key_pem() + ) + ), %% invalid signature [LicensePart, _] = binary:split( - emqx_license_test_lib:make_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]), - <<".">>), + emqx_license_test_lib:make_license( + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), + <<".">> + ), [_, SignaturePart] = binary:split( - emqx_license_test_lib:make_license( - ["220111", - "1", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]), - <<".">>), + emqx_license_test_lib:make_license( + [ + "220111", + "1", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" + ] + ), + <<".">> + ), ?assertMatch( - {error, - [{emqx_license_parser_v20220101,invalid_signature}]}, - emqx_license_parser:parse( - iolist_to_binary([LicensePart, <<".">>, SignaturePart]), - public_key_pem())), + {error, [{emqx_license_parser_v20220101, invalid_signature}]}, + emqx_license_parser:parse( + iolist_to_binary([LicensePart, <<".">>, SignaturePart]), + public_key_pem() + ) + ), %% totally invalid strings as license ?assertMatch( - {error, [_ | _]}, - emqx_license_parser:parse( - <<"badlicense">>, - public_key_pem())), + {error, [_ | _]}, + emqx_license_parser:parse( + <<"badlicense">>, + public_key_pem() + ) + ), ?assertMatch( - {error, [_ | _]}, - emqx_license_parser:parse( - <<"bad.license">>, - public_key_pem())). + {error, [_ | _]}, + emqx_license_parser:parse( + <<"bad.license">>, + public_key_pem() + ) + ). t_dump(_Config) -> {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()), ?assertEqual( - [{customer,<<"Foo">>}, - {email,<<"contact@foo.com">>}, - {max_connections,10}, - {start_at,<<"2022-01-11">>}, - {expiry_at,<<"2295-10-27">>}, - {type,<<"trial">>}, - {customer_type,10}, - {expiry,false}], - emqx_license_parser:dump(License)). + [ + {customer, <<"Foo">>}, + {email, <<"contact@foo.com">>}, + {max_connections, 10}, + {start_at, <<"2022-01-11">>}, + {expiry_at, <<"2295-10-27">>}, + {type, <<"trial">>}, + {customer_type, 10}, + {expiry, false} + ], + emqx_license_parser:dump(License) + ). t_customer_type(_Config) -> {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()), @@ -192,7 +227,7 @@ t_max_connections(_Config) -> t_expiry_date(_Config) -> {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()), - ?assertEqual({2295,10,27}, emqx_license_parser:expiry_date(License)). + ?assertEqual({2295, 10, 27}, emqx_license_parser:expiry_date(License)). %%------------------------------------------------------------------------------ %% Helpers @@ -203,11 +238,14 @@ public_key_pem() -> sample_license() -> emqx_license_test_lib:make_license( - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100,000", - "10"]). + [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100,000", + "10" + ] + ). diff --git a/lib-ee/emqx_license/test/emqx_license_resources_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_resources_SUITE.erl index 413eacb2b..a6411902e 100644 --- a/lib-ee/emqx_license/test/emqx_license_resources_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_resources_SUITE.erl @@ -33,8 +33,8 @@ end_per_testcase(_Case, _Config) -> set_special_configs(emqx_license) -> Config = #{file => emqx_license_test_lib:default_license()}, emqx_config:put([license], Config); - -set_special_configs(_) -> ok. +set_special_configs(_) -> + ok. %%------------------------------------------------------------------------------ %% Tests @@ -42,41 +42,45 @@ set_special_configs(_) -> ok. t_connection_count(_Config) -> ?check_trace( - begin - ?wait_async_action( - whereis(emqx_license_resources) ! update_resources, - #{?snk_kind := emqx_license_resources_updated}, - 1000), - emqx_license_resources:connection_count() - end, - fun(ConnCount, Trace) -> - ?assertEqual(0, ConnCount), - ?assertMatch([_ | _], ?of_kind(emqx_license_resources_updated, Trace)) - end), - + begin + ?wait_async_action( + whereis(emqx_license_resources) ! update_resources, + #{?snk_kind := emqx_license_resources_updated}, + 1000 + ), + emqx_license_resources:connection_count() + end, + fun(ConnCount, Trace) -> + ?assertEqual(0, ConnCount), + ?assertMatch([_ | _], ?of_kind(emqx_license_resources_updated, Trace)) + end + ), meck:new(emqx_cm, [passthrough]), meck:expect(emqx_cm, get_connected_client_count, fun() -> 10 end), meck:new(emqx_license_proto_v1, [passthrough]), meck:expect( - emqx_license_proto_v1, - remote_connection_counts, - fun(_Nodes) -> - [{ok, 5}, {error, some_error}] - end), + emqx_license_proto_v1, + remote_connection_counts, + fun(_Nodes) -> + [{ok, 5}, {error, some_error}] + end + ), ?check_trace( - begin - ?wait_async_action( - whereis(emqx_license_resources) ! update_resources, - #{?snk_kind := emqx_license_resources_updated}, - 1000), - emqx_license_resources:connection_count() - end, - fun(ConnCount, _Trace) -> - ?assertEqual(15, ConnCount) - end), + begin + ?wait_async_action( + whereis(emqx_license_resources) ! update_resources, + #{?snk_kind := emqx_license_resources_updated}, + 1000 + ), + emqx_license_resources:connection_count() + end, + fun(ConnCount, _Trace) -> + ?assertEqual(15, ConnCount) + end + ), meck:unload(emqx_license_proto_v1), meck:unload(emqx_cm). diff --git a/lib-ee/emqx_license/test/emqx_license_test_lib.erl b/lib-ee/emqx_license/test/emqx_license_test_lib.erl index c78583911..67f01cd92 100644 --- a/lib-ee/emqx_license/test/emqx_license_test_lib.erl +++ b/lib-ee/emqx_license/test/emqx_license_test_lib.erl @@ -7,15 +7,16 @@ -compile(nowarn_export_all). -compile(export_all). --define(DEFAULT_LICENSE_VALUES, - ["220111", - "0", - "10", - "Foo", - "contact@foo.com", - "20220111", - "100000", - "10"]). +-define(DEFAULT_LICENSE_VALUES, [ + "220111", + "0", + "10", + "Foo", + "contact@foo.com", + "20220111", + "100000", + "10" +]). -define(DEFAULT_LICENSE_FILE, "emqx.lic"). @@ -36,7 +37,8 @@ test_key(Filename, Format) -> Path = filename:join([Dir, "data", Filename]), {ok, KeyData} = file:read_file(Path), case Format of - pem -> KeyData; + pem -> + KeyData; decoded -> [PemEntry] = public_key:pem_decode(KeyData), public_key:pem_entry_decode(PemEntry)