Merge pull request #11249 from zhongwencool/license-setting-api
feat: add license setting get/put api
This commit is contained in:
commit
5b0695ca19
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_enterprise, [
|
{application, emqx_enterprise, [
|
||||||
{description, "EMQX Enterprise Edition"},
|
{description, "EMQX Enterprise Edition"},
|
||||||
{vsn, "0.1.1"},
|
{vsn, "0.1.2"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [
|
{applications, [
|
||||||
kernel,
|
kernel,
|
||||||
|
|
|
@ -35,7 +35,7 @@ desc(Name) ->
|
||||||
ee_delegate(desc, ?EE_SCHEMA_MODULES, Name).
|
ee_delegate(desc, ?EE_SCHEMA_MODULES, Name).
|
||||||
|
|
||||||
validations() ->
|
validations() ->
|
||||||
emqx_conf_schema:validations().
|
emqx_conf_schema:validations() ++ emqx_license_schema:validations().
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% helpers
|
%% helpers
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Support HTTP API for setting alarm watermark of license.
|
|
@ -22,7 +22,8 @@
|
||||||
unload/0,
|
unload/0,
|
||||||
read_license/0,
|
read_license/0,
|
||||||
read_license/1,
|
read_license/1,
|
||||||
update_key/1
|
update_key/1,
|
||||||
|
update_setting/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(CONF_KEY_PATH, [license]).
|
-define(CONF_KEY_PATH, [license]).
|
||||||
|
@ -64,6 +65,14 @@ update_key(Value) when is_binary(Value); is_list(Value) ->
|
||||||
),
|
),
|
||||||
handle_config_update_result(Result).
|
handle_config_update_result(Result).
|
||||||
|
|
||||||
|
update_setting(Setting) when is_map(Setting) ->
|
||||||
|
Result = emqx_conf:update(
|
||||||
|
?CONF_KEY_PATH,
|
||||||
|
{setting, Setting},
|
||||||
|
#{rawconf_with_defaults => true, override_to => cluster}
|
||||||
|
),
|
||||||
|
handle_config_update_result(Result).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% emqx_hooks
|
%% emqx_hooks
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
@ -96,6 +105,8 @@ check(_ConnInfo, AckProps) ->
|
||||||
pre_config_update(_, Cmd, Conf) ->
|
pre_config_update(_, Cmd, Conf) ->
|
||||||
{ok, do_update(Cmd, Conf)}.
|
{ok, do_update(Cmd, Conf)}.
|
||||||
|
|
||||||
|
post_config_update(_Path, {setting, _}, NewConf, _Old, _AppEnvs) ->
|
||||||
|
{ok, NewConf};
|
||||||
post_config_update(_Path, _Cmd, NewConf, _Old, _AppEnvs) ->
|
post_config_update(_Path, _Cmd, NewConf, _Old, _AppEnvs) ->
|
||||||
case read_license(NewConf) of
|
case read_license(NewConf) of
|
||||||
{ok, License} ->
|
{ok, License} ->
|
||||||
|
@ -122,6 +133,8 @@ do_update({key, Content}, Conf) when is_binary(Content); is_list(Content) ->
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
erlang:throw(Reason)
|
erlang:throw(Reason)
|
||||||
end;
|
end;
|
||||||
|
do_update({setting, Setting}, Conf) ->
|
||||||
|
maps:merge(Conf, Setting);
|
||||||
do_update(NewConf, _PrevConf) ->
|
do_update(NewConf, _PrevConf) ->
|
||||||
#{<<"key">> := NewKey} = NewConf,
|
#{<<"key">> := NewKey} = NewConf,
|
||||||
do_update({key, NewKey}, NewConf).
|
do_update({key, NewKey}, NewConf).
|
||||||
|
|
|
@ -13,11 +13,14 @@
|
||||||
namespace/0,
|
namespace/0,
|
||||||
api_spec/0,
|
api_spec/0,
|
||||||
paths/0,
|
paths/0,
|
||||||
schema/1
|
schema/1,
|
||||||
|
fields/1
|
||||||
]).
|
]).
|
||||||
|
-define(LICENSE_TAGS, [<<"License">>]).
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
'/license'/2
|
'/license'/2,
|
||||||
|
'/license/setting'/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(BAD_REQUEST, 'BAD_REQUEST').
|
-define(BAD_REQUEST, 'BAD_REQUEST').
|
||||||
|
@ -29,14 +32,15 @@ api_spec() ->
|
||||||
|
|
||||||
paths() ->
|
paths() ->
|
||||||
[
|
[
|
||||||
"/license"
|
"/license",
|
||||||
|
"/license/setting"
|
||||||
].
|
].
|
||||||
|
|
||||||
schema("/license") ->
|
schema("/license") ->
|
||||||
#{
|
#{
|
||||||
'operationId' => '/license',
|
'operationId' => '/license',
|
||||||
get => #{
|
get => #{
|
||||||
tags => [<<"license">>],
|
tags => ?LICENSE_TAGS,
|
||||||
summary => <<"Get license info">>,
|
summary => <<"Get license info">>,
|
||||||
description => ?DESC("desc_license_info_api"),
|
description => ?DESC("desc_license_info_api"),
|
||||||
responses => #{
|
responses => #{
|
||||||
|
@ -50,19 +54,18 @@ schema("/license") ->
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
%% TODO(5.x): It's a update action, should use PUT instead
|
||||||
post => #{
|
post => #{
|
||||||
tags => [<<"license">>],
|
tags => ?LICENSE_TAGS,
|
||||||
summary => <<"Update license key">>,
|
summary => <<"Update license key">>,
|
||||||
description => ?DESC("desc_license_key_api"),
|
description => ?DESC("desc_license_key_api"),
|
||||||
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
|
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
|
||||||
emqx_license_schema:key_license(),
|
hoconsc:ref(?MODULE, key_license),
|
||||||
#{
|
#{
|
||||||
license_key => #{
|
license_key => #{
|
||||||
summary => <<"License key string">>,
|
summary => <<"License key string">>,
|
||||||
value => #{
|
value => #{
|
||||||
<<"key">> => <<"xxx">>,
|
<<"key">> => <<"xxx">>
|
||||||
<<"connection_low_watermark">> => "75%",
|
|
||||||
<<"connection_high_watermark">> => "80%"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +82,28 @@ schema("/license") ->
|
||||||
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad license key">>)
|
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad license key">>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
schema("/license/setting") ->
|
||||||
|
#{
|
||||||
|
'operationId' => '/license/setting',
|
||||||
|
get => #{
|
||||||
|
tags => ?LICENSE_TAGS,
|
||||||
|
summary => <<"Get license setting">>,
|
||||||
|
description => ?DESC("desc_license_setting_api"),
|
||||||
|
responses => #{
|
||||||
|
200 => setting()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
put => #{
|
||||||
|
tags => ?LICENSE_TAGS,
|
||||||
|
summary => <<"Update license setting">>,
|
||||||
|
description => ?DESC("desc_license_setting_api"),
|
||||||
|
'requestBody' => setting(),
|
||||||
|
responses => #{
|
||||||
|
200 => setting(),
|
||||||
|
400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad setting value">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
}.
|
}.
|
||||||
|
|
||||||
sample_license_info_response() ->
|
sample_license_info_response() ->
|
||||||
|
@ -117,3 +142,24 @@ error_msg(Code, Msg) ->
|
||||||
end;
|
end;
|
||||||
'/license'(post, _Params) ->
|
'/license'(post, _Params) ->
|
||||||
{400, error_msg(?BAD_REQUEST, <<"Invalid request params">>)}.
|
{400, error_msg(?BAD_REQUEST, <<"Invalid request params">>)}.
|
||||||
|
|
||||||
|
'/license/setting'(get, _Params) ->
|
||||||
|
{200, maps:remove(<<"key">>, emqx_config:get_raw([license]))};
|
||||||
|
'/license/setting'(put, #{body := Setting}) ->
|
||||||
|
case emqx_license:update_setting(Setting) of
|
||||||
|
{error, Error} ->
|
||||||
|
?SLOG(error, #{
|
||||||
|
msg => "bad_license_setting",
|
||||||
|
reason => Error
|
||||||
|
}),
|
||||||
|
{400, error_msg(?BAD_REQUEST, <<"Bad license setting">>)};
|
||||||
|
{ok, _} ->
|
||||||
|
?SLOG(info, #{msg => "updated_license_setting"}),
|
||||||
|
'/license/setting'(get, undefined)
|
||||||
|
end.
|
||||||
|
|
||||||
|
fields(key_license) ->
|
||||||
|
[lists:keyfind(key, 1, emqx_license_schema:fields(key_license))].
|
||||||
|
|
||||||
|
setting() ->
|
||||||
|
lists:keydelete(key, 1, emqx_license_schema:fields(key_license)).
|
||||||
|
|
|
@ -16,15 +16,14 @@
|
||||||
-export([roots/0, fields/1, validations/0, desc/1, tags/0]).
|
-export([roots/0, fields/1, validations/0, desc/1, tags/0]).
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
default_license/0,
|
default_license/0
|
||||||
key_license/0
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
roots() ->
|
roots() ->
|
||||||
[
|
[
|
||||||
{license,
|
{license,
|
||||||
hoconsc:mk(
|
hoconsc:mk(
|
||||||
key_license(),
|
hoconsc:ref(?MODULE, key_license),
|
||||||
#{
|
#{
|
||||||
desc => ?DESC(license_root)
|
desc => ?DESC(license_root)
|
||||||
}
|
}
|
||||||
|
@ -47,11 +46,13 @@ fields(key_license) ->
|
||||||
{connection_low_watermark, #{
|
{connection_low_watermark, #{
|
||||||
type => emqx_schema:percent(),
|
type => emqx_schema:percent(),
|
||||||
default => <<"75%">>,
|
default => <<"75%">>,
|
||||||
|
example => <<"75%">>,
|
||||||
desc => ?DESC(connection_low_watermark_field)
|
desc => ?DESC(connection_low_watermark_field)
|
||||||
}},
|
}},
|
||||||
{connection_high_watermark, #{
|
{connection_high_watermark, #{
|
||||||
type => emqx_schema:percent(),
|
type => emqx_schema:percent(),
|
||||||
default => <<"80%">>,
|
default => <<"80%">>,
|
||||||
|
example => <<"80%">>,
|
||||||
desc => ?DESC(connection_high_watermark_field)
|
desc => ?DESC(connection_high_watermark_field)
|
||||||
}}
|
}}
|
||||||
].
|
].
|
||||||
|
@ -64,9 +65,6 @@ desc(_) ->
|
||||||
validations() ->
|
validations() ->
|
||||||
[{check_license_watermark, fun check_license_watermark/1}].
|
[{check_license_watermark, fun check_license_watermark/1}].
|
||||||
|
|
||||||
key_license() ->
|
|
||||||
hoconsc:ref(?MODULE, key_license).
|
|
||||||
|
|
||||||
check_license_watermark(Conf) ->
|
check_license_watermark(Conf) ->
|
||||||
case hocon_maps:get("license.connection_low_watermark", Conf) of
|
case hocon_maps:get("license.connection_low_watermark", Conf) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
|
|
@ -38,9 +38,15 @@ set_special_configs(emqx_dashboard) ->
|
||||||
emqx_dashboard_api_test_helpers:set_default_config(<<"license_admin">>);
|
emqx_dashboard_api_test_helpers:set_default_config(<<"license_admin">>);
|
||||||
set_special_configs(emqx_license) ->
|
set_special_configs(emqx_license) ->
|
||||||
LicenseKey = emqx_license_test_lib:make_license(#{max_connections => "100"}),
|
LicenseKey = emqx_license_test_lib:make_license(#{max_connections => "100"}),
|
||||||
Config = #{key => LicenseKey},
|
Config = #{
|
||||||
|
key => LicenseKey, connection_low_watermark => 0.75, connection_high_watermark => 0.8
|
||||||
|
},
|
||||||
emqx_config:put([license], Config),
|
emqx_config:put([license], Config),
|
||||||
RawConfig = #{<<"key">> => LicenseKey},
|
RawConfig = #{
|
||||||
|
<<"key">> => LicenseKey,
|
||||||
|
<<"connection_low_watermark">> => <<"75%">>,
|
||||||
|
<<"connection_high_watermark">> => <<"80%">>
|
||||||
|
},
|
||||||
emqx_config:put_raw([<<"license">>], RawConfig),
|
emqx_config:put_raw([<<"license">>], RawConfig),
|
||||||
ok = persistent_term:put(
|
ok = persistent_term:put(
|
||||||
emqx_license_test_pubkey,
|
emqx_license_test_pubkey,
|
||||||
|
@ -172,3 +178,46 @@ t_license_upload_key_not_json(_Config) ->
|
||||||
),
|
),
|
||||||
assert_untouched_license(),
|
assert_untouched_license(),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
t_license_setting(_Config) ->
|
||||||
|
%% get
|
||||||
|
GetRes = request(get, uri(["license", "setting"]), []),
|
||||||
|
validate_setting(GetRes, <<"75%">>, <<"80%">>),
|
||||||
|
%% update
|
||||||
|
Low = <<"50%">>,
|
||||||
|
High = <<"55%">>,
|
||||||
|
UpdateRes = request(put, uri(["license", "setting"]), #{
|
||||||
|
<<"connection_low_watermark">> => Low,
|
||||||
|
<<"connection_high_watermark">> => High
|
||||||
|
}),
|
||||||
|
validate_setting(UpdateRes, Low, High),
|
||||||
|
?assertEqual(0.5, emqx_config:get([license, connection_low_watermark])),
|
||||||
|
?assertEqual(0.55, emqx_config:get([license, connection_high_watermark])),
|
||||||
|
|
||||||
|
%% update bad setting low >= high
|
||||||
|
?assertMatch(
|
||||||
|
{ok, 400, _},
|
||||||
|
request(put, uri(["license", "setting"]), #{
|
||||||
|
<<"connection_low_watermark">> => <<"50%">>,
|
||||||
|
<<"connection_high_watermark">> => <<"50%">>
|
||||||
|
})
|
||||||
|
),
|
||||||
|
?assertMatch(
|
||||||
|
{ok, 400, _},
|
||||||
|
request(put, uri(["license", "setting"]), #{
|
||||||
|
<<"connection_low_watermark">> => <<"51%">>,
|
||||||
|
<<"connection_high_watermark">> => <<"50%">>
|
||||||
|
})
|
||||||
|
),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
validate_setting(Res, ExpectLow, ExpectHigh) ->
|
||||||
|
?assertMatch({ok, 200, _}, Res),
|
||||||
|
{ok, 200, Payload} = Res,
|
||||||
|
?assertEqual(
|
||||||
|
#{
|
||||||
|
<<"connection_low_watermark">> => ExpectLow,
|
||||||
|
<<"connection_high_watermark">> => ExpectHigh
|
||||||
|
},
|
||||||
|
emqx_utils_json:decode(Payload, [return_maps])
|
||||||
|
).
|
||||||
|
|
3
mix.exs
3
mix.exs
|
@ -189,7 +189,8 @@ defmodule EMQXUmbrella.MixProject do
|
||||||
:emqx_bridge_rabbitmq,
|
:emqx_bridge_rabbitmq,
|
||||||
:emqx_bridge_clickhouse,
|
:emqx_bridge_clickhouse,
|
||||||
:emqx_ft,
|
:emqx_ft,
|
||||||
:emqx_s3
|
:emqx_s3,
|
||||||
|
:emqx_enterprise
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ is_community_umbrella_app("apps/emqx_oracle") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_bridge_rabbitmq") -> false;
|
is_community_umbrella_app("apps/emqx_bridge_rabbitmq") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_ft") -> false;
|
is_community_umbrella_app("apps/emqx_ft") -> false;
|
||||||
is_community_umbrella_app("apps/emqx_s3") -> false;
|
is_community_umbrella_app("apps/emqx_s3") -> false;
|
||||||
|
is_community_umbrella_app("apps/emqx_enterprise") -> false;
|
||||||
is_community_umbrella_app(_) -> true.
|
is_community_umbrella_app(_) -> true.
|
||||||
|
|
||||||
is_jq_supported() ->
|
is_jq_supported() ->
|
||||||
|
|
|
@ -12,4 +12,10 @@ desc_license_key_api.desc:
|
||||||
desc_license_key_api.label:
|
desc_license_key_api.label:
|
||||||
"""Update license"""
|
"""Update license"""
|
||||||
|
|
||||||
|
desc_license_setting_api.desc:
|
||||||
|
"""Update license setting"""
|
||||||
|
|
||||||
|
desc_license_setting_api.label:
|
||||||
|
"""Update license setting"""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,18 @@ connection_low_watermark_field.desc:
|
||||||
connection_low_watermark_field.label:
|
connection_low_watermark_field.label:
|
||||||
"""Connection low watermark"""
|
"""Connection low watermark"""
|
||||||
|
|
||||||
|
connection_high_watermark_field_deprecated.desc:
|
||||||
|
"""deprecated use /license/setting instead"""
|
||||||
|
|
||||||
|
connection_high_watermark_field_deprecated.label:
|
||||||
|
"""deprecated use /license/setting instead"""
|
||||||
|
|
||||||
|
connection_low_watermark_field_deprecated.desc:
|
||||||
|
"""deprecated use /license/setting instead"""
|
||||||
|
|
||||||
|
connection_low_watermark_field_deprecated.label:
|
||||||
|
"""deprecated use /license/setting instead"""
|
||||||
|
|
||||||
key_field.desc:
|
key_field.desc:
|
||||||
"""License string"""
|
"""License string"""
|
||||||
|
|
||||||
|
@ -19,12 +31,12 @@ key_field.label:
|
||||||
"""License string"""
|
"""License string"""
|
||||||
|
|
||||||
license_root.desc:
|
license_root.desc:
|
||||||
"""Defines the EMQX Enterprise license.
|
"""Defines the EMQX Enterprise license.
|
||||||
|
|
||||||
|
|
||||||
The default license has 100 connections limit, it is issued on 2023-01-09 and valid for 5 years (1825 days).
|
The default license has 100 connections limit, it is issued on 2023-01-09 and valid for 5 years (1825 days).
|
||||||
|
|
||||||
EMQX comes with a default trial license. For production use, please
|
EMQX comes with a default trial license. For production use, please
|
||||||
visit https://www.emqx.com/apply-licenses/emqx to apply."""
|
visit https://www.emqx.com/apply-licenses/emqx to apply."""
|
||||||
|
|
||||||
license_root.label:
|
license_root.label:
|
||||||
|
|
Loading…
Reference in New Issue