Merge pull request #7672 from zmstone/0419-5.0-enterprise-default-license

feat: change default trial license
This commit is contained in:
Zaiming (Stone) Shi 2022-04-23 08:43:11 +01:00 committed by GitHub
commit f9fa8bb585
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 87 additions and 58 deletions

View File

@ -1,5 +1,6 @@
license { license {
key = "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KMjAyMjAxMDEKMzY1MDAKMTAK.MEUCIFc9EUjqB3SjpRqWjqmAzI4Tg4LwhCRet9scEoxMRt8fAiEAk6vfYUiPOTzBC+3EjNF3WmLTiA3B0TN5ZNwuTKbTXJQ=" # The default license has 1000 connections limit, it is issued on 20220419 and valid for 5 years (1825 days)
key = "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KZGVmYXVsdAoyMDIyMDQxOQoxODI1CjEwMDAK.MEQCICbgRVijCQov2hrvZXR1mk9Oa+tyV1F5oJ6iOZeSHjnQAiB9dUiVeaZekDOjztk+NCWjhk4PG8tWfw2uFZWruSzD6g=="
connection_low_watermark = 75%, connection_low_watermark = 75%,
connection_high_watermark = 80% connection_high_watermark = 80%
} }

View File

@ -9,20 +9,20 @@
-define(EVALUATION_LOG, -define(EVALUATION_LOG,
"\n" "\n"
"===============================================================================\n" "========================================================================\n"
"This is an evaluation license that is restricted to 10 concurrent connections.\n" "Using an evaluation license limited to ~p concurrent connections.\n"
"If you already have a paid license, please apply it now.\n" "Apply a license at https://emqx.com/apply-licenses/emqx.\n"
"Or you could visit https://emqx.com/apply-licenses/emqx to get a trial license.\n" "Or contact EMQ customer services.\n"
"===============================================================================\n" "========================================================================\n"
). ).
-define(EXPIRY_LOG, -define(EXPIRY_LOG,
"\n" "\n"
"======================================================\n" "========================================================================\n"
"Your license has expired.\n" "License has been expired for ~p days.\n"
"Please visit https://emqx.com/apply-licenses/emqx or\n" "Apply a new license at https://emqx.com/apply-licenses/emqx.\n"
"contact customer services.\n" "Or contact EMQ customer services.\n"
"======================================================\n" "========================================================================\n"
). ).
-define(OFFICIAL, 1). -define(OFFICIAL, 1).

View File

@ -11,6 +11,7 @@
-define(CHECK_INTERVAL, 5000). -define(CHECK_INTERVAL, 5000).
-define(EXPIRY_ALARM_CHECK_INTERVAL, 24 * 60 * 60). -define(EXPIRY_ALARM_CHECK_INTERVAL, 24 * 60 * 60).
-define(OK(EXPR), try _ = begin EXPR end, ok catch _:_ -> ok end).
-export([ -export([
start_link/1, start_link/1,
@ -18,7 +19,8 @@
update/1, update/1,
dump/0, dump/0,
purge/0, purge/0,
limits/0 limits/0,
print_warnings/1
]). ]).
%% gen_server callbacks %% gen_server callbacks
@ -78,7 +80,7 @@ init([LicenseFetcher, CheckInterval]) ->
?LICENSE_TAB = ets:new(?LICENSE_TAB, [ ?LICENSE_TAB = ets:new(?LICENSE_TAB, [
set, protected, named_table, {read_concurrency, true} set, protected, named_table, {read_concurrency, true}
]), ]),
#{} = check_license(License), ok = print_warnings(check_license(License)),
State0 = ensure_check_license_timer(#{ State0 = ensure_check_license_timer(#{
check_license_interval => CheckInterval, check_license_interval => CheckInterval,
license => License license => License
@ -90,7 +92,7 @@ init([LicenseFetcher, CheckInterval]) ->
end. end.
handle_call({update, License}, _From, State) -> handle_call({update, License}, _From, State) ->
_ = expiry_early_alarm(License), ok = expiry_early_alarm(License),
{reply, check_license(License), State#{license => License}}; {reply, check_license(License), State#{license => License}};
handle_call(dump, _From, #{license := License} = State) -> handle_call(dump, _From, #{license := License} = State) ->
{reply, emqx_license_parser:dump(License), State}; {reply, emqx_license_parser:dump(License), State};
@ -109,7 +111,7 @@ handle_info(check_license, #{license := License} = State) ->
?tp(debug, emqx_license_checked, #{}), ?tp(debug, emqx_license_checked, #{}),
{noreply, NewState}; {noreply, NewState};
handle_info(check_expiry_alarm, #{license := License} = State) -> handle_info(check_expiry_alarm, #{license := License} = State) ->
_ = expiry_early_alarm(License), ok = expiry_early_alarm(License),
NewState = ensure_check_expiry_timer(State), NewState = ensure_check_expiry_timer(State),
{noreply, NewState}; {noreply, NewState};
handle_info(_Msg, State) -> handle_info(_Msg, State) ->
@ -138,21 +140,21 @@ cancel_timer(State, Key) ->
check_license(License) -> check_license(License) ->
DaysLeft = days_left(License), DaysLeft = days_left(License),
NeedRestrict = need_restrict(License, DaysLeft), IsOverdue = is_overdue(License, DaysLeft),
Limits = limits(License, NeedRestrict), NeedRestriction = IsOverdue,
MaxConn = emqx_license_parser:max_connections(License),
Limits = limits(License, NeedRestriction),
true = apply_limits(Limits), true = apply_limits(Limits),
#{ #{
warn_evaluation => warn_evaluation(License, NeedRestrict), warn_evaluation => warn_evaluation(License, NeedRestriction, MaxConn),
warn_expiry => warn_expiry(License, NeedRestrict) warn_expiry => {(DaysLeft < 0), -DaysLeft}
}. }.
warn_evaluation(License, false) -> warn_evaluation(License, false, MaxConn) ->
emqx_license_parser:customer_type(License) == ?EVALUATION_CUSTOMER; {emqx_license_parser:customer_type(License) == ?EVALUATION_CUSTOMER, MaxConn};
warn_evaluation(_License, _NeedRestrict) -> warn_evaluation(_License, _NeedRestrict, _Limits) ->
false. false.
warn_expiry(_License, NeedRestrict) -> NeedRestrict.
limits(License, false) -> #{max_connections => emqx_license_parser:max_connections(License)}; limits(License, false) -> #{max_connections => emqx_license_parser:max_connections(License)};
limits(_License, true) -> #{max_connections => ?ERR_EXPIRED}. limits(_License, true) -> #{max_connections => ?ERR_EXPIRED}.
@ -161,19 +163,20 @@ days_left(License) ->
{DateNow, _} = calendar:universal_time(), {DateNow, _} = calendar:universal_time(),
calendar:date_to_gregorian_days(DateEnd) - calendar:date_to_gregorian_days(DateNow). calendar:date_to_gregorian_days(DateEnd) - calendar:date_to_gregorian_days(DateNow).
need_restrict(License, DaysLeft) -> is_overdue(License, DaysLeft) ->
CType = emqx_license_parser:customer_type(License), CType = emqx_license_parser:customer_type(License),
Type = emqx_license_parser:license_type(License), Type = emqx_license_parser:license_type(License),
DaysLeft < 0 andalso small_customer_overdue(CType, DaysLeft) orelse
(Type =/= ?OFFICIAL) orelse small_customer_over_expired(CType, DaysLeft). non_official_license_overdue(Type, DaysLeft).
small_customer_over_expired(?SMALL_CUSTOMER, DaysLeft) when %% small customers overdue 90 days after license expiry date
DaysLeft < ?EXPIRED_DAY small_customer_overdue(?SMALL_CUSTOMER, DaysLeft) -> DaysLeft < ?EXPIRED_DAY;
-> small_customer_overdue(_CType, _DaysLeft) -> false.
true;
small_customer_over_expired(_CType, _DaysLeft) -> %% never restrict official license
false. non_official_license_overdue(?OFFICIAL, _) -> false;
non_official_license_overdue(_, DaysLeft) -> DaysLeft < 0.
apply_limits(Limits) -> apply_limits(Limits) ->
ets:insert(?LICENSE_TAB, {limits, Limits}). ets:insert(?LICENSE_TAB, {limits, Limits}).
@ -181,8 +184,23 @@ apply_limits(Limits) ->
expiry_early_alarm(License) -> expiry_early_alarm(License) ->
case days_left(License) < 30 of case days_left(License) < 30 of
true -> true ->
DateEnd = emqx_license_parser:expiry_date(License), {Y, M, D} = emqx_license_parser:expiry_date(License),
catch emqx_alarm:activate(license_expiry, #{expiry_at => DateEnd}); Date = iolist_to_binary(io_lib:format("~B~2..0B~2..0B", [Y, M, D])),
?OK(emqx_alarm:activate(license_expiry, #{expiry_at => Date}));
false -> false ->
catch emqx_alarm:deactivate(license_expiry) ?OK(emqx_alarm:deactivate(license_expiry))
end. end.
print_warnings(Warnings) ->
ok = print_evaluation_warning(Warnings),
ok = print_expiry_warning(Warnings).
print_evaluation_warning(#{warn_evaluation := {true, MaxConn}}) ->
io:format(?EVALUATION_LOG, [MaxConn]);
print_evaluation_warning(_) ->
ok.
print_expiry_warning(#{warn_expiry := {true, Days}}) ->
io:format(?EXPIRY_LOG, [Days]);
print_expiry_warning(_) ->
ok.

View File

@ -66,19 +66,4 @@ unload() ->
ok = emqx_ctl:unregister_command(license). ok = emqx_ctl:unregister_command(license).
print_warnings(Warnings) -> print_warnings(Warnings) ->
ok = print_evaluation_warning(Warnings), emqx_license_checker:print_warnings(Warnings).
ok = print_expiry_warning(Warnings).
%%------------------------------------------------------------------------------
%% Private functions
%%------------------------------------------------------------------------------
print_evaluation_warning(#{warn_evaluation := true}) ->
?PRINT_MSG(?EVALUATION_LOG);
print_evaluation_warning(_) ->
ok.
print_expiry_warning(#{warn_expiry := true}) ->
?PRINT_MSG(?EXPIRY_LOG);
print_expiry_warning(_) ->
ok.

View File

@ -89,6 +89,7 @@ dump(#{
[ [
{customer, Customer}, {customer, Customer},
{email, Email}, {email, Email},
{deployment, "default"},
{max_connections, MaxConnections}, {max_connections, MaxConnections},
{start_at, format_date(StartAtDate)}, {start_at, format_date(StartAtDate)},
{expiry_at, format_date(ExpiryAtDate)}, {expiry_at, format_date(ExpiryAtDate)},

View File

@ -48,6 +48,7 @@ dump(
customer_type := CType, customer_type := CType,
customer := Customer, customer := Customer,
email := Email, email := Email,
deployment := Deployment,
date_start := DateStart, date_start := DateStart,
max_connections := MaxConns max_connections := MaxConns
} = License } = License
@ -59,6 +60,7 @@ dump(
[ [
{customer, Customer}, {customer, Customer},
{email, Email}, {email, Email},
{deployment, Deployment},
{max_connections, MaxConns}, {max_connections, MaxConns},
{start_at, format_date(DateStart)}, {start_at, format_date(DateStart)},
{expiry_at, format_date(DateExpiry)}, {expiry_at, format_date(DateExpiry)},
@ -103,20 +105,21 @@ parse_payload(Payload) ->
string:split(string:trim(Payload), <<"\n">>, all) string:split(string:trim(Payload), <<"\n">>, all)
), ),
case Lines of case Lines of
[?LICENSE_VERSION, Type, CType, Customer, Email, DateStart, Days, MaxConns] -> [?LICENSE_VERSION, Type, CType, Customer, Email, Deployment, DateStart, Days, MaxConns] ->
collect_fields([ collect_fields([
{type, parse_type(Type)}, {type, parse_type(Type)},
{customer_type, parse_customer_type(CType)}, {customer_type, parse_customer_type(CType)},
{customer, {ok, Customer}}, {customer, {ok, Customer}},
{email, {ok, Email}}, {email, {ok, Email}},
{deployment, {ok, Deployment}},
{date_start, parse_date_start(DateStart)}, {date_start, parse_date_start(DateStart)},
{days, parse_days(Days)}, {days, parse_days(Days)},
{max_connections, parse_max_connections(MaxConns)} {max_connections, parse_max_connections(MaxConns)}
]); ]);
[_Version, _Type, _CType, _Customer, _Email, _DateStart, _Days, _MaxConns] -> [_Version, _Type, _CType, _Customer, _Email, _Deployment, _DateStart, _Days, _MaxConns] ->
{error, invalid_version}; {error, invalid_version};
_ -> _ ->
{error, invalid_field_number} {error, unexpected_number_of_fields}
end. end.
parse_type(TypeStr) -> parse_type(TypeStr) ->

View File

@ -102,6 +102,7 @@ t_check_exceeded(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -130,6 +131,7 @@ t_check_ok(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -160,6 +162,7 @@ t_check_expired(_Config) ->
"0", "0",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
%% Expired long ago %% Expired long ago
"20211101", "20211101",
"10", "10",

View File

@ -55,6 +55,7 @@ t_dump(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -67,6 +68,7 @@ t_dump(_Config) ->
[ [
{customer, <<"Foo">>}, {customer, <<"Foo">>},
{email, <<"contact@foo.com">>}, {email, <<"contact@foo.com">>},
{deployment, <<"bar">>},
{max_connections, 10}, {max_connections, 10},
{start_at, <<"2022-01-11">>}, {start_at, <<"2022-01-11">>},
{expiry_at, <<"2295-10-27">>}, {expiry_at, <<"2295-10-27">>},
@ -85,6 +87,7 @@ t_update(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
"20220111", "20220111",
"100000", "100000",
"123" "123"
@ -129,6 +132,7 @@ t_expired_trial(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
format_date(Date10DaysAgo), format_date(Date10DaysAgo),
"1", "1",
"123" "123"
@ -154,6 +158,7 @@ t_overexpired_small_client(_Config) ->
"0", "0",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
format_date(Date100DaysAgo), format_date(Date100DaysAgo),
"1", "1",
"123" "123"
@ -179,6 +184,7 @@ t_overexpired_medium_client(_Config) ->
"1", "1",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
format_date(Date100DaysAgo), format_date(Date100DaysAgo),
"1", "1",
"123" "123"
@ -204,6 +210,7 @@ t_recently_expired_small_client(_Config) ->
"0", "0",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar",
format_date(Date10DaysAgo), format_date(Date10DaysAgo),
"1", "1",
"123" "123"

View File

@ -51,6 +51,7 @@ t_parse(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"bar-deployment",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -73,8 +74,10 @@ t_parse(_Config) ->
"0", "0",
"10", "10",
"Foo", "Foo",
% one extra field
"Bar", "Bar",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -85,7 +88,7 @@ t_parse(_Config) ->
?assertMatch({error, _}, Res2), ?assertMatch({error, _}, Res2),
{error, Err2} = Res2, {error, Err2} = Res2,
?assertEqual( ?assertEqual(
invalid_field_number, unexpected_number_of_fields,
proplists:get_value(emqx_license_parser_v20220101, Err2) proplists:get_value(emqx_license_parser_v20220101, Err2)
), ),
@ -97,6 +100,7 @@ t_parse(_Config) ->
"ten", "ten",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"20220231", "20220231",
"-10", "-10",
"10" "10"
@ -124,6 +128,7 @@ t_parse(_Config) ->
"ten", "ten",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"2022-02-1st", "2022-02-1st",
"-10", "-10",
"10" "10"
@ -133,6 +138,7 @@ t_parse(_Config) ->
), ),
?assertMatch({error, _}, Res4), ?assertMatch({error, _}, Res4),
{error, Err4} = Res4, {error, Err4} = Res4,
?assertEqual( ?assertEqual(
[ [
{type, invalid_license_type}, {type, invalid_license_type},
@ -152,6 +158,7 @@ t_parse(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -167,6 +174,7 @@ t_parse(_Config) ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"20220111", "20220111",
"100000", "100000",
"10" "10"
@ -210,6 +218,7 @@ t_dump(_Config) ->
[ [
{customer, <<"Foo">>}, {customer, <<"Foo">>},
{email, <<"contact@foo.com">>}, {email, <<"contact@foo.com">>},
{deployment, <<"default-deployment">>},
{max_connections, 10}, {max_connections, 10},
{start_at, <<"2022-01-11">>}, {start_at, <<"2022-01-11">>},
{expiry_at, <<"2295-10-27">>}, {expiry_at, <<"2295-10-27">>},
@ -255,6 +264,7 @@ sample_license() ->
"10", "10",
"Foo", "Foo",
"contact@foo.com", "contact@foo.com",
"default-deployment",
"20220111", "20220111",
"100,000", "100,000",
"10" "10"

View File

@ -58,6 +58,7 @@ t_dump(_Config) ->
[ [
{customer, <<"EMQ X Evaluation">>}, {customer, <<"EMQ X Evaluation">>},
{email, "contact@emqx.io"}, {email, "contact@emqx.io"},
{deployment, "default"},
{max_connections, 10}, {max_connections, 10},
{start_at, <<"2020-06-20">>}, {start_at, <<"2020-06-20">>},
{expiry_at, <<"2049-01-01">>}, {expiry_at, <<"2049-01-01">>},

View File

@ -58,7 +58,7 @@ make_license(Values) ->
default_license() -> default_license() ->
%% keep it the same as in etc/emqx_license.conf %% keep it the same as in etc/emqx_license.conf
License = License =
"MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KMjAyMjAxMDEKMzY1MDAKMTAK." "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KZGVmYXVsdAoyMDIyMDQxOQoxODI1CjEwMDAK."
"MEUCIFc9EUjqB3SjpRqWjqmAzI4Tg4LwhCRet9scEoxMRt8fAiEAk6vfYUiPOTzBC+3EjNF3WmLTiA3B0TN5ZNwuTKbTXJQ=", "MEQCICbgRVijCQov2hrvZXR1mk9Oa+tyV1F5oJ6iOZeSHjnQAiB9dUiVeaZekDOjztk+NCWjhk4PG8tWfw2uFZWruSzD6g==",
ok = file:write_file(?DEFAULT_LICENSE_FILE, License), ok = file:write_file(?DEFAULT_LICENSE_FILE, License),
?DEFAULT_LICENSE_FILE. ?DEFAULT_LICENSE_FILE.