diff --git a/.circleci/template.yml b/.circleci/template.yml index 39537a18724..510396408a6 100644 --- a/.circleci/template.yml +++ b/.circleci/template.yml @@ -591,7 +591,7 @@ jobs: preset: type: enum enum: [internal_mnesia, mysql_redis, odbc_mssql_mnesia, ldap_mnesia, - elasticsearch_and_cassandra_mnesia, pgsql_mnesia, internal_cets] + elasticsearch_and_cassandra_mnesia, pgsql_mnesia, pgsql_cets] description: Preset to run default: internal_mnesia db: @@ -826,11 +826,11 @@ workflows: - otp_25_docker filters: *all_tags - big_tests_in_docker: - name: internal_cets_25 - executor: otp_25_redis + name: pgsql_cets_25 + executor: otp_25_pgsql_redis context: mongooseim-org - preset: internal_cets - db: "mnesia cets" + preset: pgsql_cets + db: "mnesia postgres cets" requires: - otp_25_docker filters: *all_tags diff --git a/big_tests/default.spec b/big_tests/default.spec index 09686a6f466..7cd97facc0e 100644 --- a/big_tests/default.spec +++ b/big_tests/default.spec @@ -116,6 +116,7 @@ {suites, "tests", dynamic_domains_SUITE}. {suites, "tests", local_iq_SUITE}. {suites, "tests", tcp_listener_SUITE}. +{suites, "tests", cets_disco_SUITE}. {config, ["test.config"]}. {logdir, "ct_report"}. diff --git a/big_tests/dynamic_domains.spec b/big_tests/dynamic_domains.spec index 3710a19c6e5..8ec9e987850 100644 --- a/big_tests/dynamic_domains.spec +++ b/big_tests/dynamic_domains.spec @@ -158,6 +158,7 @@ {suites, "tests", domain_removal_SUITE}. {suites, "tests", local_iq_SUITE}. {suites, "tests", tcp_listener_SUITE}. +{suites, "tests", cets_disco_SUITE}. {config, ["dynamic_domains.config", "test.config"]}. diff --git a/big_tests/test.config b/big_tests/test.config index 377df5020e4..3ea5695ba62 100644 --- a/big_tests/test.config +++ b/big_tests/test.config @@ -237,13 +237,31 @@ {outgoing_pools, "[outgoing_pools.redis.global_distrib] scope = \"global\" workers = 10"}]}, - {internal_cets, - [{dbs, [redis]}, + {pgsql_cets, + [{dbs, [redis, pgsql]}, {sm_backend, "\"cets\""}, {stream_management_backend, cets}, + {auth_method, "rdbms"}, + {internal_databases, "[internal_databases.cets] + cluster_name = \"{{cluster_name}}\""}, {outgoing_pools, "[outgoing_pools.redis.global_distrib] scope = \"global\" - workers = 10"}]}, + workers = 10 +[outgoing_pools.rdbms.default] + scope = \"global\" + workers = 5 + connection.driver = \"pgsql\" + connection.host = \"localhost\" + connection.database = \"ejabberd\" + connection.username = \"ejabberd\" + connection.password = \"mongooseim_secret\" + connection.tls.required = true + connection.tls.cacertfile = \"priv/ssl/cacert.pem\" + connection.tls.server_name_indication.enabled = false"}, + {service_domain_db, ""}, + {mod_vcard, " backend = \"rdbms\" + host = \"vjud.@HOST@\"\n"}, + {mod_roster, " backend = \"rdbms\"\n"}]}, {pgsql_mnesia, [{dbs, [redis, pgsql]}, {auth_method, "rdbms"}, diff --git a/big_tests/tests/cets_disco_SUITE.erl b/big_tests/tests/cets_disco_SUITE.erl new file mode 100644 index 00000000000..b8efd04986e --- /dev/null +++ b/big_tests/tests/cets_disco_SUITE.erl @@ -0,0 +1,72 @@ +-module(cets_disco_SUITE). +-compile([export_all, nowarn_export_all]). + +-import(distributed_helper, [mim/0, rpc/4]). +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% Suite configuration +%%-------------------------------------------------------------------- + +all() -> + [{group, file}, {group, rdbms}]. + +groups() -> + [{file, [], file_cases()}, + {rdbms, [], rdbms_cases()}]. + +file_cases() -> + [file_backend]. + +rdbms_cases() -> + [rdbms_backend]. + +suite() -> + escalus:suite(). + +%%-------------------------------------------------------------------- +%% Init & teardown +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + escalus:init_per_suite(Config). + +end_per_suite(Config) -> + escalus:end_per_suite(Config). + +init_per_group(rdbms, Config) -> + case not ct_helper:is_ct_running() + orelse mongoose_helper:is_rdbms_enabled(domain_helper:host_type()) of + false -> {skip, rdbms_or_ct_not_running}; + true -> Config + end; +init_per_group(_, Config) -> + Config. + +end_per_group(_, Config) -> + Config. + +init_per_testcase(CaseName, Config) -> + escalus:init_per_testcase(CaseName, Config). + +end_per_testcase(CaseName, Config) -> + escalus:end_per_testcase(CaseName, Config). + +%%-------------------------------------------------------------------- +%% Test cases +%%-------------------------------------------------------------------- + +file_backend(Config) -> + Path = filename:join(?config(mim_data_dir, Config), "nodes.txt"), + Opts = #{disco_file => Path}, + State = rpc(mim(), cets_discovery_file, init, [Opts]), + {{ok, Nodes}, _} = rpc(mim(), cets_discovery_file, get_nodes, [State]), + ['node1@localhost', 'node2@otherhost'] = lists:sort(Nodes). + +rdbms_backend(_Config) -> + Opts1 = #{cluster_name => <<"big_test">>, node_name_to_insert => <<"test1">>}, + Opts2 = #{cluster_name => <<"big_test">>, node_name_to_insert => <<"test2">>}, + State1 = rpc(mim(), mongoose_cets_discovery_rdbms, init, [Opts1]), + rpc(mim(), mongoose_cets_discovery_rdbms, get_nodes, [State1]), + State2 = rpc(mim(), mongoose_cets_discovery_rdbms, init, [Opts2]), + {{ok, Nodes}, _} = rpc(mim(), mongoose_cets_discovery_rdbms, get_nodes, [State2]), + [test1, test2] = lists:sort(Nodes). diff --git a/big_tests/tests/cets_disco_SUITE_data/nodes.txt b/big_tests/tests/cets_disco_SUITE_data/nodes.txt new file mode 100644 index 00000000000..8e85e526bd8 --- /dev/null +++ b/big_tests/tests/cets_disco_SUITE_data/nodes.txt @@ -0,0 +1,2 @@ +node1@localhost +node2@otherhost diff --git a/doc/configuration/configuration-files.md b/doc/configuration/configuration-files.md index 35712ed2021..75b4e6ed366 100644 --- a/doc/configuration/configuration-files.md +++ b/doc/configuration/configuration-files.md @@ -15,6 +15,7 @@ The file is divided into the following sections: * [**general**](general.md) - Served XMPP domains, log level, server language and some other miscellaneous settings. * [**listen**](listen.md) - Configured listeners, receiving incoming XMPP and HTTP connections. * [**auth**](auth.md) - Supported client authentication methods and their options. +* [**internal_databases**](internal-databases.md) - Options for Mnesia and CETS. They are primarily used for clustering. * [**outgoing_pools**](outgoing-connections.md) - Outgoing connections to external services, including databases, message queues and HTTP services. * [**services**](Services.md) - Internal services like an administration API and system metrics. * [**modules**](Modules.md) - [XMPP extension](https://xmpp.org/extensions/) modules, which extend the basic functionality provided by XMPP. diff --git a/doc/configuration/internal-databases.md b/doc/configuration/internal-databases.md new file mode 100644 index 00000000000..91435a9e627 --- /dev/null +++ b/doc/configuration/internal-databases.md @@ -0,0 +1,67 @@ +Internal databases are used to cluster MongooseIM nodes, and to replicate session list data between them. + +Mnesia is a legacy way to cluster MongooseIM nodes. It is also could be used to store persistent data, but we recommend +to use RDBMS databases instead because of scalability and stability reasons. + +CETS is a new way to cluster MongooseIM nodes. +CETS needs to know a list of nodes for the node discovery. There are two ways to get a list of nodes: + +- A text file with a list of nodes on each line. It is useful when there is an external script to make this file based on + some custom logic (for example, a bash script that uses AWS CLI to discover instances in the autoscaling group). This file + would be automatilly reread on change. +- RDBMS database. MongooseIM would write into RDBMS its nodename and read a list of other nodes. It is pretty simple, but + RDBMS database could be a single point of failure. + +Section example: + +```toml +[internal_databases] + [internal_databases.mnesia] + + [internal_databases.cets] + backend = "rdbms" + cluster_name = "mongooseim" +``` + +or + +```toml +[internal_databases] + [internal_databases.cets] + backend = "file" + node_list_file = "cets_disco.txt" +``` + +To enable just CETS, define only `internal_databases.cets` section: + +```toml +[internal_databases] + [internal_databases.cets] +``` + +# CETS Options + +### `internal_databases.cets.backend` + +Backend for CETS discovery. + +* **Syntax:** string, one of `"rdbms"`, `"file"`. +* **Default:** `"rdbms"` +* **Example:** `backend = "rdbms"` + +### `internal_databases.cets.cluster_name` + +Namespace for the cluster. Only nodes with the same cluster name would be discoverd. This option is for RDBMS backend. + +* **Syntax:** string. +* **Default:** `"mongooseim"` +* **Example:** `cluster_name = "mongooseim"` + +### `internal_databases.cets.node_list_file` + +File to read a list of nodes from. Relative to the MongooseIM's release directory. This option is for the file backend. +Required, if `backend = "file"`. + +* **Syntax:** path. +* **Default:** not specified. +* **Example:** `node_list_file = "/etc/mim_nodes.txt"` diff --git a/mkdocs.yml b/mkdocs.yml index b61f6a8f7a5..1f947362739 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -69,6 +69,7 @@ nav: - 'Options: General': 'configuration/general.md' - 'Options: Listen': 'configuration/listen.md' - 'Options: Auth': 'configuration/auth.md' + - 'Options: Internal Databases': 'configuration/internal-databases.md' - 'Options: Outgoing connections': 'configuration/outgoing-connections.md' - 'Options: Services': 'configuration/Services.md' - 'Options: Extension Modules': 'configuration/Modules.md' diff --git a/priv/mssql2012.sql b/priv/mssql2012.sql index 351939358f7..605aa69bb85 100644 --- a/priv/mssql2012.sql +++ b/priv/mssql2012.sql @@ -752,3 +752,10 @@ CREATE TABLE domain_events ( domain VARCHAR(250) NOT NULL ); CREATE INDEX i_domain_events_domain ON domain_events(domain); + +CREATE TABLE discovery_nodes ( + node_name varchar(250), + cluster_name varchar(250), + updated_timestamp BIGINT NOT NULL, -- in microseconds + PRIMARY KEY (cluster_name, node_name) +); diff --git a/priv/mysql.sql b/priv/mysql.sql index f3f7ed00023..4b619a3b8b7 100644 --- a/priv/mysql.sql +++ b/priv/mysql.sql @@ -544,3 +544,10 @@ CREATE TABLE domain_events ( domain VARCHAR(250) NOT NULL ); CREATE INDEX i_domain_events_domain ON domain_events(domain); + +CREATE TABLE discovery_nodes ( + node_name varchar(250), + cluster_name varchar(250), + updated_timestamp BIGINT NOT NULL, -- in microseconds + PRIMARY KEY (cluster_name, node_name) +); diff --git a/priv/pg.sql b/priv/pg.sql index d0525f57c84..7aa5924ec04 100644 --- a/priv/pg.sql +++ b/priv/pg.sql @@ -504,3 +504,10 @@ CREATE TABLE domain_events ( PRIMARY KEY(id) ); CREATE INDEX i_domain_events_domain ON domain_events(domain); + +CREATE TABLE discovery_nodes ( + node_name varchar(250), + cluster_name varchar(250), + updated_timestamp BIGINT NOT NULL, -- in microseconds + PRIMARY KEY (cluster_name, node_name) +); diff --git a/rel/fed1.vars-toml.config b/rel/fed1.vars-toml.config index b6e34e8d401..34c4b2420f3 100644 --- a/rel/fed1.vars-toml.config +++ b/rel/fed1.vars-toml.config @@ -17,6 +17,7 @@ %% "localhost" host should NOT be defined. {hosts, "\"fed1\""}. {default_server_domain, "\"fed1\""}. +{cluster_name, "fed"}. %% domain.example.com is for multitenancy preset, muc_SUITE:register_over_s2s {s2s_addr, "[[s2s.address]] diff --git a/rel/files/mongooseim.toml b/rel/files/mongooseim.toml index eb6bc696879..fea8ca43c63 100644 --- a/rel/files/mongooseim.toml +++ b/rel/files/mongooseim.toml @@ -162,6 +162,8 @@ {{{auth_method_opts}}}{{/auth_method_opts}} {{/auth_method}} +{{{internal_databases}}} + {{#outgoing_pools}} {{{outgoing_pools}}} {{/outgoing_pools}} diff --git a/rel/mim1.vars-toml.config b/rel/mim1.vars-toml.config index 5fcea75ba4c..0cf2e6bbd8c 100644 --- a/rel/mim1.vars-toml.config +++ b/rel/mim1.vars-toml.config @@ -20,6 +20,7 @@ {hosts, "\"localhost\", \"anonymous.localhost\", \"localhost.bis\""}. {host_types, "\"test type\", \"dummy auth\", \"anonymous\""}. {default_server_domain, "\"localhost\""}. +{cluster_name, "mim"}. {mod_amp, ""}. {host_config, diff --git a/rel/mim2.vars-toml.config b/rel/mim2.vars-toml.config index 2581a209a45..758de03b341 100644 --- a/rel/mim2.vars-toml.config +++ b/rel/mim2.vars-toml.config @@ -18,6 +18,7 @@ {hosts, "\"localhost\", \"anonymous.localhost\", \"localhost.bis\""}. {host_types, "\"test type\", \"dummy auth\""}. {default_server_domain, "\"localhost\""}. +{cluster_name, "mim"}. {s2s_addr, "[[s2s.address]] host = \"localhost2\" ip_address = \"127.0.0.1\""}. diff --git a/rel/mim3.vars-toml.config b/rel/mim3.vars-toml.config index 645ea41e1cc..6e758440aa6 100644 --- a/rel/mim3.vars-toml.config +++ b/rel/mim3.vars-toml.config @@ -20,6 +20,7 @@ {hosts, "\"localhost\", \"anonymous.localhost\", \"localhost.bis\""}. {default_server_domain, "\"localhost\""}. +{cluster_name, "mim"}. {s2s_addr, "[[s2s.address]] host = \"localhost2\" diff --git a/rel/reg1.vars-toml.config b/rel/reg1.vars-toml.config index 4b5a4e4fea7..da485e138c5 100644 --- a/rel/reg1.vars-toml.config +++ b/rel/reg1.vars-toml.config @@ -21,6 +21,8 @@ %% "reg1" is a local host. {hosts, "\"reg1\", \"localhost\""}. {default_server_domain, "\"reg1\""}. +{cluster_name, "reg"}. + {s2s_addr, "[[s2s.address]] host = \"localhost\" ip_address = \"127.0.0.1\" diff --git a/rel/vars-toml.config b/rel/vars-toml.config index d17f75d1fcb..4d5e1b235b1 100644 --- a/rel/vars-toml.config +++ b/rel/vars-toml.config @@ -17,6 +17,8 @@ {http_api_client_endpoint, "port = {{ http_api_client_endpoint_port }}"}. {s2s_use_starttls, "\"optional\""}. {s2s_certfile, "\"priv/ssl/fake_server.pem\""}. +{internal_databases, "[internal_databases] + [internal_databases.mnesia]"}. "./configure.vars.config". diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 1ed67738942..34e5e615291 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -91,6 +91,7 @@ root() -> <<"listen">> => Listen#section{include = always}, <<"auth">> => Auth#section{include = always}, <<"outgoing_pools">> => outgoing_pools(), + <<"internal_databases">> => internal_databases(), <<"services">> => services(), <<"modules">> => Modules#section{include = always}, <<"shaper">> => shaper(), @@ -425,6 +426,32 @@ auth_password() -> include = always }. +%% path: internal_databases +internal_databases() -> + Items = #{<<"cets">> => internal_database_cets(), + <<"mnesia">> => internal_database_mnesia()}, + #section{items = Items, + format_items = map, + wrap = global_config, + include = always}. + +%% path: internal_databases.*.* +internal_database_cets() -> + #section{ + items = #{<<"backend">> => #option{type = atom, + validate = {enum, [file, rdbms]}}, + <<"cluster_name">> => #option{type = atom, validate = non_empty}, + %% Relative to the release directory (or an absolute name) + <<"node_list_file">> => #option{type = string, + validate = filename} + }, + defaults = #{<<"backend">> => rdbms, <<"cluster_name">> => mongooseim} + }. + +%% path: internal_databases.*.* +internal_database_mnesia() -> + #section{}. + %% path: outgoing_pools outgoing_pools() -> PoolTypes = [<<"cassandra">>, <<"elastic">>, <<"http">>, <<"ldap">>, diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 5b1cb95812d..f81fc5ea940 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -153,16 +153,9 @@ init([]) -> {pg, {pg, start_link, [mim_scope]}, permanent, infinity, supervisor, [pg]}, - ConfigDir = filename:dirname(mongoose_config:get_config_path()), - DiscoFile = filename:join(ConfigDir, "cets_disco.txt"), - DiscoOpts = #{name => mongoose_cets_discovery, disco_file => DiscoFile}, - CetsDisco = - {cets_discovery, - {cets_discovery, start_link, [DiscoOpts]}, - permanent, infinity, supervisor, [cets_discovery]}, {ok, {{one_for_one, 10, 1}, - [CetsDisco, - PG, + cets_specs() ++ + [PG, Hooks, Cleaner, SMBackendSupervisor, @@ -195,3 +188,34 @@ stop_child(Proc) -> supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc), ok. + +cets_specs() -> + cets_specs(mongoose_config:get_opt([internal_databases, cets], disabled)). + +cets_specs(disabled) -> + []; +cets_specs(#{backend := DiscoBackend, cluster_name := ClusterName} = Opts) -> + DiscoFile = + case {DiscoBackend, Opts} of + {file, #{node_list_file := NodeFile}} -> + NodeFile; + {file, _} -> + ?LOG_CRITICAL(#{what => node_list_file_option_is_required, + text => <<"Specify internal_databases.cets.node_list_file option">>}), + error(node_list_file_option_is_required); + _ -> + undefined + end, + DiscoOpts = #{ + backend_module => disco_backend_to_module(DiscoBackend), + cluster_name => atom_to_binary(ClusterName), + node_name_to_insert => atom_to_binary(node(), latin1), + name => mongoose_cets_discovery, disco_file => DiscoFile}, + CetsDisco = + {cets_discovery, + {cets_discovery, start_link, [DiscoOpts]}, + permanent, infinity, supervisor, [cets_discovery]}, + [CetsDisco]. + +disco_backend_to_module(rdbms) -> mongoose_cets_discovery_rdbms; +disco_backend_to_module(file) -> cets_discovery_file. diff --git a/src/mongoose_cets_discovery_rdbms.erl b/src/mongoose_cets_discovery_rdbms.erl new file mode 100644 index 00000000000..106c4e2d91b --- /dev/null +++ b/src/mongoose_cets_discovery_rdbms.erl @@ -0,0 +1,56 @@ +%% @doc MongooseIM RDBMS backend for cets_discovery. +-module(mongoose_cets_discovery_rdbms). +-behaviour(cets_discovery). +-export([init/1, get_nodes/1]). + +-include_lib("kernel/include/logger.hrl"). + +-type opts() :: #{cluster_name => binary(), node_name_to_insert => binary()}. +-type state() :: opts(). + +-spec init(opts()) -> state(). +init(Opts = #{cluster_name := _, node_name_to_insert := _}) -> + Opts. + +-spec get_nodes(state()) -> {cets_discovery:get_nodes_result(), state()}. +get_nodes(State = #{cluster_name := ClusterName, node_name_to_insert := Node}) -> + prepare(), + insert(ClusterName, Node), + try mongoose_rdbms:execute_successfully(global, cets_disco_select, [ClusterName]) of + {selected, Rows} -> + Nodes = [binary_to_atom(X) || {X} <- Rows, X =/= <<>>], + {{ok, Nodes}, State} + catch Class:Reason:Stacktrace -> + ?LOG_ERROR(#{ + what => discovery_failed_select, + class => Class, + reason => Reason, + stacktrace => Stacktrace + }), + {{error, Reason}, State} + end. + +prepare() -> + Filter = [<<"node_name">>, <<"cluster_name">>], + Fields = [<<"updated_timestamp">>], + rdbms_queries:prepare_upsert(global, cets_disco_insert, discovery_nodes, + Filter ++ Fields, Fields, Filter), + mongoose_rdbms:prepare(cets_disco_select, discovery_nodes, [cluster_name], + <<"SELECT node_name FROM discovery_nodes WHERE cluster_name = ?">>). + +insert(ClusterName, Node) -> + Timestamp = os:system_time(microsecond), + Filter = [Node, ClusterName], + Fields = [Timestamp], + try + {updated, _} = rdbms_queries:execute_upsert(global, cets_disco_insert, + Filter ++ Fields, Fields, + Filter) + catch Class:Reason:Stacktrace -> + ?LOG_ERROR(#{ + what => discovery_failed_insert, + class => Class, + reason => Reason, + stacktrace => Stacktrace + }) + end. diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl index b0de4bd1d76..f535dfdaf23 100644 --- a/test/common/config_parser_helper.erl +++ b/test/common/config_parser_helper.erl @@ -14,6 +14,7 @@ options("host_types") -> [<<"this is host type">>, <<"some host type">>, <<"another host type">>, <<"yet another host type">>]}, {hosts, [<<"localhost">>]}, + {internal_databases, #{}}, {language, <<"en">>}, {listen, []}, {loglevel, warning}, @@ -62,6 +63,10 @@ options("miscellaneous") -> {hide_service_name, true}, {host_types, []}, {hosts, [<<"localhost">>, <<"anonymous.localhost">>]}, + {internal_databases, + #{cets => + #{backend => rdbms, cluster_name => mongooseim}, + mnesia => #{}}}, {language, <<"en">>}, {listen, [config([listen, http], @@ -106,6 +111,7 @@ options("modules") -> {hide_service_name, false}, {host_types, []}, {hosts, [<<"localhost">>, <<"dummy_host">>]}, + {internal_databases, #{mnesia => #{}}}, {language, <<"en">>}, {listen, []}, {loglevel, warning}, @@ -131,6 +137,10 @@ options("mongooseim-pgsql") -> {host_types, []}, {hosts, [<<"localhost">>, <<"anonymous.localhost">>, <<"localhost.bis">>]}, + {internal_databases, + #{cets => + #{backend => rdbms, cluster_name => mongooseim}, + mnesia => #{}}}, {language, <<"en">>}, {listen, [config([listen, c2s], @@ -299,6 +309,7 @@ options("outgoing_pools") -> {host_types, []}, {hosts, [<<"localhost">>, <<"anonymous.localhost">>, <<"localhost.bis">>]}, + {internal_databases, #{}}, {language, <<"en">>}, {listen, []}, {loglevel, warning}, @@ -370,6 +381,7 @@ options("s2s_only") -> {hide_service_name, false}, {host_types, []}, {hosts, [<<"localhost">>, <<"dummy_host">>]}, + {internal_databases, #{}}, {language, <<"en">>}, {listen, []}, {loglevel, warning}, diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index be5ce8ed65b..aa8f0995b5b 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -52,6 +52,7 @@ all() -> {group, listen}, {group, auth}, {group, pool}, + {group, internal_databases}, {group, shaper_acl_access}, {group, s2s}, {group, modules}, @@ -147,6 +148,7 @@ groups() -> pool_rabbit_connection, pool_ldap, pool_ldap_connection]}, + {internal_databases, [parallel], [internal_database_cets]}, {shaper_acl_access, [parallel], [shaper, acl, acl_merge_host_and_global, @@ -1200,6 +1202,30 @@ test_fast_tls_server(P, T) -> ?err(T(#{<<"versions">> => [<<"tlsv1.2">>]})), % option only for just_tls ?err(T(#{<<"protocol_options">> => [<<>>]})). +%% tests: internal_databases + +internal_database_cets(_Config) -> + CetsEnabled = #{<<"internal_databases">> => #{<<"cets">> => #{}}}, + CetsFile = #{<<"internal_databases">> => #{<<"cets">> => + #{<<"backend">> => <<"file">>, <<"node_list_file">> => <<"/dev/null">>}}}, + %% No internal_databases section means an empty list of databases + ?cfg([internal_databases], #{}, #{}), % default + %% Empty internal_databases could be configured explicitly + ?cfg([internal_databases], #{}, #{<<"internal_databases">> => #{}}), + + ?cfg([internal_databases, cets, backend], file, + #{<<"internal_databases">> => #{<<"cets">> => #{<<"backend">> => <<"file">>}}}), + ?cfg([internal_databases, cets, backend], rdbms, + #{<<"internal_databases">> => #{<<"cets">> => #{<<"cluster_name">> => <<"test">>}}}), + + ?cfg([internal_databases, cets, cluster_name], mongooseim, CetsEnabled), + ?cfg([internal_databases, cets, node_list_file], "/dev/null", CetsFile), + %% If only mnesia section is defined, CETS section is not included + ?cfg([internal_databases], #{mnesia => #{}}, + #{<<"internal_databases">> => #{<<"mnesia">> => #{}}}), + ?err(#{<<"internal_databases">> => #{<<"cets">> => #{<<"backend">> => <<"mnesia">>}}}), + ?err(#{<<"internal_databases">> => #{<<"cets">> => #{<<"cluster_name">> => 123}}}). + %% tests: shaper, acl, access shaper(_Config) -> ?cfg([shaper, normal], #{max_rate => 1000}, diff --git a/test/config_parser_SUITE_data/miscellaneous.toml b/test/config_parser_SUITE_data/miscellaneous.toml index b94d35fa089..15ea205eac6 100644 --- a/test/config_parser_SUITE_data/miscellaneous.toml +++ b/test/config_parser_SUITE_data/miscellaneous.toml @@ -80,3 +80,7 @@ periodic_report = 300_000 tracking_id.id = "G-12345678" tracking_id.secret = "Secret" + +[internal_databases] + [internal_databases.mnesia] + [internal_databases.cets] diff --git a/test/config_parser_SUITE_data/modules.toml b/test/config_parser_SUITE_data/modules.toml index f11a1a4d6a5..35713d01edd 100644 --- a/test/config_parser_SUITE_data/modules.toml +++ b/test/config_parser_SUITE_data/modules.toml @@ -5,6 +5,9 @@ ] default_server_domain = "localhost" +[internal_databases] + [internal_databases.mnesia] + [modules.mod_adhoc] iqdisc.type = "one_queue" report_commands_node = true diff --git a/test/config_parser_SUITE_data/mongooseim-pgsql.toml b/test/config_parser_SUITE_data/mongooseim-pgsql.toml index ff43dc17e02..327087cc16d 100644 --- a/test/config_parser_SUITE_data/mongooseim-pgsql.toml +++ b/test/config_parser_SUITE_data/mongooseim-pgsql.toml @@ -12,6 +12,10 @@ sm_backend = "mnesia" max_fsm_queue = 1000 +[internal_databases] + [internal_databases.mnesia] + [internal_databases.cets] + [[listen.http]] port = 5280 transport.num_acceptors = 10 diff --git a/test/mongoose_config_SUITE.erl b/test/mongoose_config_SUITE.erl index 87d48955685..d8ea28afda8 100644 --- a/test/mongoose_config_SUITE.erl +++ b/test/mongoose_config_SUITE.erl @@ -177,6 +177,7 @@ minimal_config_opts() -> {hide_service_name, false}, {host_types, []}, {hosts, [<<"localhost">>]}, + {internal_databases, #{}}, {language, <<"en">>}, {listen, []}, {loglevel, warning}, diff --git a/tools/gh-actions-configure-preset.sh b/tools/gh-actions-configure-preset.sh index 9096c5f9c08..5b1f1201e25 100755 --- a/tools/gh-actions-configure-preset.sh +++ b/tools/gh-actions-configure-preset.sh @@ -36,6 +36,8 @@ case "$PRESET" in export REL_CONFIG="with-mysql with-redis with-amqp_client" ;; pgsql_mnesia) export REL_CONFIG="with-pgsql" ;; + cets_mnesia) + export REL_CONFIG="with-pgsql" ;; riak_mnesia) export REL_CONFIG="with-riak" ;; ldap_mnesia)