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

Merge pull request #12256 from keynslug/fix/mysql-wo-pwd

fix(mysql): expect password may be missing from config
Andrew Mayorov 2 лет назад
Родитель
Сommit
ca3109dfa6

+ 0 - 2
apps/emqx_bridge_mysql/test/emqx_bridge_mysql_SUITE.erl

@@ -112,8 +112,6 @@ end_per_group(_Group, _Config) ->
     ok.
 
 init_per_suite(Config) ->
-    emqx_common_test_helpers:clear_screen(),
-
     Config.
 
 end_per_suite(_Config) ->

+ 1 - 1
apps/emqx_mysql/src/emqx_mysql.app.src

@@ -1,6 +1,6 @@
 {application, emqx_mysql, [
     {description, "EMQX MySQL Database Connector"},
-    {vsn, "0.1.5"},
+    {vsn, "0.1.6"},
     {registered, []},
     {applications, [
         kernel,

+ 9 - 2
apps/emqx_mysql/src/emqx_mysql.erl

@@ -289,10 +289,17 @@ do_check_prepares(_NoTemplates) ->
 
 connect(Options) ->
     %% TODO: teach `tdengine` to accept 0-arity closures as passwords.
-    {value, {password, Secret}, Rest} = lists:keytake(password, 1, Options),
-    NOptions = [{password, emqx_secret:unwrap(Secret)} | Rest],
+    NOptions = init_connect_opts(Options),
     mysql:start_link(NOptions).
 
+init_connect_opts(Options) ->
+    case lists:keytake(password, 1, Options) of
+        {value, {password, Secret}, Rest} ->
+            [{password, emqx_secret:unwrap(Secret)} | Rest];
+        false ->
+            Options
+    end.
+
 init_prepare(State = #{query_templates := Templates}) ->
     case maps:size(Templates) of
         0 ->

+ 75 - 49
apps/emqx_mysql/test/emqx_mysql_SUITE.erl

@@ -1,17 +1,17 @@
-% %%--------------------------------------------------------------------
-% %% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
-% %%
-% %% Licensed under the Apache License, Version 2.0 (the "License");
-% %% you may not use this file except in compliance with the License.
-% %% You may obtain a copy of the License at
-% %% http://www.apache.org/licenses/LICENSE-2.0
-% %%
-% %% Unless required by applicable law or agreed to in writing, software
-% %% distributed under the License is distributed on an "AS IS" BASIS,
-% %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-% %% See the License for the specific language governing permissions and
-% %% limitations under the License.
-% %%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%--------------------------------------------------------------------
 
 -module(emqx_mysql_SUITE).
 
@@ -19,40 +19,30 @@
 -compile(export_all).
 
 -include_lib("emqx_connector/include/emqx_connector.hrl").
--include_lib("eunit/include/eunit.hrl").
--include_lib("emqx/include/emqx.hrl").
 -include_lib("stdlib/include/assert.hrl").
 
 -define(MYSQL_HOST, "mysql").
+-define(MYSQL_USER, "root").
+-define(MYSQL_PASSWORD, "public").
 -define(MYSQL_RESOURCE_MOD, emqx_mysql).
 
 all() ->
     emqx_common_test_helpers:all(?MODULE).
 
-groups() ->
-    [].
-
 init_per_suite(Config) ->
     case emqx_common_test_helpers:is_tcp_server_available(?MYSQL_HOST, ?MYSQL_DEFAULT_PORT) of
         true ->
-            ok = emqx_common_test_helpers:start_apps([emqx_conf]),
-            ok = emqx_connector_test_helpers:start_apps([emqx_resource]),
-            {ok, _} = application:ensure_all_started(emqx_connector),
-            Config;
+            Apps = emqx_cth_suite:start(
+                [emqx_conf, emqx_connector],
+                #{work_dir => emqx_cth_suite:work_dir(Config)}
+            ),
+            [{apps, Apps} | Config];
         false ->
             {skip, no_mysql}
     end.
 
-end_per_suite(_Config) ->
-    ok = emqx_common_test_helpers:stop_apps([emqx_conf]),
-    ok = emqx_connector_test_helpers:stop_apps([emqx_resource]),
-    _ = application:stop(emqx_connector).
-
-init_per_testcase(_, Config) ->
-    Config.
-
-end_per_testcase(_, _Config) ->
-    ok.
+end_per_suite(Config) ->
+    ok = emqx_cth_suite:stop(proplists:get_value(apps, Config)).
 
 % %%------------------------------------------------------------------------------
 % %% Testcases
@@ -64,6 +54,12 @@ t_lifecycle(_Config) ->
         mysql_config()
     ).
 
+t_lifecycle_passwordless(_Config) ->
+    perform_lifecycle_check(
+        <<"emqx_mysql_SUITE:passwordless">>,
+        mysql_config(passwordless)
+    ).
+
 perform_lifecycle_check(ResourceId, InitialConfig) ->
     {ok, #{config := CheckedConfig}} =
         emqx_resource:check_config(?MYSQL_RESOURCE_MOD, InitialConfig),
@@ -136,25 +132,55 @@ perform_lifecycle_check(ResourceId, InitialConfig) ->
 % %%------------------------------------------------------------------------------
 
 mysql_config() ->
-    RawConfig = list_to_binary(
-        io_lib:format(
-            ""
-            "\n"
-            "    auto_reconnect = true\n"
-            "    database = mqtt\n"
-            "    username= root\n"
-            "    password = public\n"
-            "    pool_size = 8\n"
-            "    server = \"~s:~b\"\n"
-            "    "
-            "",
-            [?MYSQL_HOST, ?MYSQL_DEFAULT_PORT]
-        )
-    ),
+    mysql_config(default).
+
+mysql_config(default) ->
+    parse_mysql_config(
+        "\n  auto_reconnect = true"
+        "\n  database = mqtt"
+        "\n  username = ~p"
+        "\n  password = ~p"
+        "\n  pool_size = 8"
+        "\n  server = \"~s:~b\""
+        "\n",
+        [?MYSQL_USER, ?MYSQL_PASSWORD, ?MYSQL_HOST, ?MYSQL_DEFAULT_PORT]
+    );
+mysql_config(passwordless) ->
+    ok = run_admin_query("CREATE USER IF NOT EXISTS 'nopwd'@'%'"),
+    ok = run_admin_query("GRANT ALL ON mqtt.* TO 'nopwd'@'%'"),
+    parse_mysql_config(
+        "\n  auto_reconnect = true"
+        "\n  database = mqtt"
+        "\n  username = nopwd"
+        "\n  pool_size = 8"
+        "\n  server = \"~s:~b\""
+        "\n",
+        [?MYSQL_HOST, ?MYSQL_DEFAULT_PORT]
+    ).
 
-    {ok, Config} = hocon:binary(RawConfig),
+parse_mysql_config(FormatString, Args) ->
+    {ok, Config} = hocon:binary(io_lib:format(FormatString, Args)),
     #{<<"config">> => Config}.
 
+run_admin_query(Query) ->
+    Pid = connect_mysql(),
+    try
+        mysql:query(Pid, Query)
+    after
+        mysql:stop(Pid)
+    end.
+
+connect_mysql() ->
+    Opts = [
+        {host, ?MYSQL_HOST},
+        {port, ?MYSQL_DEFAULT_PORT},
+        {user, ?MYSQL_USER},
+        {password, ?MYSQL_PASSWORD},
+        {database, "mysql"}
+    ],
+    {ok, Pid} = mysql:start_link(Opts),
+    Pid.
+
 test_query_no_params() ->
     {sql, <<"SELECT 1">>}.
 

+ 1 - 0
changes/ee/fix-12256.en.md

@@ -0,0 +1 @@
+Fix an issue where connections to passwordless MySQL resources could not be established.