From 7d807ce6bb85c1c676b4dec10f37346c1a1fea68 Mon Sep 17 00:00:00 2001 From: Thales Macedo Garitezi Date: Wed, 30 Mar 2022 17:53:28 -0300 Subject: [PATCH] feat(gateway): export basic gateway info for telemetry --- apps/emqx_gateway/src/emqx_gateway.erl | 63 ++++++++++++++ apps/emqx_gateway/test/emqx_gateway_SUITE.erl | 83 ++++++++++++++++++- .../test/emqx_gateway_SUITE_data/lwm2m.conf | 76 +++++++++++++++++ .../test/emqx_gateway_api_SUITE.erl | 2 + .../test/emqx_gateway_cm_SUITE.erl | 3 +- .../test/emqx_gateway_cm_registry_SUITE.erl | 3 +- .../test/emqx_gateway_conf_SUITE.erl | 3 +- .../test/emqx_mgmt_api_test_util.erl | 4 +- 8 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 apps/emqx_gateway/test/emqx_gateway_SUITE_data/lwm2m.conf diff --git a/apps/emqx_gateway/src/emqx_gateway.erl b/apps/emqx_gateway/src/emqx_gateway.erl index ecc7a96f3..12748c2a6 100644 --- a/apps/emqx_gateway/src/emqx_gateway.erl +++ b/apps/emqx_gateway/src/emqx_gateway.erl @@ -30,6 +30,9 @@ list/0 ]). +%% APIs For `emqx_telemetry' +-export([get_basic_usage_info/0]). + %%-------------------------------------------------------------------- %% APIs %%-------------------------------------------------------------------- @@ -81,6 +84,66 @@ start(Name) -> stop(Name) -> emqx_gateway_sup:stop_gateway_insta(Name). +%% @doc Expose basic info for `emqx_telemetry'. +-spec get_basic_usage_info() -> + #{ + authn => Authn, + num_clients => non_neg_integer(), + listeners => [ + #{ + type => atom(), + authn => Authn + } + ] + } +when + Authn :: binary(). +get_basic_usage_info() -> + lists:foldl( + fun(GatewayInfo, Acc) -> + Config = maps:get(config, GatewayInfo, #{}), + GatewayType = maps:get(name, GatewayInfo), + GatewayAuthn = get_authn_type(Config), + Listeners = get_listeners(Config), + TabName = emqx_gateway_cm:tabname(chan, GatewayType), + NumClients = ets:info(TabName, size), + Acc#{ + GatewayType => #{ + authn => GatewayAuthn, + listeners => Listeners, + num_clients => NumClients + } + } + end, + #{}, + list() + ). + %%-------------------------------------------------------------------- %% Internal funcs %%-------------------------------------------------------------------- + +get_authn_type(#{authentication := #{mechanism := Mechanism, backend := Backend}}) when + is_atom(Mechanism), is_atom(Backend) +-> + MechanismBin = atom_to_binary(Mechanism), + BackendBin = atom_to_binary(Backend), + <>; +get_authn_type(_) -> + <<"undefined">>. + +get_listeners(#{listeners := Listeners0}) when is_map(Listeners0) -> + Listeners = [ + {ListenerType, Config} + || {ListenerType, Listeners1} <- maps:to_list(Listeners0), + {_Name, Config} <- maps:to_list(Listeners1) + ], + lists:map( + fun({ListenerType, ListenerConfig}) -> + ListenerAuthn = get_authn_type(ListenerConfig), + #{type => ListenerType, authn => ListenerAuthn} + end, + Listeners + ); +get_listeners(_) -> + []. diff --git a/apps/emqx_gateway/test/emqx_gateway_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_SUITE.erl index fa8ea66d0..1f218090b 100644 --- a/apps/emqx_gateway/test/emqx_gateway_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_SUITE.erl @@ -17,6 +17,7 @@ -module(emqx_gateway_SUITE). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -compile(export_all). -compile(nowarn_export_all). @@ -37,7 +38,26 @@ init_per_suite(Conf) -> Conf. end_per_suite(_Conf) -> - emqx_common_test_helpers:stop_apps([emqx_gateway]). + emqx_common_test_helpers:stop_apps([emqx_gateway, emqx_authn]), + emqx_config:delete_override_conf_files(), + ok. + +init_per_testcase(t_get_basic_usage_info_2, Config) -> + DataDir = ?config(data_dir, Config), + emqx_common_test_helpers:stop_apps([emqx_gateway]), + ok = setup_fake_usage_data(DataDir), + Config; +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(t_get_basic_usage_info_2, _Config) -> + emqx_gateway_cm:unregister_channel(lwm2m, <<"client_id">>), + emqx_config:put([gateway], #{}), + emqx_common_test_helpers:stop_apps([emqx_gateway]), + emqx_common_test_helpers:start_apps([emqx_gateway]), + ok; +end_per_testcase(_TestCase, _Config) -> + ok. %%-------------------------------------------------------------------- %% cases @@ -114,3 +134,64 @@ t_start_stop_update(_) -> {error, already_started} = emqx_gateway:start(?GWNAME), ok. + +t_get_basic_usage_info_empty(_Config) -> + ?assertEqual( + #{}, + emqx_gateway:get_basic_usage_info() + ). + +t_get_basic_usage_info_1(_Config) -> + {ok, _} = emqx_gateway:load(?GWNAME, #{idle_timeout => 1000}), + ?assertEqual( + #{ + mqttsn => + #{ + authn => <<"undefined">>, + listeners => [], + num_clients => 0 + } + }, + emqx_gateway:get_basic_usage_info() + ). + +t_get_basic_usage_info_2(_Config) -> + ?assertEqual( + #{ + lwm2m => + #{ + authn => <<"password_based:redis">>, + listeners => + [ + #{ + authn => + <<"password_based:built_in_database">>, + type => udp + } + ], + num_clients => 1 + } + }, + emqx_gateway:get_basic_usage_info() + ). + +%%-------------------------------------------------------------------- +%% helper functions +%%-------------------------------------------------------------------- + +read_lwm2m_conf(DataDir) -> + ConfPath = filename:join([DataDir, "lwm2m.conf"]), + {ok, Conf} = file:read_file(ConfPath), + Conf. + +setup_fake_usage_data(Lwm2mDataDir) -> + XmlDir = emqx_common_test_helpers:deps_path(emqx_gateway, "src/lwm2m/lwm2m_xml"), + Lwm2mConf = read_lwm2m_conf(Lwm2mDataDir), + ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, Lwm2mConf), + emqx_config:put([gateway, lwm2m, xml_dir], XmlDir), + {ok, _} = application:ensure_all_started(emqx_gateway), + %% to simulate a connection + FakeConnInfo = #{conn_mod => fake_conn_mod}, + FakeChanPid = self(), + ok = emqx_gateway_cm:register_channel(lwm2m, <<"client_id">>, FakeChanPid, FakeConnInfo), + ok. diff --git a/apps/emqx_gateway/test/emqx_gateway_SUITE_data/lwm2m.conf b/apps/emqx_gateway/test/emqx_gateway_SUITE_data/lwm2m.conf new file mode 100644 index 000000000..160286a12 --- /dev/null +++ b/apps/emqx_gateway/test/emqx_gateway_SUITE_data/lwm2m.conf @@ -0,0 +1,76 @@ +gateway.lwm2m { + + ## How long time the connection will be disconnected if the + ## connection is established but no bytes received + idle_timeout = 30s + + ## To control whether write statistics data into ETS table + ## for dashboard to read. + enable_stats = true + + ## When publishing or subscribing, prefix all topics with a mountpoint string. + mountpoint = "lwm2m/${username}" + + xml_dir = "etc/lwm2m_xml" + + ## + ## + lifetime_min = 1s + + lifetime_max = 86400s + + qmode_time_window = 22s + + auto_observe = false + + ## always | contains_object_list + update_msg_publish_condition = contains_object_list + + + translators { + command { + topic = "/dn/#" + qos = 0 + } + + response { + topic = "/up/resp" + qos = 0 + } + + notify { + topic = "/up/notify" + qos = 0 + } + + register { + topic = "/up/resp" + qos = 0 + } + + update { + topic = "/up/resp" + qos = 0 + } + } + + listeners.udp.default { + bind = 5783 + authentication: { + mechanism: password_based, + backend: built_in_database + } + } + + authentication { + mechanism: password_based, + backend: redis, + redis_type: single, + server: "localhost:6379", + cmd: "HMGET mqtt_user:${username} password_hash salt is_superuser", + password_hash_algorithm: { + name: plain, + salt_position: suffix + } + } +} diff --git a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl index f2080dc8c..260cff115 100644 --- a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl @@ -42,6 +42,8 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Conf) -> + application:load(emqx), + emqx_config:delete_override_conf_files(), emqx_config:erase(gateway), emqx_common_test_helpers:load_config(emqx_gateway_schema, ?CONF_DEFAULT), emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_authn, emqx_gateway]), diff --git a/apps/emqx_gateway/test/emqx_gateway_cm_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_cm_SUITE.erl index 6aa3533df..ba5275e30 100644 --- a/apps/emqx_gateway/test/emqx_gateway_cm_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_cm_SUITE.erl @@ -43,7 +43,8 @@ init_per_suite(Conf) -> end_per_suite(_Conf) -> meck:unload(emqx_gateway_metrics), - emqx_common_test_helpers:stop_apps([]). + emqx_common_test_helpers:stop_apps([]), + emqx_config:delete_override_conf_files(). init_per_testcase(_TestCase, Conf) -> process_flag(trap_exit, true), diff --git a/apps/emqx_gateway/test/emqx_gateway_cm_registry_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_cm_registry_SUITE.erl index 1cfe40a3b..b9b7b38f6 100644 --- a/apps/emqx_gateway/test/emqx_gateway_cm_registry_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_cm_registry_SUITE.erl @@ -39,7 +39,8 @@ init_per_suite(Conf) -> Conf. end_per_suite(_Conf) -> - emqx_common_test_helpers:stop_apps([]). + emqx_common_test_helpers:stop_apps([]), + emqx_config:delete_override_conf_files(). init_per_testcase(_TestCase, Conf) -> {ok, Pid} = emqx_gateway_cm_registry:start_link(?GWNAME), diff --git a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl index e3de574e0..4d77fbb79 100644 --- a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl @@ -42,7 +42,8 @@ init_per_suite(Conf) -> Conf. end_per_suite(_Conf) -> - emqx_common_test_helpers:stop_apps([emqx_gateway, emqx_authn, emqx_conf]). + emqx_common_test_helpers:stop_apps([emqx_gateway, emqx_authn, emqx_conf]), + emqx_config:delete_override_conf_files(). init_per_testcase(_CaseName, Conf) -> _ = emqx_gateway_conf:unload_gateway(stomp), diff --git a/apps/emqx_management/test/emqx_mgmt_api_test_util.erl b/apps/emqx_management/test/emqx_mgmt_api_test_util.erl index a8aada448..76fb10f65 100644 --- a/apps/emqx_management/test/emqx_mgmt_api_test_util.erl +++ b/apps/emqx_management/test/emqx_mgmt_api_test_util.erl @@ -34,7 +34,9 @@ end_suite() -> end_suite(Apps) -> application:unload(emqx_management), - emqx_common_test_helpers:stop_apps(Apps ++ [emqx_dashboard]). + emqx_common_test_helpers:stop_apps(Apps ++ [emqx_dashboard]), + emqx_config:delete_override_conf_files(), + ok. set_special_configs(emqx_dashboard) -> Config = #{