feat(license): allow setting 'default' license key
This commit is contained in:
parent
caaf8113fc
commit
14077ec43b
|
@ -59,6 +59,12 @@
|
|||
max_connections/1
|
||||
]).
|
||||
|
||||
%% for testing purpose
|
||||
-export([
|
||||
default/0,
|
||||
pubkey/0
|
||||
]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Behaviour
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -82,19 +88,18 @@
|
|||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-ifdef(TEST).
|
||||
pubkey() -> persistent_term:get(emqx_license_test_pubkey, ?PUBKEY).
|
||||
-else.
|
||||
pubkey() -> ?PUBKEY.
|
||||
-endif.
|
||||
default() -> emqx_license_schema:default_license().
|
||||
|
||||
%% @doc Parse license key.
|
||||
%% If the license key is prefixed with "file://path/to/license/file",
|
||||
%% then the license key is read from the file.
|
||||
-spec parse(string() | binary()) -> {ok, license()} | {error, map()}.
|
||||
-spec parse(default | string() | binary()) -> {ok, license()} | {error, map()}.
|
||||
parse(Content) ->
|
||||
parse(iolist_to_binary(Content), pubkey()).
|
||||
parse(to_bin(Content), ?MODULE:pubkey()).
|
||||
|
||||
parse(<<"default">>, PubKey) ->
|
||||
parse(?MODULE:default(), PubKey);
|
||||
parse(<<"file://", Path/binary>> = FileKey, PubKey) ->
|
||||
case file:read_file(Path) of
|
||||
{ok, Content} ->
|
||||
|
@ -159,3 +164,8 @@ do_parse(Content, Key, [Module | Modules], Errors) ->
|
|||
#{module => Module, error => Error, stacktrace => Stacktrace} | Errors
|
||||
])
|
||||
end.
|
||||
|
||||
to_bin(A) when is_atom(A) ->
|
||||
atom_to_binary(A);
|
||||
to_bin(L) ->
|
||||
iolist_to_binary(L).
|
||||
|
|
|
@ -38,8 +38,8 @@ tags() ->
|
|||
fields(key_license) ->
|
||||
[
|
||||
{key, #{
|
||||
type => binary(),
|
||||
default => default_license(),
|
||||
type => hoconsc:union([default, binary()]),
|
||||
default => <<"default">>,
|
||||
%% so it's not logged
|
||||
sensitive => true,
|
||||
required => true,
|
||||
|
|
|
@ -16,12 +16,14 @@ all() ->
|
|||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
emqx_license_test_lib:mock_parser(),
|
||||
_ = application:load(emqx_conf),
|
||||
emqx_config:save_schema_mod_and_names(emqx_license_schema),
|
||||
emqx_common_test_helpers:start_apps([emqx_license], fun set_special_configs/1),
|
||||
Config.
|
||||
|
||||
end_per_suite(_) ->
|
||||
emqx_license_test_lib:unmock_parser(),
|
||||
emqx_common_test_helpers:stop_apps([emqx_license]),
|
||||
ok.
|
||||
|
||||
|
@ -103,17 +105,7 @@ setup_test(TestCase, Config) when
|
|||
),
|
||||
ok;
|
||||
(emqx_license) ->
|
||||
LicensePath = filename:join(emqx_license:license_dir(), "emqx.lic"),
|
||||
filelib:ensure_dir(LicensePath),
|
||||
ok = file:write_file(LicensePath, LicenseKey),
|
||||
LicConfig = #{type => file, file => LicensePath},
|
||||
emqx_config:put([license], LicConfig),
|
||||
RawConfig = #{<<"type">> => file, <<"file">> => LicensePath},
|
||||
emqx_config:put_raw([<<"license">>], RawConfig),
|
||||
ok = persistent_term:put(
|
||||
emqx_license_test_pubkey,
|
||||
emqx_license_test_lib:public_key_pem()
|
||||
),
|
||||
set_special_configs(emqx_license),
|
||||
ok;
|
||||
(_) ->
|
||||
ok
|
||||
|
@ -129,9 +121,9 @@ teardown_test(_TestCase, _Config) ->
|
|||
ok.
|
||||
|
||||
set_special_configs(emqx_license) ->
|
||||
Config = #{key => emqx_license_test_lib:default_license()},
|
||||
Config = #{key => default},
|
||||
emqx_config:put([license], Config),
|
||||
RawConfig = #{<<"key">> => emqx_license_test_lib:default_license()},
|
||||
RawConfig = #{<<"key">> => <<"default">>},
|
||||
emqx_config:put_raw([<<"license">>], RawConfig);
|
||||
set_special_configs(_) ->
|
||||
ok.
|
||||
|
@ -150,7 +142,7 @@ t_update_value(_Config) ->
|
|||
emqx_license:update_key("invalid.license")
|
||||
),
|
||||
|
||||
LicenseValue = emqx_license_test_lib:default_license(),
|
||||
LicenseValue = emqx_license_test_lib:default_test_license(),
|
||||
|
||||
?assertMatch(
|
||||
{ok, #{}},
|
||||
|
|
|
@ -16,15 +16,12 @@ all() ->
|
|||
|
||||
init_per_suite(CtConfig) ->
|
||||
_ = application:load(emqx_conf),
|
||||
ok = persistent_term:put(
|
||||
emqx_license_test_pubkey,
|
||||
emqx_license_test_lib:public_key_pem()
|
||||
),
|
||||
emqx_license_test_lib:mock_parser(),
|
||||
ok = emqx_common_test_helpers:start_apps([emqx_license], fun set_special_configs/1),
|
||||
CtConfig.
|
||||
|
||||
end_per_suite(_) ->
|
||||
persistent_term:erase(emqx_license_test_pubkey),
|
||||
emqx_license_test_lib:unmock_parser(),
|
||||
ok = emqx_common_test_helpers:stop_apps([emqx_license]).
|
||||
|
||||
init_per_testcase(t_default_limits, Config) ->
|
||||
|
|
|
@ -24,15 +24,12 @@ end_per_suite(_) ->
|
|||
ok.
|
||||
|
||||
init_per_testcase(_Case, Config) ->
|
||||
ok = persistent_term:put(
|
||||
emqx_license_test_pubkey,
|
||||
emqx_license_test_lib:public_key_pem()
|
||||
),
|
||||
emqx_license_test_lib:mock_parser(),
|
||||
{ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
|
||||
Config.
|
||||
|
||||
end_per_testcase(_Case, _Config) ->
|
||||
persistent_term:erase(emqx_license_test_pubkey),
|
||||
emqx_license_test_lib:unmock_parser(),
|
||||
ok.
|
||||
|
||||
set_special_configs(emqx_license) ->
|
||||
|
|
|
@ -19,6 +19,7 @@ all() ->
|
|||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
emqx_license_test_lib:mock_parser(),
|
||||
_ = application:load(emqx_conf),
|
||||
emqx_config:save_schema_mod_and_names(emqx_license_schema),
|
||||
emqx_common_test_helpers:start_apps([emqx_license, emqx_dashboard], fun set_special_configs/1),
|
||||
|
@ -31,7 +32,7 @@ end_per_suite(_) ->
|
|||
emqx_config:put([license], Config),
|
||||
RawConfig = #{<<"key">> => LicenseKey},
|
||||
emqx_config:put_raw([<<"license">>], RawConfig),
|
||||
persistent_term:erase(emqx_license_test_pubkey),
|
||||
emqx_license_test_lib:unmock_parser(),
|
||||
ok.
|
||||
|
||||
set_special_configs(emqx_dashboard) ->
|
||||
|
@ -48,10 +49,6 @@ set_special_configs(emqx_license) ->
|
|||
<<"connection_high_watermark">> => <<"80%">>
|
||||
},
|
||||
emqx_config:put_raw([<<"license">>], RawConfig),
|
||||
ok = persistent_term:put(
|
||||
emqx_license_test_pubkey,
|
||||
emqx_license_test_lib:public_key_pem()
|
||||
),
|
||||
ok;
|
||||
set_special_configs(_) ->
|
||||
ok.
|
||||
|
@ -113,6 +110,19 @@ t_license_info(_Config) ->
|
|||
),
|
||||
ok.
|
||||
|
||||
t_set_default_license(_Config) ->
|
||||
NewKey = <<"default">>,
|
||||
Res = request(
|
||||
post,
|
||||
uri(["license"]),
|
||||
#{key => NewKey}
|
||||
),
|
||||
?assertMatch({ok, 200, _}, Res),
|
||||
{ok, 200, Payload} = Res,
|
||||
%% assert that it's not the string "default" returned
|
||||
?assertMatch(#{<<"customer">> := _}, emqx_utils_json:decode(Payload, [return_maps])),
|
||||
ok.
|
||||
|
||||
t_license_upload_key_success(_Config) ->
|
||||
NewKey = emqx_license_test_lib:make_license(#{max_connections => "999"}),
|
||||
Res = request(
|
||||
|
|
|
@ -70,3 +70,13 @@ default_test_license() ->
|
|||
|
||||
default_license() ->
|
||||
emqx_license_schema:default_license().
|
||||
|
||||
mock_parser() ->
|
||||
meck:new(emqx_license_parser, [non_strict, passthrough, no_history, no_link]),
|
||||
meck:expect(emqx_license_parser, pubkey, fun() -> public_key_pem() end),
|
||||
meck:expect(emqx_license_parser, default, fun() -> default_test_license() end),
|
||||
ok.
|
||||
|
||||
unmock_parser() ->
|
||||
meck:unload(emqx_license_parser),
|
||||
ok.
|
||||
|
|
|
@ -25,15 +25,16 @@ connection_low_watermark_field_deprecated.label:
|
|||
"""deprecated use /license/setting instead"""
|
||||
|
||||
key_field.desc:
|
||||
"""This configuration parameter is designated for the license key and supports two input formats:
|
||||
"""This configuration parameter is designated for the license key and supports below input formats:
|
||||
|
||||
- Direct Key: Enter the secret key directly as a string value.
|
||||
- File Path: Specify the path to a file that contains the secret key. Ensure the path starts with <code>file://</code>.
|
||||
- "default": Use string value <code>"default"</code> to apply the default trial license.
|
||||
|
||||
Note: An invalid license key or an incorrect file path may prevent EMQX from starting successfully.
|
||||
If a file path is used, EMQX attempts to reload the license key every 2 minutes.
|
||||
Any failure in reloading the license key will be recorded as an error level log message,
|
||||
without causing system downtime."""
|
||||
If a file path is used, EMQX attempts to reload the license key from the file every 2 minutes.
|
||||
Any failure in reloading the license file will be recorded as an error level log message,
|
||||
and EMQX continues to apply the license loaded previously."""
|
||||
|
||||
key_field.label:
|
||||
"""License string"""
|
||||
|
|
Loading…
Reference in New Issue