From 26f92493705f19ad5ea3bcabe383dfd6ca15f24d Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Tue, 27 Feb 2024 11:16:59 +0100 Subject: [PATCH 1/8] Simplify atom-binary conversions in config_spec listeners --- src/config/mongoose_config_spec.erl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 6611c6f62b..fa6665f28c 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -236,10 +236,10 @@ domain_cert() -> %% path: listen listen() -> - Keys = [c2s, s2s, service, http], + ListenerTypes = [<<"c2s">>, <<"s2s">>, <<"service">>, <<"http">>], #section{ - items = maps:from_list([{atom_to_binary(Key), #list{items = listener(Key), wrap = none}} - || Key <- Keys]), + items = maps:from_list([{Listener, #list{items = listener(Listener), wrap = none}} + || Listener <- ListenerTypes]), process = fun mongoose_listener_config:verify_unique_listeners/1, wrap = global_config, format_items = list @@ -264,7 +264,7 @@ listener_common() -> process = fun ?MODULE:process_listener/2 }. -listener_extra(http) -> +listener_extra(<<"http">>) -> %% tls options passed to ranch_ssl (with verify_mode translated to verify_fun) #section{items = #{<<"tls">> => tls([server], [just_tls]), <<"transport">> => http_transport(), @@ -292,7 +292,7 @@ xmpp_listener_common() -> <<"num_acceptors">> => 100} }. -xmpp_listener_extra(c2s) -> +xmpp_listener_extra(<<"c2s">>) -> #section{items = #{<<"access">> => #option{type = atom, validate = non_empty}, <<"shaper">> => #option{type = atom, @@ -315,14 +315,14 @@ xmpp_listener_extra(c2s) -> <<"reuse_port">> => false, <<"backwards_compatible_session">> => true} }; -xmpp_listener_extra(s2s) -> +xmpp_listener_extra(<<"s2s">>) -> TLSSection = tls([server], [fast_tls]), #section{items = #{<<"shaper">> => #option{type = atom, validate = non_empty}, <<"tls">> => TLSSection#section{include = always}}, defaults = #{<<"shaper">> => none} }; -xmpp_listener_extra(service) -> +xmpp_listener_extra(<<"service">>) -> #section{items = #{<<"access">> => #option{type = atom, validate = non_empty}, <<"shaper_rule">> => #option{type = atom, From dcf0cd7edceeb352f6ede5ea4b8cdeabf6445f58 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Wed, 28 Feb 2024 17:46:33 +0100 Subject: [PATCH 2/8] Extract list of scopes --- src/config/mongoose_config_spec.erl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index fa6665f28c..af38e6077a 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -475,10 +475,9 @@ wpool(ExtraDefaults) -> <<"call_timeout">> => 5000}, ExtraDefaults)}. outgoing_pool_extra(Type) -> + Scopes = [global, host_type, single_host_type, host, single_host], %% TODO deprecated #section{items = #{<<"scope">> => #option{type = atom, - validate = {enum, [global, - host_type, single_host_type, - host, single_host]}}, %% TODO deprecated + validate = {enum, Scopes}}, <<"host_type">> => #option{type = binary, validate = non_empty}, <<"host">> => #option{type = binary, %% TODO deprecated From aef7a94318c57258a0aba15d3a264a55e704a979 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Wed, 28 Feb 2024 17:47:31 +0100 Subject: [PATCH 3/8] Cosmetic spacing in mongoose_wpool --- src/wpool/mongoose_wpool.erl | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/wpool/mongoose_wpool.erl b/src/wpool/mongoose_wpool.erl index bc8f72a5e9..67f8930869 100644 --- a/src/wpool/mongoose_wpool.erl +++ b/src/wpool/mongoose_wpool.erl @@ -27,9 +27,7 @@ get_pool_settings/3, get_pools/0, stats/3]). -export([start_sup_pool/3]). --export([start_configured_pools/0]). --export([start_configured_pools/1]). --export([start_configured_pools/2]). +-export([start_configured_pools/0, start_configured_pools/1, start_configured_pools/2]). -export([is_configured/1]). -export([make_pool_name/3]). -export([call_start_callback/2]). @@ -43,14 +41,13 @@ start/5, start_configured_pools/1, start_configured_pools/2, stats/3, stop/1, stop/2]). --type pool_type() :: redis | http | rdbms | cassandra | elastic | generic - | rabbit | ldap. +-type pool_type() :: redis | http | rdbms | cassandra | elastic | generic | rabbit | ldap. %% Config scope -type scope() :: global | host_type | mongooseim:host_type(). -type host_type_or_global() :: mongooseim:host_type_or_global(). - -type tag() :: atom(). + %% Name of a process -type proc_name() :: atom(). @@ -80,13 +77,7 @@ -type start_result() :: {ok, pid()} | {error, term()}. -type stop_result() :: ok | term(). --export_type([pool_type/0]). --export_type([tag/0]). --export_type([scope/0]). --export_type([proc_name/0]). --export_type([pool_name/0]). --export_type([pool_opts/0]). --export_type([conn_opts/0]). +-export_type([pool_type/0, tag/0, scope/0, proc_name/0, pool_name/0, pool_opts/0, conn_opts/0]). -type callback_fun() :: init | start | is_supported_strategy | stop. From 9f45375837c56cbe9c7021d14851e057e7cce776 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Tue, 5 Mar 2024 15:57:12 +0100 Subject: [PATCH 4/8] Verify expanding pools before any side-effects are executed --- src/wpool/mongoose_wpool.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wpool/mongoose_wpool.erl b/src/wpool/mongoose_wpool.erl index 67f8930869..9924b9207a 100644 --- a/src/wpool/mongoose_wpool.erl +++ b/src/wpool/mongoose_wpool.erl @@ -112,8 +112,8 @@ start_configured_pools(PoolsIn) -> start_configured_pools(PoolsIn, ?ALL_HOST_TYPES). start_configured_pools(PoolsIn, HostTypes) -> - [call_callback(init, PoolType, []) || PoolType <- get_unique_types(PoolsIn)], Pools = expand_pools(PoolsIn, HostTypes), + [call_callback(init, PoolType, []) || PoolType <- get_unique_types(PoolsIn)], [start(Pool) || Pool <- Pools]. -spec start(pool_map()) -> start_result(). From 922092d886460ee1f77efd4dbc1c308001c159a0 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Tue, 5 Mar 2024 15:34:55 +0100 Subject: [PATCH 5/8] Move pools single_host opt to host_config sections --- doc/configuration/host_config.md | 20 ++++++++++ doc/configuration/outgoing-connections.md | 22 ++++------ doc/migrations/6.2.0_x.x.x.md | 4 +- src/config/mongoose_config_spec.erl | 40 +++++++++++++++---- test/common/config_parser_helper.erl | 31 ++++++++++++++ .../mongooseim-pgsql.toml | 11 ++++- .../outgoing_pools.toml | 5 +++ 7 files changed, 109 insertions(+), 24 deletions(-) diff --git a/doc/configuration/host_config.md b/doc/configuration/host_config.md index e645155446..1eb070615b 100644 --- a/doc/configuration/host_config.md +++ b/doc/configuration/host_config.md @@ -112,6 +112,26 @@ If we wanted to enable `mod_roster`, it would need to be repeated in `host_confi [host_config.modules.mod_stream_management] ``` +### `host_config.outgoing_pools` + +This section overrides any pool with the same type and tag that was defined in the top-level [`outgoing_pools`](outgoing-connections.md) section. +If we wanted to enable a `default` `rdbms` pool only for `"host-type-basic"` for example, we could do so as follows: + +```toml +[general] + host_type = ["host-type-basic", "host-type-advanced", "host-type-privacy"] + +[[host_config]] + host = "host-type-basic" + + [outgoing_pools.rdbms.default] + workers = 5 + [outgoing_pools.rdbms.default.connection] + ... +``` + +Configuration for such pools is all the same, except that the `scope` key is here disallowed. + ### `host_config.acl` The access classes defined here are merged with the ones defined in the top-level [`acl`](acl.md) section - when a class is defined in both places, the result is a union of both classes. diff --git a/doc/configuration/outgoing-connections.md b/doc/configuration/outgoing-connections.md index b14fa8c4d8..472a790f9a 100644 --- a/doc/configuration/outgoing-connections.md +++ b/doc/configuration/outgoing-connections.md @@ -15,32 +15,24 @@ This allows you to create multiple dedicated pools of the same type. ## General pool options ### `outgoing_pools.*.*.scope` -* **Syntax:** string, one of:`"global"`, `"host_type"`, `"single_host_type"` +* **Syntax:** string, one of:`"global"`, `"host_type"`. * **Default:** `"global"` * **Example:** `scope = "host_type"` -### `outgoing_pools.*.*.host_type` -* **Syntax:** string -* **Default:** no default; required if `"single_host_type"` scope is specified -* **Example:** `host_type = "basic_host_type"` - -### `outgoing_pools.*.*.host` -* **Syntax:** string -* **Default:** no default; required if `"single_host"` scope is specified -* **Example:** `host = "anotherhost.com"` - `scope` can be set to: -* `global` - meaning that the pool will be started once no matter how many XMPP hosts are served by MongooseIM -* `host_type` - the pool will be started for each XMPP host or host type served by MongooseIM -* `single_host_type` - the pool will be started for the selected host or host type only (you must provide the name). +* `global` - meaning that the pool will be started once no matter how many XMPP hosts are served by MongooseIM. +* `host_type` - the pool will be started for each static XMPP host or host type served by MongooseIM. !!! Note A pool with scope `global` and tag `default` is used by services that are not configured by host_type, like `service_domain_db` or `service_mongoose_system_metrics`, or by modules that don't support dynamic domains, like `mod_pubsub`. If a global default pool is not configured, these services will fail. !!! Note - `host` and `single_host` are still supported and behave equivalent to `host_type` and `single_host_type` respectively; however, they are deprecated in favour of the latter. + The option `host` is still supported and behaves equivalent to `host_type`; however, it is deprecated in favour of the latter. + + !!! Warning + The options `single_host` and `single_host_type` for the scope has been deprecated, in favour of configuring the specified pools within the [`host_config`](host_config.md) section. ## Worker pool options diff --git a/doc/migrations/6.2.0_x.x.x.md b/doc/migrations/6.2.0_x.x.x.md index 1c58f46455..5272e65e84 100644 --- a/doc/migrations/6.2.0_x.x.x.md +++ b/doc/migrations/6.2.0_x.x.x.md @@ -12,4 +12,6 @@ There is a new column in the `mam_message` table in the database, which is used ## Outgoing pools -Pools now take `host_type` and `single_host_type` instead of `host` and `single_host` in their scope, see [outgoing pools](../configuration/outgoing-connections.md) for more information. +The outgoing connections option `host` is now named `host_type`, see [outgoing pools](../configuration/outgoing-connections.md) for more information. + +The option `single_host` for the scope has been deprecated, in favour of configuring the specified pools within the [`host_config`](../configuration/host_config.md) section. diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index af38e6077a..6d03201ea0 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -21,6 +21,7 @@ process_sasl_mechanism/1, process_auth/1, process_pool/2, + process_host_config_pool/2, process_ldap_connection/1, process_iqdisc/1, process_acl_condition/1, @@ -136,6 +137,7 @@ host_config() -> <<"general">> => general(), <<"auth">> => auth(), <<"modules">> => modules(), + <<"outgoing_pools">> => host_config_outgoing_pools(), <<"acl">> => acl(), <<"access">> => access(), <<"s2s">> => s2s() @@ -438,21 +440,34 @@ internal_database_mnesia() -> %% path: outgoing_pools outgoing_pools() -> + outgoing_pools(global_config). + +%% path: (host_config[].)outgoing_pools +host_config_outgoing_pools() -> + outgoing_pools(host_config). + +outgoing_pools(Scope) -> PoolTypes = [<<"cassandra">>, <<"elastic">>, <<"http">>, <<"ldap">>, <<"rabbit">>, <<"rdbms">>, <<"redis">>], - Items = [{Type, #section{items = #{default => outgoing_pool(Type)}, + Items = [{Type, #section{items = #{default => outgoing_pool(Scope, Type)}, validate_keys = non_empty, wrap = none, format_items = list}} || Type <- PoolTypes], #section{items = maps:from_list(Items), format_items = list, - wrap = global_config, - include = always}. + wrap = Scope, + include = include_only_on_global_config(Scope)}. + +include_only_on_global_config(global_config) -> + always; +include_only_on_global_config(host_config) -> + when_present. %% path: outgoing_pools.*.* -outgoing_pool(Type) -> +outgoing_pool(Scope, Type) -> ExtraDefaults = extra_wpool_defaults(Type), - Pool = mongoose_config_utils:merge_sections(wpool(ExtraDefaults), outgoing_pool_extra(Type)), + ExtraConfig = outgoing_pool_extra(Scope, Type), + Pool = mongoose_config_utils:merge_sections(wpool(ExtraDefaults), ExtraConfig), Pool#section{wrap = item}. extra_wpool_defaults(<<"cassandra">>) -> @@ -474,7 +489,11 @@ wpool(ExtraDefaults) -> <<"strategy">> => best_worker, <<"call_timeout">> => 5000}, ExtraDefaults)}. -outgoing_pool_extra(Type) -> +outgoing_pool_extra(host_config, Type) -> + #section{items = #{<<"connection">> => outgoing_pool_connection(Type)}, + process = fun ?MODULE:process_host_config_pool/2 + }; +outgoing_pool_extra(global_config, Type) -> Scopes = [global, host_type, single_host_type, host, single_host], %% TODO deprecated #section{items = #{<<"scope">> => #option{type = atom, validate = {enum, Scopes}}, @@ -1080,7 +1099,7 @@ check_auth_method(Method, Opts) -> false -> error(#{what => missing_section_for_auth_method, auth_method => Method}) end. -process_pool([Tag, Type|_], AllOpts = #{scope := ScopeIn, connection := Connection}) -> +process_pool([Tag, Type | _], AllOpts = #{scope := ScopeIn, connection := Connection}) -> Scope = pool_scope(ScopeIn, maps:get(host_type, AllOpts, maps:get(host, AllOpts, none))), Opts = maps:without([scope, host, connection], AllOpts), #{type => b2a(Type), @@ -1089,6 +1108,13 @@ process_pool([Tag, Type|_], AllOpts = #{scope := ScopeIn, connection := Connecti opts => Opts, conn_opts => Connection}. +process_host_config_pool([Tag, Type, _Pools, {host, HT} | _], AllOpts = #{connection := Connection}) -> + #{type => b2a(Type), + scope => HT, + tag => b2a(Tag), + opts => maps:remove(connection, AllOpts), + conn_opts => Connection}. + pool_scope(single_host_type, none) -> error(#{what => pool_single_host_type_not_specified, text => <<"\"host_type\" option is required if \"single_host_type\" is used.">>}); diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl index a93adcf343..7bdea9685e 100644 --- a/test/common/config_parser_helper.erl +++ b/test/common/config_parser_helper.erl @@ -262,6 +262,21 @@ options("mongooseim-pgsql") -> {sm_backend, mnesia}, {component_backend, mnesia}, {s2s_backend, mnesia}, + {{outgoing_pools, <<"anonymous.localhost">>}, + lists:map( + fun host_pool_config/1, + [#{tag => special, + scope => <<"anonymous.localhost">>, + type => rdbms, + opts => #{workers => 5}, + conn_opts => #{driver => pgsql, host => "localhost", port => 5432, database => "mongooseim", + username => "mongooseim", password => "mongooseim_secret", + tls => #{required => true, + cacertfile => "priv/ca.pem", + server_name_indication => #{enabled => false}} + } + } + ])}, {{auth, <<"anonymous.localhost">>}, (default_auth())#{anonymous => #{backend => mnesia, allow_multiple_connections => true, @@ -285,6 +300,11 @@ options("mongooseim-pgsql") -> {{replaced_wait_timeout, <<"anonymous.localhost">>}, 2000}, {{replaced_wait_timeout, <<"localhost">>}, 2000}, {{replaced_wait_timeout, <<"localhost.bis">>}, 2000}, + {{outgoing_pools, <<"localhost">>}, + lists:map( + fun host_pool_config/1, + [#{type => redis, scope => <<"localhost">>, tag => global_distrib, + opts => #{workers => 10}, conn_opts => #{}}])}, {{s2s, <<"anonymous.localhost">>}, pgsql_s2s()}, {{s2s, <<"localhost">>}, pgsql_s2s()}, {{s2s, <<"localhost.bis">>}, pgsql_s2s()}, @@ -353,6 +373,11 @@ options("outgoing_pools") -> {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, {services, #{}}, + {{outgoing_pools, <<"localhost.bis">>}, + lists:map( + fun host_pool_config/1, + [#{type => redis, scope => <<"localhost">>, tag => global_distrib, + opts => #{workers => 10}, conn_opts => #{}}])}, {{s2s, <<"anonymous.localhost">>}, default_s2s()}, {{s2s, <<"localhost">>}, default_s2s()}, {{s2s, <<"localhost.bis">>}, default_s2s()}, @@ -771,6 +796,9 @@ pgsql_access() -> pool_config(PoolIn = #{type := Type}) -> config([outgoing_pools, Type, maps:get(tag, PoolIn, default)], PoolIn). +host_pool_config(PoolIn = #{type := Type}) -> + config([host_config, outgoing_pools, Type, maps:get(tag, PoolIn, default)], PoolIn). + default_pool_wpool_opts(cassandra) -> #{workers => 20, strategy => best_worker, @@ -1258,6 +1286,9 @@ default_config([outgoing_pools, _Type, _Tag, conn_opts, tls] = P) -> server_name_indication => default_config(P ++ [server_name_indication])}; default_config([outgoing_pools, _Type, _Tag, conn_opts, tls, server_name_indication]) -> #{enabled => true, protocol => default}; +default_config([host_config, outgoing_pools | Path]) -> + Default = default_config([outgoing_pools | Path]), + maps:remove(scope, Default); default_config([services, service_domain_db]) -> #{event_cleaning_interval => 1800, event_max_age => 7200, diff --git a/test/config_parser_SUITE_data/mongooseim-pgsql.toml b/test/config_parser_SUITE_data/mongooseim-pgsql.toml index c2d88921a7..7ce51e1010 100644 --- a/test/config_parser_SUITE_data/mongooseim-pgsql.toml +++ b/test/config_parser_SUITE_data/mongooseim-pgsql.toml @@ -307,7 +307,16 @@ [[host_config]] host = "anonymous.localhost" - [host_config.auth.anonymous] allow_multiple_connections = true protocol = "both" + [host_config.outgoing_pools.rdbms.special] + workers = 5 + connection.driver = "pgsql" + connection.host = "localhost" + connection.database = "mongooseim" + connection.username = "mongooseim" + connection.password = "mongooseim_secret" + connection.tls.required = true + connection.tls.cacertfile = "priv/ca.pem" + connection.tls.server_name_indication.enabled = false diff --git a/test/config_parser_SUITE_data/outgoing_pools.toml b/test/config_parser_SUITE_data/outgoing_pools.toml index fb51c8e7b5..0e4006565c 100644 --- a/test/config_parser_SUITE_data/outgoing_pools.toml +++ b/test/config_parser_SUITE_data/outgoing_pools.toml @@ -69,3 +69,8 @@ servers = ["ldap-server.example.com"] root_dn = "cn=admin,dc=example,dc=com" password = "ldap-admin-password" + +[[host_config]] + host = "localhost.bis" + [host_config.outgoing_pools.redis.global_distrib] + workers = 10 From 4ca0440f424f952661fc8f32907ce2641a50e2e7 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Tue, 5 Mar 2024 15:45:36 +0100 Subject: [PATCH 6/8] Remove single_host(_type) option in favour of host_config --- doc/configuration/Services.md | 2 +- doc/configuration/outgoing-connections.md | 3 --- src/config/mongoose_config_spec.erl | 10 +--------- test/common/config_parser_helper.erl | 10 +++------- test/config_parser_SUITE.erl | 4 ---- test/config_parser_SUITE_data/mongooseim-pgsql.toml | 10 +++++----- test/config_parser_SUITE_data/outgoing_pools.toml | 7 +------ 7 files changed, 11 insertions(+), 35 deletions(-) diff --git a/doc/configuration/Services.md b/doc/configuration/Services.md index a43b3afaa0..059e1a9cef 100644 --- a/doc/configuration/Services.md +++ b/doc/configuration/Services.md @@ -75,7 +75,7 @@ It is used to synchronise dynamic domains between nodes after starting. * **Example:** `db_pool = "my_host_type"` By default, this service uses the RDBMS connection pool configured with the scope `"global"`. -You can put a specific host type there to use the pool with the `"host"` or `"single_host"` scope for that particular host type. See the [outgoing connections docs](outgoing-connections.md) for more information about pool scopes. +You can put a specific host type there to use the `default` pool with the `host_type` scope for that particular host type. See the [outgoing connections docs](outgoing-connections.md) for more information about pool scopes. ### `services.service_domain_db.event_cleaning_interval` diff --git a/doc/configuration/outgoing-connections.md b/doc/configuration/outgoing-connections.md index 472a790f9a..e91f7d90ec 100644 --- a/doc/configuration/outgoing-connections.md +++ b/doc/configuration/outgoing-connections.md @@ -31,9 +31,6 @@ This allows you to create multiple dedicated pools of the same type. !!! Note The option `host` is still supported and behaves equivalent to `host_type`; however, it is deprecated in favour of the latter. - !!! Warning - The options `single_host` and `single_host_type` for the scope has been deprecated, in favour of configuring the specified pools within the [`host_config`](host_config.md) section. - ## Worker pool options All pools are managed by the [inaka/worker_pool](https://github.com/inaka/worker_pool) library. diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 6d03201ea0..00f804326f 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -494,7 +494,7 @@ outgoing_pool_extra(host_config, Type) -> process = fun ?MODULE:process_host_config_pool/2 }; outgoing_pool_extra(global_config, Type) -> - Scopes = [global, host_type, single_host_type, host, single_host], %% TODO deprecated + Scopes = [global, host_type, host], %% TODO deprecated #section{items = #{<<"scope">> => #option{type = atom, validate = {enum, Scopes}}, <<"host_type">> => #option{type = binary, @@ -1115,14 +1115,6 @@ process_host_config_pool([Tag, Type, _Pools, {host, HT} | _], AllOpts = #{connec opts => maps:remove(connection, AllOpts), conn_opts => Connection}. -pool_scope(single_host_type, none) -> - error(#{what => pool_single_host_type_not_specified, - text => <<"\"host_type\" option is required if \"single_host_type\" is used.">>}); -pool_scope(single_host, none) -> - error(#{what => pool_single_host_not_specified, - text => <<"\"host\" option is required if \"single_host\" is used.">>}); -pool_scope(single_host_type, HostType) -> HostType; -pool_scope(single_host, Host) -> Host; pool_scope(host, none) -> host_type; pool_scope(host_type, none) -> host_type; pool_scope(global, none) -> global. diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl index 7bdea9685e..903bd07bf8 100644 --- a/test/common/config_parser_helper.erl +++ b/test/common/config_parser_helper.erl @@ -248,9 +248,7 @@ options("mongooseim-pgsql") -> cacertfile => "priv/ca.pem", server_name_indication => #{enabled => false}} } - }, - #{type => redis, scope => <<"localhost">>, tag => global_distrib, - opts => #{workers => 10}, conn_opts => #{}} + } ])}, {rdbms_server_type, generic}, {registration_timeout, infinity}, @@ -365,15 +363,13 @@ options("outgoing_pools") -> cacertfile => "priv/ca.pem", server_name_indication => #{enabled => false}} } - }, - #{type => redis, scope => <<"localhost">>, tag => global_distrib, - opts => #{workers => 10}, conn_opts => #{}} + } ])}, {rdbms_server_type, generic}, {registration_timeout, 600}, {routing_modules, mongoose_router:default_routing_modules()}, {services, #{}}, - {{outgoing_pools, <<"localhost.bis">>}, + {{outgoing_pools, <<"localhost">>}, lists:map( fun host_pool_config/1, [#{type => redis, scope => <<"localhost">>, tag => global_distrib, diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 143b8a41f3..50c5f0e6b9 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -886,12 +886,8 @@ pool_scope(_Config) -> T = fun(Opts) -> pool_raw(<<"http">>, <<"default">>, maps:merge(Required, Opts)) end, ?cfg(P, host_type, T(#{<<"scope">> => <<"host">>})), ?cfg(P, host_type, T(#{<<"scope">> => <<"host_type">>})), - ?cfg(P, <<"localhost">>, T(#{<<"scope">> => <<"single_host">>, <<"host">> => <<"localhost">>})), - ?cfg(P, <<"localhost">>, T(#{<<"scope">> => <<"single_host_type">>, <<"host_type">> => <<"localhost">>})), ?err(T(#{<<"host">> => <<"localhost">>})), % missing scope ?err(T(#{<<"host_type">> => <<"localhost">>})), % missing scope - ?err(T(#{<<"scope">> => <<"single_host">>})), % missing host - ?err(T(#{<<"scope">> => <<"single_host_type">>})), % missing host type ?err(T(#{<<"scope">> => <<"whatever">>})). pool_rdbms(_Config) -> diff --git a/test/config_parser_SUITE_data/mongooseim-pgsql.toml b/test/config_parser_SUITE_data/mongooseim-pgsql.toml index 7ce51e1010..b4b6c926e6 100644 --- a/test/config_parser_SUITE_data/mongooseim-pgsql.toml +++ b/test/config_parser_SUITE_data/mongooseim-pgsql.toml @@ -131,11 +131,6 @@ [auth.rdbms] -[outgoing_pools.redis.global_distrib] - scope = "single_host" - host = "localhost" - workers = 10 - [outgoing_pools.rdbms.default] scope = "global" workers = 5 @@ -305,6 +300,11 @@ host = "fed1" ip_address = "127.0.0.1" +[[host_config]] + host = "localhost" + [host_config.outgoing_pools.redis.global_distrib] + workers = 10 + [[host_config]] host = "anonymous.localhost" [host_config.auth.anonymous] diff --git a/test/config_parser_SUITE_data/outgoing_pools.toml b/test/config_parser_SUITE_data/outgoing_pools.toml index 0e4006565c..2c4a98d140 100644 --- a/test/config_parser_SUITE_data/outgoing_pools.toml +++ b/test/config_parser_SUITE_data/outgoing_pools.toml @@ -6,11 +6,6 @@ ] default_server_domain = "localhost" -[outgoing_pools.redis.global_distrib] - scope = "single_host_type" - host = "localhost" - workers = 10 - [outgoing_pools.rdbms.default] scope = "global" workers = 5 @@ -71,6 +66,6 @@ password = "ldap-admin-password" [[host_config]] - host = "localhost.bis" + host = "localhost" [host_config.outgoing_pools.redis.global_distrib] workers = 10 From 075d95750f070d51a00e3fdf4be4e7952da0137b Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Wed, 6 Mar 2024 09:52:35 +0100 Subject: [PATCH 7/8] Expand pools taking new host_config ones --- src/wpool/mongoose_wpool.erl | 37 ++++++++++++++-------- test/auth_http_SUITE.erl | 2 +- test/ejabberd_sm_SUITE.erl | 2 +- test/http_client_SUITE.erl | 2 +- test/mongoose_wpool_SUITE.erl | 59 ++++++++++++++++++----------------- 5 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/wpool/mongoose_wpool.erl b/src/wpool/mongoose_wpool.erl index 9924b9207a..03fb1884b2 100644 --- a/src/wpool/mongoose_wpool.erl +++ b/src/wpool/mongoose_wpool.erl @@ -27,19 +27,20 @@ get_pool_settings/3, get_pools/0, stats/3]). -export([start_sup_pool/3]). --export([start_configured_pools/0, start_configured_pools/1, start_configured_pools/2]). +-export([start_configured_pools/0, start_configured_pools/1, + start_configured_pools/2, start_configured_pools/3]). -export([is_configured/1]). -export([make_pool_name/3]). -export([call_start_callback/2]). %% Mostly for tests --export([expand_pools/2]). +-export([expand_pools/3]). --ignore_xref([call/2, cast/2, cast/3, expand_pools/2, get_worker/2, +-ignore_xref([call/2, cast/2, cast/3, expand_pools/3, get_worker/2, send_request/2, send_request/3, send_request/4, send_request/5, is_configured/2, is_configured/1, is_configured/1, start/2, start/3, - start/5, start_configured_pools/1, start_configured_pools/2, stats/3, - stop/1, stop/2]). + start/5, start_configured_pools/1, start_configured_pools/2, start_configured_pools/3, + stats/3, stop/1, stop/2]). -type pool_type() :: redis | http | rdbms | cassandra | elastic | generic | rabbit | ldap. @@ -112,7 +113,11 @@ start_configured_pools(PoolsIn) -> start_configured_pools(PoolsIn, ?ALL_HOST_TYPES). start_configured_pools(PoolsIn, HostTypes) -> - Pools = expand_pools(PoolsIn, HostTypes), + HostTypeSpecific = get_host_type_specific_pools(HostTypes), + start_configured_pools(PoolsIn, HostTypeSpecific, HostTypes). + +start_configured_pools(PoolsIn, HostTypeSpecific, HostTypes) -> + Pools = expand_pools(PoolsIn, HostTypeSpecific, HostTypes), [call_callback(init, PoolType, []) || PoolType <- get_unique_types(PoolsIn)], [start(Pool) || Pool <- Pools]. @@ -348,19 +353,25 @@ make_callback_module_name(PoolType) -> Name = "mongoose_wpool_" ++ atom_to_list(PoolType), list_to_atom(Name). --spec expand_pools([pool_map_in()], [mongooseim:host_type()]) -> [pool_map()]. -expand_pools(Pools, HostTypes) -> - %% First we select only pools for a specific vhost - HostSpecific = [{Type, HT, Tag} || #{type := Type, scope := HT, tag := Tag} <- Pools, is_binary(HT)], - %% Then we expand all pools with `host_type` as HostType parameter but using host_type specific configs - %% if they were provided +-spec get_host_type_specific_pools([mongooseim:host_type()]) -> [pool_map_in()]. +get_host_type_specific_pools(HostTypes) -> + lists:append([ mongoose_config:get_opt({outgoing_pools, HostType}, []) + || HostType <- HostTypes ]). + +-spec expand_pools([pool_map_in()], [pool_map_in()], [mongooseim:host_type()]) -> [pool_map()]. +expand_pools(Pools, PerHostType, HostTypes) -> + %% First we select only vhost/host_type specific pools + HostSpecific = [ {Type, HT, Tag} + || #{type := Type, scope := HT, tag := Tag} <- PerHostType ], + %% Then we expand all pools with `host_type` as scope + %% but using host_type specific configs if they were provided F = fun(M = #{type := PoolType, scope := host_type, tag := Tag}) -> [M#{scope => HostType} || HostType <- HostTypes, not lists:member({PoolType, HostType, Tag}, HostSpecific)]; (Other) -> [Other] end, Pools1 = lists:flatmap(F, Pools), - lists:map(fun prepare_pool_map/1, Pools1). + lists:map(fun prepare_pool_map/1, PerHostType ++ Pools1). -spec prepare_pool_map(pool_map_in()) -> pool_map(). prepare_pool_map(Pool = #{scope := HT, opts := Opts}) -> diff --git a/test/auth_http_SUITE.erl b/test/auth_http_SUITE.erl index 7c8d910cc2..b1e0c4522a 100644 --- a/test/auth_http_SUITE.erl +++ b/test/auth_http_SUITE.erl @@ -77,7 +77,7 @@ init_per_suite(Config) -> % This would be started via outgoing_pools in normal case Pool = config([outgoing_pools, http, auth], pool_opts()), HostTypes = [?HOST_TYPE, <<"another host type">>], - mongoose_wpool:start_configured_pools([Pool], HostTypes), + mongoose_wpool:start_configured_pools([Pool], [], HostTypes), mongoose_wpool_http:init(), ejabberd_auth_http:start(?HOST_TYPE) end), diff --git a/test/ejabberd_sm_SUITE.erl b/test/ejabberd_sm_SUITE.erl index f8f3886607..976ed1865c 100644 --- a/test/ejabberd_sm_SUITE.erl +++ b/test/ejabberd_sm_SUITE.erl @@ -78,7 +78,7 @@ init_redis_group(true, Config) -> mongoose_wpool:ensure_started(), % This would be started via outgoing_pools in normal case Pool = default_config([outgoing_pools, redis, default]), - mongoose_wpool:start_configured_pools([Pool], []), + mongoose_wpool:start_configured_pools([Pool], [], []), Self ! ready, receive stop -> ok end end), diff --git a/test/http_client_SUITE.erl b/test/http_client_SUITE.erl index 5c1d030e83..0fd7b5dd56 100644 --- a/test/http_client_SUITE.erl +++ b/test/http_client_SUITE.erl @@ -57,7 +57,7 @@ end_per_suite(_Config) -> init_per_testcase(TC, Config) -> Pool = config([outgoing_pools, http, pool()], pool_opts(TC)), - mongoose_wpool:start_configured_pools([Pool], [<<"a.com">>]), + mongoose_wpool:start_configured_pools([Pool], [], [<<"a.com">>]), Config. pool_opts(request_timeout_test) -> diff --git a/test/mongoose_wpool_SUITE.erl b/test/mongoose_wpool_SUITE.erl index c4c4fa9835..b0cf5e617f 100644 --- a/test/mongoose_wpool_SUITE.erl +++ b/test/mongoose_wpool_SUITE.erl @@ -137,37 +137,40 @@ generic_pools_are_started_for_all_vhosts(_C) -> ordsets:from_list(mongoose_wpool:get_pools())). host_specific_pools_are_preserved(_C) -> - Pools = [#{type => generic, scope => host_type, tag => default, opts => #{}, conn_opts => #{}}, - #{type => generic, scope => <<"b.com">>, tag => default, - opts => #{workers => 12}, conn_opts => #{}}], - Expanded = mongoose_wpool:expand_pools(Pools, [<<"a.com">>, <<"b.com">>, <<"c.eu">>]), - ?assertMatch([#{type := generic, host_type := <<"a.com">>, tag := default, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"c.eu">>, tag := default, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"b.com">>, tag := default, - opts := [{workers, 12}], conn_opts := #{}}], - Expanded). + Pools = [#{type => generic, scope => host_type, tag => default, opts => #{}, conn_opts => #{}}], + HostSpecific = [#{type => generic, scope => <<"b.com">>, tag => default, + opts => #{workers => 12}, conn_opts => #{}}], + Expanded = mongoose_wpool:expand_pools( + Pools, HostSpecific, [<<"a.com">>, <<"b.com">>, <<"c.eu">>]), + Expected = lists:sort([#{type => generic, host_type => <<"a.com">>, tag => default, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"c.eu">>, tag => default, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"b.com">>, tag => default, + opts => [{workers, 12}], conn_opts => #{}}]), + ?assertMatch(Expected, lists:sort(Expanded)). pools_for_different_tag_are_expanded_with_host_specific_config_preserved(_C) -> Pools = [#{type => generic, scope => host_type, tag => default, opts => #{}, conn_opts => #{}}, - #{type => generic, scope => <<"b.com">>, tag => default, - opts => #{workers => 12}, conn_opts => #{}}, - #{type => generic, scope => host_type, tag => other_tag, opts => #{}, conn_opts => #{}}], - Expanded = mongoose_wpool:expand_pools(Pools, [<<"a.com">>, <<"b.com">>, <<"c.eu">>]), - ?assertMatch([#{type := generic, host_type := <<"a.com">>, tag := default, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"c.eu">>, tag := default, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"b.com">>, tag := default, - opts := [{workers, 12}], conn_opts := #{}}, - #{type := generic, host_type := <<"a.com">>, tag := other_tag, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"b.com">>, tag := other_tag, - opts := [], conn_opts := #{}}, - #{type := generic, host_type := <<"c.eu">>, tag := other_tag, - opts := [], conn_opts := #{}}], - Expanded). + #{type => generic, scope => host_type, tag => other_tag, + opts => #{}, conn_opts => #{}}], + HostSpecific = [#{type => generic, scope => <<"b.com">>, tag => default, + opts => #{workers => 12}, conn_opts => #{}}], + Expanded = mongoose_wpool:expand_pools( + Pools, HostSpecific, [<<"a.com">>, <<"b.com">>, <<"c.eu">>]), + Expected = lists:sort([#{type => generic, host_type => <<"a.com">>, tag => default, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"c.eu">>, tag => default, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"b.com">>, tag => default, + opts => [{workers, 12}], conn_opts => #{}}, + #{type => generic, host_type => <<"a.com">>, tag => other_tag, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"b.com">>, tag => other_tag, + opts => [], conn_opts => #{}}, + #{type => generic, host_type => <<"c.eu">>, tag => other_tag, + opts => [], conn_opts => #{}}]), + ?assertMatch(Expected, lists:sort(Expanded)). global_pool_is_used_by_default(_C) -> Pools = [#{type => generic, scope => global, tag => default, opts => #{}, conn_opts => #{}}, From daf4c017adfd2f7e90a08af7f1c745575c208d99 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Thu, 7 Mar 2024 15:40:15 +0100 Subject: [PATCH 8/8] Apply review comments --- src/config/mongoose_config_spec.erl | 27 ++++++++------------------- src/wpool/mongoose_wpool.erl | 8 ++++---- test/common/config_parser_helper.erl | 21 +++++++++------------ test/config_parser_SUITE.erl | 7 ++++--- 4 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/config/mongoose_config_spec.erl b/src/config/mongoose_config_spec.erl index 00f804326f..24e2132dee 100644 --- a/src/config/mongoose_config_spec.erl +++ b/src/config/mongoose_config_spec.erl @@ -92,7 +92,7 @@ root() -> defaults = general_defaults()}, <<"listen">> => Listen#section{include = always}, <<"auth">> => Auth#section{include = always}, - <<"outgoing_pools">> => outgoing_pools(), + <<"outgoing_pools">> => outgoing_pools(global_config), <<"internal_databases">> => internal_databases(), <<"services">> => services(), <<"modules">> => Modules#section{include = always}, @@ -137,7 +137,7 @@ host_config() -> <<"general">> => general(), <<"auth">> => auth(), <<"modules">> => modules(), - <<"outgoing_pools">> => host_config_outgoing_pools(), + <<"outgoing_pools">> => outgoing_pools(host_config), <<"acl">> => acl(), <<"access">> => access(), <<"s2s">> => s2s() @@ -439,13 +439,7 @@ internal_database_mnesia() -> #section{}. %% path: outgoing_pools -outgoing_pools() -> - outgoing_pools(global_config). - %% path: (host_config[].)outgoing_pools -host_config_outgoing_pools() -> - outgoing_pools(host_config). - outgoing_pools(Scope) -> PoolTypes = [<<"cassandra">>, <<"elastic">>, <<"http">>, <<"ldap">>, <<"rabbit">>, <<"rdbms">>, <<"redis">>], @@ -494,13 +488,8 @@ outgoing_pool_extra(host_config, Type) -> process = fun ?MODULE:process_host_config_pool/2 }; outgoing_pool_extra(global_config, Type) -> - Scopes = [global, host_type, host], %% TODO deprecated - #section{items = #{<<"scope">> => #option{type = atom, - validate = {enum, Scopes}}, - <<"host_type">> => #option{type = binary, - validate = non_empty}, - <<"host">> => #option{type = binary, %% TODO deprecated - validate = non_empty}, + Scopes = [global, host_type, host], %% TODO host is deprecated + #section{items = #{<<"scope">> => #option{type = atom, validate = {enum, Scopes}}, <<"connection">> => outgoing_pool_connection(Type) }, process = fun ?MODULE:process_pool/2, @@ -1100,7 +1089,7 @@ check_auth_method(Method, Opts) -> end. process_pool([Tag, Type | _], AllOpts = #{scope := ScopeIn, connection := Connection}) -> - Scope = pool_scope(ScopeIn, maps:get(host_type, AllOpts, maps:get(host, AllOpts, none))), + Scope = pool_scope(ScopeIn), Opts = maps:without([scope, host, connection], AllOpts), #{type => b2a(Type), scope => Scope, @@ -1115,9 +1104,9 @@ process_host_config_pool([Tag, Type, _Pools, {host, HT} | _], AllOpts = #{connec opts => maps:remove(connection, AllOpts), conn_opts => Connection}. -pool_scope(host, none) -> host_type; -pool_scope(host_type, none) -> host_type; -pool_scope(global, none) -> global. +pool_scope(host) -> host_type; +pool_scope(host_type) -> host_type; +pool_scope(global) -> global. process_ldap_connection(ConnOpts = #{port := _}) -> ConnOpts; process_ldap_connection(ConnOpts = #{tls := _}) -> ConnOpts#{port => 636}; diff --git a/src/wpool/mongoose_wpool.erl b/src/wpool/mongoose_wpool.erl index 03fb1884b2..1ffd6d5192 100644 --- a/src/wpool/mongoose_wpool.erl +++ b/src/wpool/mongoose_wpool.erl @@ -118,7 +118,7 @@ start_configured_pools(PoolsIn, HostTypes) -> start_configured_pools(PoolsIn, HostTypeSpecific, HostTypes) -> Pools = expand_pools(PoolsIn, HostTypeSpecific, HostTypes), - [call_callback(init, PoolType, []) || PoolType <- get_unique_types(PoolsIn)], + [call_callback(init, PoolType, []) || PoolType <- get_unique_types(PoolsIn, HostTypeSpecific)], [start(Pool) || Pool <- Pools]. -spec start(pool_map()) -> start_result(). @@ -379,9 +379,9 @@ prepare_pool_map(Pool = #{scope := HT, opts := Opts}) -> Pool1 = maps:remove(scope, Pool), Pool1#{host_type => HT, opts => maps:to_list(Opts)}. --spec get_unique_types([pool_map_in()]) -> [pool_type()]. -get_unique_types(Pools) -> - lists:usort([maps:get(type, Pool) || Pool <- Pools]). +-spec get_unique_types([pool_map_in()], [pool_map_in()]) -> [pool_type()]. +get_unique_types(Pools, HostTypeSpecific) -> + lists:usort([maps:get(type, Pool) || Pool <- Pools ++ HostTypeSpecific]). -spec get_pool(pool_type(), host_type_or_global(), tag()) -> pool_record_result(). get_pool(PoolType, HostType, Tag) -> diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl index 903bd07bf8..a3ba384f6d 100644 --- a/test/common/config_parser_helper.erl +++ b/test/common/config_parser_helper.erl @@ -261,9 +261,8 @@ options("mongooseim-pgsql") -> {component_backend, mnesia}, {s2s_backend, mnesia}, {{outgoing_pools, <<"anonymous.localhost">>}, - lists:map( - fun host_pool_config/1, - [#{tag => special, + [host_pool_config( + #{tag => special, scope => <<"anonymous.localhost">>, type => rdbms, opts => #{workers => 5}, @@ -274,7 +273,7 @@ options("mongooseim-pgsql") -> server_name_indication => #{enabled => false}} } } - ])}, + )]}, {{auth, <<"anonymous.localhost">>}, (default_auth())#{anonymous => #{backend => mnesia, allow_multiple_connections => true, @@ -299,10 +298,9 @@ options("mongooseim-pgsql") -> {{replaced_wait_timeout, <<"localhost">>}, 2000}, {{replaced_wait_timeout, <<"localhost.bis">>}, 2000}, {{outgoing_pools, <<"localhost">>}, - lists:map( - fun host_pool_config/1, - [#{type => redis, scope => <<"localhost">>, tag => global_distrib, - opts => #{workers => 10}, conn_opts => #{}}])}, + [host_pool_config( + #{type => redis, scope => <<"localhost">>, tag => global_distrib, + opts => #{workers => 10}, conn_opts => #{}})]}, {{s2s, <<"anonymous.localhost">>}, pgsql_s2s()}, {{s2s, <<"localhost">>}, pgsql_s2s()}, {{s2s, <<"localhost.bis">>}, pgsql_s2s()}, @@ -370,10 +368,9 @@ options("outgoing_pools") -> {routing_modules, mongoose_router:default_routing_modules()}, {services, #{}}, {{outgoing_pools, <<"localhost">>}, - lists:map( - fun host_pool_config/1, - [#{type => redis, scope => <<"localhost">>, tag => global_distrib, - opts => #{workers => 10}, conn_opts => #{}}])}, + [host_pool_config( + #{type => redis, scope => <<"localhost">>, tag => global_distrib, + opts => #{workers => 10}, conn_opts => #{}})]}, {{s2s, <<"anonymous.localhost">>}, default_s2s()}, {{s2s, <<"localhost">>}, default_s2s()}, {{s2s, <<"localhost.bis">>}, default_s2s()}, diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl index 50c5f0e6b9..9d3b0c33da 100644 --- a/test/config_parser_SUITE.erl +++ b/test/config_parser_SUITE.erl @@ -877,6 +877,8 @@ pool_basics(_Config) -> Required = #{<<"connection">> => #{<<"host">> => <<"http://localhost">>}}, ?cfg(P ++ [type], http, pool_raw(<<"http">>, <<"default">>, Required)), ?cfg(P ++ [tag], default, pool_raw(<<"http">>, <<"default">>, Required)), + ?cfg(host_opts([{P ++ [tag], default}]), + host_config(pool_raw(<<"http">>, <<"default">>, Required))), ?err(pool_raw(<<"swimming_pool">>, <<"default">>, Required)), ?err(pool_raw(<<"http">>, 1000, Required)). @@ -886,9 +888,8 @@ pool_scope(_Config) -> T = fun(Opts) -> pool_raw(<<"http">>, <<"default">>, maps:merge(Required, Opts)) end, ?cfg(P, host_type, T(#{<<"scope">> => <<"host">>})), ?cfg(P, host_type, T(#{<<"scope">> => <<"host_type">>})), - ?err(T(#{<<"host">> => <<"localhost">>})), % missing scope - ?err(T(#{<<"host_type">> => <<"localhost">>})), % missing scope - ?err(T(#{<<"scope">> => <<"whatever">>})). + ?err(T(#{<<"scope">> => <<"whatever">>})), + ?err(host_config(T(#{<<"scope">> => <<"global">>}))). %% scope is not allowed in host_config pool_rdbms(_Config) -> test_pool_opts(rdbms, #{<<"connection">> => raw_sql_opts(pgsql)}).