From f03d4d090ed79ea067a86c77107dddaef097d516 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 11 Jul 2023 11:53:41 +0800 Subject: [PATCH 1/6] feat: add license setting get/put api --- lib-ee/emqx_license/src/emqx_license.erl | 15 +++- .../src/emqx_license_http_api.erl | 77 ++++++++++++++++--- .../emqx_license/src/emqx_license_schema.erl | 8 +- rel/i18n/emqx_license_http_api.hocon | 6 ++ rel/i18n/emqx_license_schema.hocon | 16 +++- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/lib-ee/emqx_license/src/emqx_license.erl b/lib-ee/emqx_license/src/emqx_license.erl index 0918293a6..eaa9661e3 100644 --- a/lib-ee/emqx_license/src/emqx_license.erl +++ b/lib-ee/emqx_license/src/emqx_license.erl @@ -22,7 +22,8 @@ unload/0, read_license/0, read_license/1, - update_key/1 + update_key/1, + update_setting/1 ]). -define(CONF_KEY_PATH, [license]). @@ -64,6 +65,14 @@ update_key(Value) when is_binary(Value); is_list(Value) -> ), 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 %%------------------------------------------------------------------------------ @@ -96,6 +105,8 @@ check(_ConnInfo, AckProps) -> pre_config_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) -> case read_license(NewConf) of {ok, License} -> @@ -122,6 +133,8 @@ do_update({key, Content}, Conf) when is_binary(Content); is_list(Content) -> {error, Reason} -> erlang:throw(Reason) end; +do_update({setting, Setting}, Conf) -> + maps:merge(Conf, Setting); do_update(NewConf, _PrevConf) -> #{<<"key">> := NewKey} = NewConf, do_update({key, NewKey}, NewConf). diff --git a/lib-ee/emqx_license/src/emqx_license_http_api.erl b/lib-ee/emqx_license/src/emqx_license_http_api.erl index ef0e1ee52..93b759a06 100644 --- a/lib-ee/emqx_license/src/emqx_license_http_api.erl +++ b/lib-ee/emqx_license/src/emqx_license_http_api.erl @@ -13,11 +13,14 @@ namespace/0, api_spec/0, paths/0, - schema/1 + schema/1, + fields/1 ]). +-define(LICENSE_TAGS, [<<"License">>]). -export([ - '/license'/2 + '/license'/2, + '/license/setting'/2 ]). -define(BAD_REQUEST, 'BAD_REQUEST'). @@ -29,14 +32,15 @@ api_spec() -> paths() -> [ - "/license" + "/license", + "/license/setting" ]. schema("/license") -> #{ 'operationId' => '/license', get => #{ - tags => [<<"license">>], + tags => ?LICENSE_TAGS, summary => <<"Get license info">>, description => ?DESC("desc_license_info_api"), responses => #{ @@ -51,18 +55,16 @@ schema("/license") -> } }, post => #{ - tags => [<<"license">>], + tags => ?LICENSE_TAGS, summary => <<"Update license key">>, description => ?DESC("desc_license_key_api"), 'requestBody' => emqx_dashboard_swagger:schema_with_examples( - emqx_license_schema:key_license(), + hoconsc:ref(?MODULE, key_license), #{ license_key => #{ summary => <<"License key string">>, value => #{ - <<"key">> => <<"xxx">>, - <<"connection_low_watermark">> => "75%", - <<"connection_high_watermark">> => "80%" + <<"key">> => <<"xxx">> } } } @@ -79,6 +81,28 @@ schema("/license") -> 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() + } + }, + post => #{ + 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() -> @@ -117,3 +141,38 @@ error_msg(Code, Msg) -> end; '/license'(post, _Params) -> {400, error_msg(?BAD_REQUEST, <<"Invalid request params">>)}. + +'/license/setting'(get, _Params) -> + {200, maps:remove(<<"key">>, emqx_config:get_raw([license]))}; +'/license/setting'(post, #{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) -> + Key = lists:keyfind(key, 1, emqx_license_schema:fields(key_license)), + [ + Key, + %% FIXME: remove when 5.2.0 + {connection_low_watermark, #{ + type => emqx_schema:percent(), + deprecated => true, + desc => ?DESC(connection_low_watermark_field_deprecated) + }}, + {connection_high_watermark, #{ + type => emqx_schema:percent(), + deprecated => true, + desc => ?DESC(connection_high_watermark_field_deprecated) + }} + ]. + +setting() -> + lists:keydelete(key, 1, emqx_license_schema:fields(key_license)). diff --git a/lib-ee/emqx_license/src/emqx_license_schema.erl b/lib-ee/emqx_license/src/emqx_license_schema.erl index bb7868d8d..2132b0670 100644 --- a/lib-ee/emqx_license/src/emqx_license_schema.erl +++ b/lib-ee/emqx_license/src/emqx_license_schema.erl @@ -16,15 +16,14 @@ -export([roots/0, fields/1, validations/0, desc/1, tags/0]). -export([ - default_license/0, - key_license/0 + default_license/0 ]). roots() -> [ {license, hoconsc:mk( - key_license(), + hoconsc:ref(?MODULE, key_license), #{ desc => ?DESC(license_root) } @@ -64,9 +63,6 @@ desc(_) -> validations() -> [{check_license_watermark, fun check_license_watermark/1}]. -key_license() -> - hoconsc:ref(?MODULE, key_license). - check_license_watermark(Conf) -> case hocon_maps:get("license.connection_low_watermark", Conf) of undefined -> diff --git a/rel/i18n/emqx_license_http_api.hocon b/rel/i18n/emqx_license_http_api.hocon index 895041c18..63c9dc558 100644 --- a/rel/i18n/emqx_license_http_api.hocon +++ b/rel/i18n/emqx_license_http_api.hocon @@ -12,4 +12,10 @@ desc_license_key_api.desc: desc_license_key_api.label: """Update license""" +desc_license_setting_api.desc: +"""Update license setting""" + +desc_license_setting_api.label: +"""Update license setting""" + } diff --git a/rel/i18n/emqx_license_schema.hocon b/rel/i18n/emqx_license_schema.hocon index 3e4e37bff..51387ed39 100644 --- a/rel/i18n/emqx_license_schema.hocon +++ b/rel/i18n/emqx_license_schema.hocon @@ -12,6 +12,18 @@ connection_low_watermark_field.desc: connection_low_watermark_field.label: """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: """License string""" @@ -19,12 +31,12 @@ key_field.label: """License string""" 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). -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.""" license_root.label: From 43866b8e550be677e2acd21685ecfad0787aef25 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 12 Jul 2023 14:07:13 +0800 Subject: [PATCH 2/6] test(license): test setting HTTP API --- changes/ce/feat-11249.en.md | 1 + .../src/emqx_license_http_api.erl | 2 + .../emqx_license/src/emqx_license_schema.erl | 2 + .../test/emqx_license_http_api_SUITE.erl | 37 ++++++++++++++++++- 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 changes/ce/feat-11249.en.md diff --git a/changes/ce/feat-11249.en.md b/changes/ce/feat-11249.en.md new file mode 100644 index 000000000..fcbe03716 --- /dev/null +++ b/changes/ce/feat-11249.en.md @@ -0,0 +1 @@ +Support HTTP API for setting alarm watermark of license. diff --git a/lib-ee/emqx_license/src/emqx_license_http_api.erl b/lib-ee/emqx_license/src/emqx_license_http_api.erl index 93b759a06..fe280c735 100644 --- a/lib-ee/emqx_license/src/emqx_license_http_api.erl +++ b/lib-ee/emqx_license/src/emqx_license_http_api.erl @@ -164,11 +164,13 @@ fields(key_license) -> %% FIXME: remove when 5.2.0 {connection_low_watermark, #{ type => emqx_schema:percent(), + example => <<"75%">>, deprecated => true, desc => ?DESC(connection_low_watermark_field_deprecated) }}, {connection_high_watermark, #{ type => emqx_schema:percent(), + example => <<"80%">>, deprecated => true, desc => ?DESC(connection_high_watermark_field_deprecated) }} diff --git a/lib-ee/emqx_license/src/emqx_license_schema.erl b/lib-ee/emqx_license/src/emqx_license_schema.erl index 2132b0670..8f2d7f20d 100644 --- a/lib-ee/emqx_license/src/emqx_license_schema.erl +++ b/lib-ee/emqx_license/src/emqx_license_schema.erl @@ -46,11 +46,13 @@ fields(key_license) -> {connection_low_watermark, #{ type => emqx_schema:percent(), default => <<"75%">>, + example => <<"75%">>, desc => ?DESC(connection_low_watermark_field) }}, {connection_high_watermark, #{ type => emqx_schema:percent(), default => <<"80%">>, + example => <<"80%">>, desc => ?DESC(connection_high_watermark_field) }} ]. diff --git a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl index 3de5ae121..1b4a2ad2d 100644 --- a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl @@ -38,9 +38,15 @@ set_special_configs(emqx_dashboard) -> emqx_dashboard_api_test_helpers:set_default_config(<<"license_admin">>); set_special_configs(emqx_license) -> 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), - RawConfig = #{<<"key">> => LicenseKey}, + RawConfig = #{ + <<"key">> => LicenseKey, + <<"connection_low_watermark">> => <<"75%">>, + <<"connection_high_watermark">> => <<"80%">> + }, emqx_config:put_raw([<<"license">>], RawConfig), ok = persistent_term:put( emqx_license_test_pubkey, @@ -172,3 +178,30 @@ t_license_upload_key_not_json(_Config) -> ), assert_untouched_license(), ok. + +t_license_setting(_Config) -> + %% get + GetRes = request(get, uri(["license", "setting"]), []), + validate_setting(GetRes, <<"75%">>, <<"80%">>), + %% update + Low = <<"50%">>, + High = <<"55%">>, + UpdateRes = request(post, 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])), + 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]) + ). From f40d8318b7d25aec4bbda1264c94449adb68d2f2 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 12 Jul 2023 14:40:38 +0800 Subject: [PATCH 3/6] fix: license validations is not working --- apps/emqx_enterprise/src/emqx_enterprise.app.src | 2 +- .../src/emqx_enterprise_schema.erl | 2 +- .../test/emqx_license_http_api_SUITE.erl | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/emqx_enterprise/src/emqx_enterprise.app.src b/apps/emqx_enterprise/src/emqx_enterprise.app.src index 37c74bdec..ac35da5b9 100644 --- a/apps/emqx_enterprise/src/emqx_enterprise.app.src +++ b/apps/emqx_enterprise/src/emqx_enterprise.app.src @@ -1,6 +1,6 @@ {application, emqx_enterprise, [ {description, "EMQX Enterprise Edition"}, - {vsn, "0.1.1"}, + {vsn, "0.1.2"}, {registered, []}, {applications, [ kernel, diff --git a/apps/emqx_enterprise/src/emqx_enterprise_schema.erl b/apps/emqx_enterprise/src/emqx_enterprise_schema.erl index 67e8a9c9a..5da65e2f5 100644 --- a/apps/emqx_enterprise/src/emqx_enterprise_schema.erl +++ b/apps/emqx_enterprise/src/emqx_enterprise_schema.erl @@ -35,7 +35,7 @@ desc(Name) -> ee_delegate(desc, ?EE_SCHEMA_MODULES, Name). validations() -> - emqx_conf_schema:validations(). + emqx_conf_schema:validations() ++ emqx_license_schema:validations(). %%------------------------------------------------------------------------------ %% helpers diff --git a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl index 1b4a2ad2d..0de91c6d4 100644 --- a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl @@ -193,6 +193,22 @@ t_license_setting(_Config) -> 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(post, uri(["license", "setting"]), #{ + <<"connection_low_watermark">> => <<"50%">>, + <<"connection_high_watermark">> => <<"50%">> + }) + ), + ?assertMatch( + {ok, 400, _}, + request(post, uri(["license", "setting"]), #{ + <<"connection_low_watermark">> => <<"51%">>, + <<"connection_high_watermark">> => <<"50%">> + }) + ), ok. validate_setting(Res, ExpectLow, ExpectHigh) -> From a8b9b6f27f6b7982deb0ab2aa89a59d3f9a8fa62 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 12 Jul 2023 14:56:24 +0800 Subject: [PATCH 4/6] chore: use put instead of post to update setting --- lib-ee/emqx_license/src/emqx_license_http_api.erl | 5 +++-- lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib-ee/emqx_license/src/emqx_license_http_api.erl b/lib-ee/emqx_license/src/emqx_license_http_api.erl index fe280c735..ef350c87b 100644 --- a/lib-ee/emqx_license/src/emqx_license_http_api.erl +++ b/lib-ee/emqx_license/src/emqx_license_http_api.erl @@ -54,6 +54,7 @@ schema("/license") -> ) } }, + %% FIXME: It's a update action, should use put instead of post in 5.2.0 post => #{ tags => ?LICENSE_TAGS, summary => <<"Update license key">>, @@ -93,7 +94,7 @@ schema("/license/setting") -> 200 => setting() } }, - post => #{ + put => #{ tags => ?LICENSE_TAGS, summary => <<"Update license setting">>, description => ?DESC("desc_license_setting_api"), @@ -144,7 +145,7 @@ error_msg(Code, Msg) -> '/license/setting'(get, _Params) -> {200, maps:remove(<<"key">>, emqx_config:get_raw([license]))}; -'/license/setting'(post, #{body := Setting}) -> +'/license/setting'(put, #{body := Setting}) -> case emqx_license:update_setting(Setting) of {error, Error} -> ?SLOG(error, #{ diff --git a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl index 0de91c6d4..4ee0c8c8e 100644 --- a/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl +++ b/lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl @@ -186,7 +186,7 @@ t_license_setting(_Config) -> %% update Low = <<"50%">>, High = <<"55%">>, - UpdateRes = request(post, uri(["license", "setting"]), #{ + UpdateRes = request(put, uri(["license", "setting"]), #{ <<"connection_low_watermark">> => Low, <<"connection_high_watermark">> => High }), @@ -197,14 +197,14 @@ t_license_setting(_Config) -> %% update bad setting low >= high ?assertMatch( {ok, 400, _}, - request(post, uri(["license", "setting"]), #{ + request(put, uri(["license", "setting"]), #{ <<"connection_low_watermark">> => <<"50%">>, <<"connection_high_watermark">> => <<"50%">> }) ), ?assertMatch( {ok, 400, _}, - request(post, uri(["license", "setting"]), #{ + request(put, uri(["license", "setting"]), #{ <<"connection_low_watermark">> => <<"51%">>, <<"connection_high_watermark">> => <<"50%">> }) From 4a07106aa556fd6b0f58a9eac5e693bf19b8f1f0 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 12 Jul 2023 16:48:56 +0800 Subject: [PATCH 5/6] fix: don't include emqx_enterprise in community version --- mix.exs | 3 ++- rebar.config.erl | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 65c942394..41de27139 100644 --- a/mix.exs +++ b/mix.exs @@ -189,7 +189,8 @@ defmodule EMQXUmbrella.MixProject do :emqx_bridge_rabbitmq, :emqx_bridge_clickhouse, :emqx_ft, - :emqx_s3 + :emqx_s3, + :emqx_enterprise ]) end diff --git a/rebar.config.erl b/rebar.config.erl index 5f86afaa2..5db22990a 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -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_ft") -> false; is_community_umbrella_app("apps/emqx_s3") -> false; +is_community_umbrella_app("apps/emqx_enterprise") -> false; is_community_umbrella_app(_) -> true. is_jq_supported() -> From 8b73a50ca1309b98ea03a29b9056e999c674c3f2 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Wed, 12 Jul 2023 17:48:30 +0800 Subject: [PATCH 6/6] chore: delete watermark from /license post api --- .../src/emqx_license_http_api.erl | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/lib-ee/emqx_license/src/emqx_license_http_api.erl b/lib-ee/emqx_license/src/emqx_license_http_api.erl index ef350c87b..8f563300b 100644 --- a/lib-ee/emqx_license/src/emqx_license_http_api.erl +++ b/lib-ee/emqx_license/src/emqx_license_http_api.erl @@ -54,7 +54,7 @@ schema("/license") -> ) } }, - %% FIXME: It's a update action, should use put instead of post in 5.2.0 + %% TODO(5.x): It's a update action, should use PUT instead post => #{ tags => ?LICENSE_TAGS, summary => <<"Update license key">>, @@ -159,23 +159,7 @@ error_msg(Code, Msg) -> end. fields(key_license) -> - Key = lists:keyfind(key, 1, emqx_license_schema:fields(key_license)), - [ - Key, - %% FIXME: remove when 5.2.0 - {connection_low_watermark, #{ - type => emqx_schema:percent(), - example => <<"75%">>, - deprecated => true, - desc => ?DESC(connection_low_watermark_field_deprecated) - }}, - {connection_high_watermark, #{ - type => emqx_schema:percent(), - example => <<"80%">>, - deprecated => true, - desc => ?DESC(connection_high_watermark_field_deprecated) - }} - ]. + [lists:keyfind(key, 1, emqx_license_schema:fields(key_license))]. setting() -> lists:keydelete(key, 1, emqx_license_schema:fields(key_license)).