Просмотр исходного кода

Merge pull request #11249 from zhongwencool/license-setting-api

feat: add license setting get/put api
zhongwencool 2 лет назад
Родитель
Сommit
5b0695ca19

+ 1 - 1
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,

+ 1 - 1
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

+ 1 - 0
changes/ce/feat-11249.en.md

@@ -0,0 +1 @@
+Support HTTP API for setting alarm watermark of license.

+ 14 - 1
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).

+ 55 - 9
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 => #{
@@ -50,19 +54,18 @@ schema("/license") ->
                 )
             }
         },
+        %% TODO(5.x): It's a update action, should use PUT instead
         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 +82,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()
+            }
+        },
+        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() ->
@@ -117,3 +142,24 @@ 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'(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)).

+ 4 - 6
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)
                 }
@@ -47,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)
         }}
     ].
@@ -64,9 +65,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 ->

+ 51 - 2
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,46 @@ 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(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])
+    ).

+ 2 - 1
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
 

+ 1 - 0
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() ->

+ 6 - 0
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"""
+
 }

+ 14 - 2
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: