diff options
| author | Michael Klishin <mklishin@pivotal.io> | 2019-11-19 02:27:21 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-19 02:27:21 +0300 |
| commit | e5f2dfafce3b5c75b11fb76b7ddf464c5358ad41 (patch) | |
| tree | ac554e45cefb5c31cb43d959c5ceaf203ce6681e | |
| parent | 880965aa67009dc3fb8dc161b8b1b6df6a71ed9d (diff) | |
| parent | 8f085a3ec546137ca7c5d2adc43cfb12f86af294 (diff) | |
| download | rabbitmq-server-git-e5f2dfafce3b5c75b11fb76b7ddf464c5358ad41.tar.gz | |
Merge pull request #2160 from rabbitmq/rabbitmq-management-749
Extract rabbit_definitions from rabbitmq-management
24 files changed, 2545 insertions, 27 deletions
@@ -133,7 +133,7 @@ define PROJECT_ENV ] endef -LOCAL_DEPS = sasl mnesia os_mon inets compiler public_key crypto ssl syntax_tools +LOCAL_DEPS = sasl mnesia os_mon inets compiler public_key crypto ssl syntax_tools xmerl BUILD_DEPS = rabbitmq_cli syslog DEPS = ranch lager rabbit_common ra sysmon_handler stdout_formatter recon observer_cli TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client meck proper diff --git a/priv/schema/rabbit.schema b/priv/schema/rabbit.schema index e05623ae78..2054a48ccf 100644 --- a/priv/schema/rabbit.schema +++ b/priv/schema/rabbit.schema @@ -73,7 +73,7 @@ end}. ]}. -%% Maximum time for AMQP 0-8/0-9/0-9-1 handshake (after socket connection +%% Maximum time for 0-9-1 handshake (after socket connection %% and SSL handshake), in milliseconds. %% %% {handshake_timeout, 10000}, @@ -98,6 +98,19 @@ end}. ]}. %% +%% Definition import +%% + +%% Load definitions from a JSON file or directory of files. See +%% https://www.rabbitmq.com/management.html#load-definitions +%% +%% {load_definitions, "/path/to/schema.json"}, +%% {load_definitions, "/path/to/schemas"}, +{mapping, "load_definitions", "rabbit.load_definitions", + [{datatype, string}, + {validators, ["file_accessible"]}]}. + +%% %% Security / AAA %% ============== %% @@ -1631,7 +1644,7 @@ fun(Dir) -> Res end}. -{validator, "file_accessible", "file doesn/t exist or isn't readable", +{validator, "file_accessible", "file doesn't exist or isn't readable", fun(File) -> ReadFile = file:read_file_info(File), element(1, ReadFile) == ok diff --git a/src/rabbit.erl b/src/rabbit.erl index 87ceb5d701..e4d2ee9808 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -187,6 +187,15 @@ {requires, [core_initialized]}, {enables, routing_ready}]}). +%% We want to A) make sure we apply definitions before the node begins serving +%% traffic and B) in fact do it before empty_db_check (so the defaults will not +%% get created if we don't need 'em). +-rabbit_boot_step({load_core_definitions, + [{description, "imports definitions"}, + {mfa, {rabbit_definitions, maybe_load_definitions, []}}, + {requires, recovery}, + {enables, empty_db_check}]}). + -rabbit_boot_step({empty_db_check, [{description, "empty DB check"}, {mfa, {?MODULE, maybe_insert_default_data, []}}, diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl index e675ad188b..09392bf7b8 100644 --- a/src/rabbit_auth_backend_internal.erl +++ b/src/rabbit_auth_backend_internal.erl @@ -28,7 +28,7 @@ hash_password/2, change_password_hash/2, change_password_hash/3, set_tags/3, set_permissions/6, clear_permissions/3, set_topic_permissions/6, clear_topic_permissions/3, clear_topic_permissions/4, - add_user_sans_validation/3]). + add_user_sans_validation/3, put_user/2, put_user/3]). -export([user_info_keys/0, perms_info_keys/0, user_perms_info_keys/0, vhost_perms_info_keys/0, @@ -471,6 +471,138 @@ clear_topic_permissions(Username, VHostPath, Exchange, ActingUser) -> {user_who_performed_action, ActingUser}]), R. +put_user(User, ActingUser) -> put_user(User, undefined, ActingUser). + +put_user(User, Version, ActingUser) -> + Username = maps:get(name, User), + HasPassword = maps:is_key(password, User), + HasPasswordHash = maps:is_key(password_hash, User), + Password = maps:get(password, User, undefined), + PasswordHash = maps:get(password_hash, User, undefined), + + Tags = case {maps:get(tags, User, undefined), maps:get(administrator, User, undefined)} of + {undefined, undefined} -> + throw({error, tags_not_present}); + {undefined, AdminS} -> + case rabbit_mgmt_util:parse_bool(AdminS) of + true -> [administrator]; + false -> [] + end; + {TagsS, _} -> + [list_to_atom(string:strip(T)) || + T <- string:tokens(binary_to_list(TagsS), ",")] + end, + + UserExists = case rabbit_auth_backend_internal:lookup_user(Username) of + %% expected + {error, not_found} -> false; + %% shouldn't normally happen but worth guarding + %% against + {error, _} -> false; + _ -> true + end, + + %% pre-configured, only applies to newly created users + Permissions = maps:get(permissions, User, undefined), + + PassedCredentialValidation = + case {HasPassword, HasPasswordHash} of + {true, false} -> + rabbit_credential_validation:validate(Username, Password) =:= ok; + {false, true} -> true; + _ -> + rabbit_credential_validation:validate(Username, Password) =:= ok + end, + + case UserExists of + true -> + case {HasPassword, HasPasswordHash} of + {true, false} -> + update_user_password(PassedCredentialValidation, Username, Password, Tags, ActingUser); + {false, true} -> + update_user_password_hash(Username, PasswordHash, Tags, User, Version, ActingUser); + {true, true} -> + throw({error, both_password_and_password_hash_are_provided}); + %% clear password, update tags if needed + _ -> + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser), + rabbit_auth_backend_internal:clear_password(Username, ActingUser) + end; + false -> + case {HasPassword, HasPasswordHash} of + {true, false} -> + create_user_with_password(PassedCredentialValidation, Username, Password, Tags, Permissions, ActingUser); + {false, true} -> + create_user_with_password_hash(Username, PasswordHash, Tags, User, Version, Permissions, ActingUser); + {true, true} -> + throw({error, both_password_and_password_hash_are_provided}); + {false, false} -> + %% this user won't be able to sign in using + %% a username/password pair but can be used for x509 certificate authentication, + %% with authn backends such as HTTP or LDAP and so on. + create_user_with_password(PassedCredentialValidation, Username, <<"">>, Tags, Permissions, ActingUser) + end + end. + +update_user_password(_PassedCredentialValidation = true, Username, Password, Tags, ActingUser) -> + rabbit_auth_backend_internal:change_password(Username, Password, ActingUser), + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser); +update_user_password(_PassedCredentialValidation = false, _Username, _Password, _Tags, _ActingUser) -> + %% we don't log here because + %% rabbit_auth_backend_internal will do it + throw({error, credential_validation_failed}). + +update_user_password_hash(Username, PasswordHash, Tags, User, Version, ActingUser) -> + %% when a hash this provided, credential validation + %% is not applied + HashingAlgorithm = hashing_algorithm(User, Version), + + Hash = rabbit_misc:b64decode_or_throw(PasswordHash), + rabbit_auth_backend_internal:change_password_hash( + Username, Hash, HashingAlgorithm), + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser). + +create_user_with_password(_PassedCredentialValidation = true, Username, Password, Tags, undefined, ActingUser) -> + rabbit_auth_backend_internal:add_user(Username, Password, ActingUser), + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser); +create_user_with_password(_PassedCredentialValidation = true, Username, Password, Tags, PreconfiguredPermissions, ActingUser) -> + rabbit_auth_backend_internal:add_user(Username, Password, ActingUser), + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser), + preconfigure_permissions(Username, PreconfiguredPermissions, ActingUser); +create_user_with_password(_PassedCredentialValidation = false, _Username, _Password, _Tags, _, _) -> + %% we don't log here because + %% rabbit_auth_backend_internal will do it + throw({error, credential_validation_failed}). + +create_user_with_password_hash(Username, PasswordHash, Tags, User, Version, PreconfiguredPermissions, ActingUser) -> + %% when a hash this provided, credential validation + %% is not applied + HashingAlgorithm = hashing_algorithm(User, Version), + Hash = rabbit_misc:b64decode_or_throw(PasswordHash), + + %% first we create a user with dummy credentials and no + %% validation applied, then we update password hash + TmpPassword = rabbit_guid:binary(rabbit_guid:gen_secure(), "tmp"), + rabbit_auth_backend_internal:add_user_sans_validation(Username, TmpPassword, ActingUser), + + rabbit_auth_backend_internal:change_password_hash( + Username, Hash, HashingAlgorithm), + rabbit_auth_backend_internal:set_tags(Username, Tags, ActingUser), + preconfigure_permissions(Username, PreconfiguredPermissions, ActingUser). + +preconfigure_permissions(_Username, undefined, _ActingUser) -> + ok; +preconfigure_permissions(Username, Map, ActingUser) when is_map(Map) -> + maps:map(fun(VHost, M) -> + rabbit_auth_backend_internal:set_permissions(Username, VHost, + maps:get(<<"configure">>, M), + maps:get(<<"write">>, M), + maps:get(<<"read">>, M), + ActingUser) + end, + Map), + ok. + %%---------------------------------------------------------------------------- %% Listing @@ -649,3 +781,21 @@ extract_topic_permission_params(Keys, #topic_permission{ {exchange, Exchange}, {write, WritePerm}, {read, ReadPerm}]). + +hashing_algorithm(User, Version) -> + case maps:get(hashing_algorithm, User, undefined) of + undefined -> + case Version of + %% 3.6.1 and later versions are supposed to have + %% the algorithm exported and thus not need a default + <<"3.6.0">> -> rabbit_password_hashing_sha256; + <<"3.5.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.4.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.3.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.2.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.1.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.0.", _/binary>> -> rabbit_password_hashing_md5; + _ -> rabbit_password:hashing_mod() + end; + Alg -> rabbit_data_coercion:to_atom(Alg, utf8) + end. diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl index 94b8870192..881374a4aa 100644 --- a/src/rabbit_binding.erl +++ b/src/rabbit_binding.erl @@ -18,9 +18,9 @@ -include_lib("rabbit_common/include/rabbit.hrl"). -include("amqqueue.hrl"). --export([recover/0, recover/2, exists/1, add/2, add/3, remove/1, remove/3, list/1]). --export([list_for_source/1, list_for_destination/1, - list_for_source_and_destination/2]). +-export([recover/0, recover/2, exists/1, add/2, add/3, remove/1, remove/3]). +-export([list/1, list_for_source/1, list_for_destination/1, + list_for_source_and_destination/2, list_explicit/0]). -export([new_deletions/0, combine_deletions/2, add_deletion/3, process_deletions/2]). -export([info_keys/0, info/1, info/2, info_all/1, info_all/2, info_all/4]). @@ -236,6 +236,20 @@ remove_default_exchange_binding_rows_of(Dst = #resource{}) -> end, ok. +-spec list_explicit() -> bindings(). + +list_explicit() -> + mnesia:async_dirty( + fun () -> + AllRoutes = mnesia:dirty_match_object(rabbit_route, #route{_ = '_'}), + %% if there are any default exchange bindings left after an upgrade + %% of a pre-3.8 database, filter them out + AllBindings = [B || #route{binding = B} <- AllRoutes], + lists:filter(fun(#binding{source = S}) -> + not (S#resource.kind =:= exchange andalso S#resource.name =:= <<>>) + end, AllBindings) + end). + -spec list(rabbit_types:vhost()) -> bindings(). list(VHostPath) -> diff --git a/src/rabbit_definitions.erl b/src/rabbit_definitions.erl new file mode 100644 index 0000000000..260284d19c --- /dev/null +++ b/src/rabbit_definitions.erl @@ -0,0 +1,674 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_definitions). +-include_lib("rabbit_common/include/rabbit.hrl"). + +%% automatic import on boot +-export([maybe_load_definitions/0, maybe_load_definitions_from/2]). +%% import +-export([import_raw/1, import_raw/2, import_parsed/1, import_parsed/2, + apply_defs/2, apply_defs/3, apply_defs/4, apply_defs/5]). +%% export +-export([all_definitions/0]). +-export([decode/1, decode/2, args/1]). + +-import(rabbit_misc, [pget/2]). + +%% +%% API +%% + +maybe_load_definitions() -> + %% this feature was a part of rabbitmq-management for a long time, + %% so we check rabbit_management.load_definitions for backward compatibility. + maybe_load_management_definitions(), + %% this backs "core" load_definitions + maybe_load_core_definitions(). + +maybe_load_core_definitions() -> + maybe_load_definitions(rabbit, load_definitions). + +maybe_load_management_definitions() -> + maybe_load_definitions(rabbitmq_management, load_definitions). + +-spec import_raw(Body :: binary() | iolist()) -> ok | {error, term()}. +import_raw(Body) -> + rabbit_log:info("Asked to import definitions. Acting user: ~s", [?INTERNAL_USER]), + case decode([], Body) of + {error, E} -> {error, E}; + {ok, _, Map} -> apply_defs(Map, ?INTERNAL_USER) + end. + +-spec import_raw(Body :: binary() | iolist(), VHost :: vhost:name()) -> ok | {error, term()}. +import_raw(Body, VHost) -> + rabbit_log:info("Asked to import definitions. Acting user: ~s", [?INTERNAL_USER]), + case decode([], Body) of + {error, E} -> {error, E}; + {ok, _, Map} -> apply_defs(Map, ?INTERNAL_USER, fun() -> ok end, VHost) + end. + +-spec import_parsed(Defs :: #{any() => any()} | list()) -> ok | {error, term()}. +import_parsed(Body0) when is_list(Body0) -> + import_parsed(maps:from_list(Body0)); +import_parsed(Body0) when is_map(Body0) -> + rabbit_log:info("Asked to import definitions. Acting user: ~s", [?INTERNAL_USER]), + Body = atomise_map_keys(Body0), + apply_defs(Body, ?INTERNAL_USER). + +-spec import_parsed(Defs :: #{any() => any() | list()}, VHost :: vhost:name()) -> ok | {error, term()}. +import_parsed(Body0, VHost) when is_list(Body0) -> + import_parsed(maps:from_list(Body0), VHost); +import_parsed(Body0, VHost) -> + rabbit_log:info("Asked to import definitions. Acting user: ~s", [?INTERNAL_USER]), + Body = atomise_map_keys(Body0), + apply_defs(Body, ?INTERNAL_USER, fun() -> ok end, VHost). + +-spec all_definitions() -> map(). +all_definitions() -> + Xs = list_exchanges(), + Qs = list_queues(), + Bs = list_bindings(), + + Users = list_users(), + VHosts = list_vhosts(), + Params = list_runtime_parameters(), + GParams = list_global_runtime_parameters(), + Pols = list_policies(), + + Perms = list_permissions(), + TPerms = list_topic_permissions(), + + {ok, Vsn} = application:get_key(rabbit, vsn), + #{ + rabbit_version => rabbit_data_coercion:to_binary(Vsn), + rabbitmq_version => rabbit_data_coercion:to_binary(Vsn), + users => Users, + vhosts => VHosts, + permissions => Perms, + topic_permissions => TPerms, + parameters => Params, + global_parameters => GParams, + policies => Pols, + queues => Qs, + bindings => Bs, + exchanges => Xs + }. + +%% +%% Implementation +%% + +maybe_load_definitions(App, Key) -> + case application:get_env(App, Key) of + undefined -> ok; + {ok, none} -> ok; + {ok, FileOrDir} -> + IsDir = filelib:is_dir(FileOrDir), + maybe_load_definitions_from(IsDir, FileOrDir) + end. + +maybe_load_definitions_from(true, Dir) -> + rabbit_log:info("Applying definitions from directory ~s", [Dir]), + load_definitions_from_files(file:list_dir(Dir), Dir); +maybe_load_definitions_from(false, File) -> + load_definitions_from_file(File). + +load_definitions_from_files({ok, Filenames0}, Dir) -> + Filenames1 = lists:sort(Filenames0), + Filenames2 = [filename:join(Dir, F) || F <- Filenames1], + load_definitions_from_filenames(Filenames2); +load_definitions_from_files({error, E}, Dir) -> + rabbit_log:error("Could not read definitions from directory ~s, Error: ~p", [Dir, E]), + {error, {could_not_read_defs, E}}. + +load_definitions_from_filenames([]) -> + ok; +load_definitions_from_filenames([File|Rest]) -> + case load_definitions_from_file(File) of + ok -> load_definitions_from_filenames(Rest); + {error, E} -> {error, {failed_to_import_definitions, File, E}} + end. + +load_definitions_from_file(File) -> + case file:read_file(File) of + {ok, Body} -> + rabbit_log:info("Applying definitions from ~s", [File]), + import_raw(Body); + {error, E} -> + rabbit_log:error("Could not read definitions from ~s, Error: ~p", [File, E]), + {error, {could_not_read_defs, {File, E}}} + end. + +decode(Keys, Body) -> + case decode(Body) of + {ok, J0} -> + J = maps:fold(fun(K, V, Acc) -> + Acc#{rabbit_data_coercion:to_atom(K, utf8) => V} + end, J0, J0), + Results = [get_or_missing(K, J) || K <- Keys], + case [E || E = {key_missing, _} <- Results] of + [] -> {ok, Results, J}; + Errors -> {error, Errors} + end; + Else -> Else + end. + +decode(<<"">>) -> + {ok, #{}}; +decode(Body) -> + try + Decoded = rabbit_json:decode(Body), + Normalised = atomise_map_keys(Decoded), + {ok, Normalised} + catch error:_ -> {error, not_json} + end. + +atomise_map_keys(Decoded) -> + maps:fold(fun(K, V, Acc) -> + Acc#{rabbit_data_coercion:to_atom(K, utf8) => V} + end, Decoded, Decoded). + +-spec apply_defs(Map :: #{atom() => any()}, ActingUser :: rabbit_types:username()) -> 'ok'. + +apply_defs(Map, ActingUser) -> + apply_defs(Map, ActingUser, fun () -> ok end). + +-spec apply_defs(Map :: #{atom() => any()}, ActingUser :: rabbit_types:username(), + SuccessFun :: fun(() -> 'ok')) -> 'ok'; + (Map :: #{atom() => any()}, ActingUser :: rabbit_types:username(), + VHost :: vhost:name()) -> 'ok'. + +apply_defs(Map, ActingUser, VHost) when is_binary(VHost) -> + apply_defs(Map, ActingUser, fun () -> ok end, VHost); + +apply_defs(Map, ActingUser, SuccessFun) when is_function(SuccessFun) -> + Version = maps:get(rabbitmq_version, Map, maps:get(rabbit_version, Map, undefined)), + try + rabbit_log:info("Importing users..."), + for_all(users, ActingUser, Map, + fun(User, _Username) -> + rabbit_auth_backend_internal:put_user(User, Version, ActingUser) + end), + rabbit_log:info("Importing vhosts..."), + for_all(vhosts, ActingUser, Map, fun add_vhost/2), + validate_limits(Map), + rabbit_log:info("Importing user permissions..."), + for_all(permissions, ActingUser, Map, fun add_permission/2), + rabbit_log:info("Importing topic permissions..."), + for_all(topic_permissions, ActingUser, Map, fun add_topic_permission/2), + rabbit_log:info("Importing parameters..."), + for_all(parameters, ActingUser, Map, fun add_parameter/2), + rabbit_log:info("Importing global parameters..."), + for_all(global_parameters, ActingUser, Map, fun add_global_parameter/2), + rabbit_log:info("Importing policies..."), + for_all(policies, ActingUser, Map, fun add_policy/2), + rabbit_log:info("Importing queues..."), + for_all(queues, ActingUser, Map, fun add_queue/2), + rabbit_log:info("Importing exchanges..."), + for_all(exchanges, ActingUser, Map, fun add_exchange/2), + rabbit_log:info("Importing bindings..."), + for_all(bindings, ActingUser, Map, fun add_binding/2), + SuccessFun(), + ok + catch {error, E} -> {error, E}; + exit:E -> {error, E} + end. + +-spec apply_defs(Map :: #{atom() => any()}, + ActingUser :: rabbit_types:username(), + SuccessFun :: fun(() -> 'ok'), + VHost :: vhost:name()) -> 'ok'. + +apply_defs(Map, ActingUser, SuccessFun, VHost) when is_binary(VHost) -> + rabbit_log:info("Asked to import definitions for a virtual host. Virtual host: ~p, acting user: ~p", + [VHost, ActingUser]), + try + validate_limits(Map, VHost), + rabbit_log:info("Importing parameters..."), + for_all(parameters, ActingUser, Map, VHost, fun add_parameter/3), + rabbit_log:info("Importing policies..."), + for_all(policies, ActingUser, Map, VHost, fun add_policy/3), + rabbit_log:info("Importing queues..."), + for_all(queues, ActingUser, Map, VHost, fun add_queue/3), + rabbit_log:info("Importing exchanges..."), + for_all(exchanges, ActingUser, Map, VHost, fun add_exchange/3), + rabbit_log:info("Importing bindings..."), + for_all(bindings, ActingUser, Map, VHost, fun add_binding/3), + SuccessFun() + catch {error, E} -> {error, format(E)}; + exit:E -> {error, format(E)} + end. + +-spec apply_defs(Map :: #{atom() => any()}, + ActingUser :: rabbit_types:username(), + SuccessFun :: fun(() -> 'ok'), + ErrorFun :: fun((any()) -> 'ok'), + VHost :: vhost:name()) -> 'ok'. + +apply_defs(Map, ActingUser, SuccessFun, ErrorFun, VHost) -> + rabbit_log:info("Asked to import definitions for a virtual host. Virtual host: ~p, acting user: ~p", + [VHost, ActingUser]), + try + validate_limits(Map, VHost), + rabbit_log:info("Importing parameters..."), + for_all(parameters, ActingUser, Map, VHost, fun add_parameter/3), + rabbit_log:info("Importing policies..."), + for_all(policies, ActingUser, Map, VHost, fun add_policy/3), + rabbit_log:info("Importing queues..."), + for_all(queues, ActingUser, Map, VHost, fun add_queue/3), + rabbit_log:info("Importing exchanges..."), + for_all(exchanges, ActingUser, Map, VHost, fun add_exchange/3), + rabbit_log:info("Importing bindings..."), + for_all(bindings, ActingUser, Map, VHost, fun add_binding/3), + SuccessFun() + catch {error, E} -> ErrorFun(format(E)); + exit:E -> ErrorFun(format(E)) + end. + +for_all(Name, ActingUser, Definitions, Fun) -> + case maps:get(rabbit_data_coercion:to_atom(Name), Definitions, undefined) of + undefined -> ok; + List -> [Fun(maps:from_list([{atomise_name(K), V} || {K, V} <- maps:to_list(M)]), + ActingUser) || + M <- List, is_map(M)] + end. + +for_all(Name, ActingUser, Definitions, VHost, Fun) -> + + case maps:get(rabbit_data_coercion:to_atom(Name), Definitions, undefined) of + undefined -> ok; + List -> [Fun(VHost, maps:from_list([{atomise_name(K), V} || {K, V} <- maps:to_list(M)]), + ActingUser) || + M <- List, is_map(M)] + end. + +format(#amqp_error{name = Name, explanation = Explanation}) -> + rabbit_data_coercion:to_binary(rabbit_misc:format("~s: ~s", [Name, Explanation])); +format({no_such_vhost, undefined}) -> + rabbit_data_coercion:to_binary( + "Virtual host does not exist and is not specified in definitions file."); +format({no_such_vhost, VHost}) -> + rabbit_data_coercion:to_binary( + rabbit_misc:format("Please create virtual host \"~s\" prior to importing definitions.", + [VHost])); +format({vhost_limit_exceeded, ErrMsg}) -> + rabbit_data_coercion:to_binary(ErrMsg); +format(E) -> + rabbit_data_coercion:to_binary(rabbit_misc:format("~p", [E])). + +add_parameter(Param, Username) -> + VHost = maps:get(vhost, Param, undefined), + add_parameter(VHost, Param, Username). + +add_parameter(VHost, Param, Username) -> + Comp = maps:get(component, Param, undefined), + Key = maps:get(name, Param, undefined), + Term = maps:get(value, Param, undefined), + Result = case is_map(Term) of + true -> + %% coerce maps to proplists for backwards compatibility. + %% See rabbitmq-management#528. + TermProplist = rabbit_data_coercion:to_proplist(Term), + rabbit_runtime_parameters:set(VHost, Comp, Key, TermProplist, Username); + _ -> + rabbit_runtime_parameters:set(VHost, Comp, Key, Term, Username) + end, + case Result of + ok -> ok; + {error_string, E} -> + S = rabbit_misc:format(" (~s/~s/~s)", [VHost, Comp, Key]), + exit(rabbit_data_coercion:to_binary(rabbit_misc:escape_html_tags(E ++ S))) + end. + +add_global_parameter(Param, Username) -> + Key = maps:get(name, Param, undefined), + Term = maps:get(value, Param, undefined), + case is_map(Term) of + true -> + %% coerce maps to proplists for backwards compatibility. + %% See rabbitmq-management#528. + TermProplist = rabbit_data_coercion:to_proplist(Term), + rabbit_runtime_parameters:set_global(Key, TermProplist, Username); + _ -> + rabbit_runtime_parameters:set_global(Key, Term, Username) + end. + +add_policy(Param, Username) -> + VHost = maps:get(vhost, Param, undefined), + add_policy(VHost, Param, Username). + +add_policy(VHost, Param, Username) -> + Key = maps:get(name, Param, undefined), + case rabbit_policy:set( + VHost, Key, maps:get(pattern, Param, undefined), + case maps:get(definition, Param, undefined) of + undefined -> undefined; + Def -> rabbit_data_coercion:to_proplist(Def) + end, + maps:get(priority, Param, undefined), + maps:get('apply-to', Param, <<"all">>), + Username) of + ok -> ok; + {error_string, E} -> S = rabbit_misc:format(" (~s/~s)", [VHost, Key]), + exit(rabbit_data_coercion:to_binary(rabbit_misc:escape_html_tags(E ++ S))) + end. + +add_vhost(VHost, ActingUser) -> + VHostName = maps:get(name, VHost, undefined), + VHostTrace = maps:get(tracing, VHost, undefined), + VHostDefinition = maps:get(definition, VHost, undefined), + VHostTags = maps:get(tags, VHost, undefined), + rabbit_vhost:put_vhost(VHostName, VHostDefinition, VHostTags, VHostTrace, ActingUser). + +add_permission(Permission, ActingUser) -> + rabbit_auth_backend_internal:set_permissions(maps:get(user, Permission, undefined), + maps:get(vhost, Permission, undefined), + maps:get(configure, Permission, undefined), + maps:get(write, Permission, undefined), + maps:get(read, Permission, undefined), + ActingUser). + +add_topic_permission(TopicPermission, ActingUser) -> + rabbit_auth_backend_internal:set_topic_permissions( + maps:get(user, TopicPermission, undefined), + maps:get(vhost, TopicPermission, undefined), + maps:get(exchange, TopicPermission, undefined), + maps:get(write, TopicPermission, undefined), + maps:get(read, TopicPermission, undefined), + ActingUser). + +add_queue(Queue, ActingUser) -> + add_queue_int(Queue, r(queue, Queue), ActingUser). + +add_queue(VHost, Queue, ActingUser) -> + add_queue_int(Queue, rv(VHost, queue, Queue), ActingUser). + +add_queue_int(Queue, Name, ActingUser) -> + rabbit_amqqueue:declare(Name, + maps:get(durable, Queue, undefined), + maps:get(auto_delete, Queue, undefined), + args(maps:get(arguments, Queue, undefined)), + none, + ActingUser). + +add_exchange(Exchange, ActingUser) -> + add_exchange_int(Exchange, r(exchange, Exchange), ActingUser). + +add_exchange(VHost, Exchange, ActingUser) -> + add_exchange_int(Exchange, rv(VHost, exchange, Exchange), ActingUser). + +add_exchange_int(Exchange, Name, ActingUser) -> + Internal = case maps:get(internal, Exchange, undefined) of + undefined -> false; %% =< 2.2.0 + I -> I + end, + rabbit_exchange:declare(Name, + rabbit_exchange:check_type(maps:get(type, Exchange, undefined)), + maps:get(durable, Exchange, undefined), + maps:get(auto_delete, Exchange, undefined), + Internal, + args(maps:get(arguments, Exchange, undefined)), + ActingUser). + +add_binding(Binding, ActingUser) -> + DestType = dest_type(Binding), + add_binding_int(Binding, r(exchange, source, Binding), + r(DestType, destination, Binding), ActingUser). + +add_binding(VHost, Binding, ActingUser) -> + DestType = dest_type(Binding), + add_binding_int(Binding, rv(VHost, exchange, source, Binding), + rv(VHost, DestType, destination, Binding), ActingUser). + +add_binding_int(Binding, Source, Destination, ActingUser) -> + rabbit_binding:add( + #binding{source = Source, + destination = Destination, + key = maps:get(routing_key, Binding, undefined), + args = args(maps:get(arguments, Binding, undefined))}, + ActingUser). + +dest_type(Binding) -> + rabbit_data_coercion:to_atom(maps:get(destination_type, Binding, undefined)). + +r(Type, Props) -> r(Type, name, Props). + +r(Type, Name, Props) -> + rabbit_misc:r(maps:get(vhost, Props, undefined), Type, maps:get(Name, Props, undefined)). + +rv(VHost, Type, Props) -> rv(VHost, Type, name, Props). + +rv(VHost, Type, Name, Props) -> + rabbit_misc:r(VHost, Type, maps:get(Name, Props, undefined)). + +%%-------------------------------------------------------------------- + +validate_limits(All) -> + case maps:get(queues, All, undefined) of + undefined -> ok; + Queues0 -> + {ok, VHostMap} = filter_out_existing_queues(Queues0), + maps:fold(fun validate_vhost_limit/3, ok, VHostMap) + end. + +validate_limits(All, VHost) -> + case maps:get(queues, All, undefined) of + undefined -> ok; + Queues0 -> + Queues1 = filter_out_existing_queues(VHost, Queues0), + AddCount = length(Queues1), + validate_vhost_limit(VHost, AddCount, ok) + end. + +filter_out_existing_queues(Queues) -> + build_filtered_map(Queues, maps:new()). + +filter_out_existing_queues(VHost, Queues) -> + Pred = fun(Queue) -> + Rec = rv(VHost, queue, <<"name">>, Queue), + case rabbit_amqqueue:lookup(Rec) of + {ok, _} -> false; + {error, not_found} -> true + end + end, + lists:filter(Pred, Queues). + +build_queue_data(Queue) -> + VHost = maps:get(<<"vhost">>, Queue, undefined), + Rec = rv(VHost, queue, <<"name">>, Queue), + {Rec, VHost}. + +build_filtered_map([], AccMap) -> + {ok, AccMap}; +build_filtered_map([Queue|Rest], AccMap0) -> + {Rec, VHost} = build_queue_data(Queue), + case rabbit_amqqueue:lookup(Rec) of + {error, not_found} -> + AccMap1 = maps_update_with(VHost, fun(V) -> V + 1 end, 1, AccMap0), + build_filtered_map(Rest, AccMap1); + {ok, _} -> + build_filtered_map(Rest, AccMap0) + end. + +%% Copy of maps:with_util/3 from Erlang 20.0.1. +maps_update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) -> + case maps:find(Key,Map) of + {ok,Val} -> maps:update(Key,Fun(Val),Map); + error -> maps:put(Key,Init,Map) + end; +maps_update_with(Key,Fun,Init,Map) -> + erlang:error(maps_error_type(Map),[Key,Fun,Init,Map]). + +%% Copy of maps:error_type/1 from Erlang 20.0.1. +maps_error_type(M) when is_map(M) -> badarg; +maps_error_type(V) -> {badmap, V}. + +validate_vhost_limit(VHost, AddCount, ok) -> + WouldExceed = rabbit_vhost_limit:would_exceed_queue_limit(AddCount, VHost), + validate_vhost_queue_limit(VHost, AddCount, WouldExceed). + +validate_vhost_queue_limit(_VHost, 0, _) -> + % Note: not adding any new queues so the upload + % must be update-only + ok; +validate_vhost_queue_limit(_VHost, _AddCount, false) -> + % Note: would not exceed queue limit + ok; +validate_vhost_queue_limit(VHost, AddCount, {true, Limit, QueueCount}) -> + ErrFmt = "Adding ~B queue(s) to virtual host \"~s\" would exceed the limit of ~B queue(s).~n~nThis virtual host currently has ~B queue(s) defined.~n~nImport aborted!", + ErrInfo = [AddCount, VHost, Limit, QueueCount], + ErrMsg = rabbit_misc:format(ErrFmt, ErrInfo), + exit({vhost_limit_exceeded, ErrMsg}). + +atomise_name(N) -> rabbit_data_coercion:to_atom(N). + +get_or_missing(K, L) -> + case maps:get(K, L, undefined) of + undefined -> {key_missing, K}; + V -> V + end. + +args([]) -> args(#{}); +args(L) -> rabbit_misc:to_amqp_table(L). + +%% +%% Export +%% + +list_exchanges() -> + %% exclude internal exchanges, they are not meant to be declared or used by + %% applications + [exchange_definition(X) || X <- lists:filter(fun(#exchange{internal = true}) -> false; + (#exchange{}) -> true + end, + rabbit_exchange:list())]. + +exchange_definition(#exchange{name = #resource{virtual_host = VHost, name = Name}, + type = Type, + durable = Durable, auto_delete = AD, arguments = Args}) -> + #{<<"vhost">> => VHost, + <<"name">> => Name, + <<"type">> => Type, + <<"durable">> => Durable, + <<"auto_delete">> => AD, + <<"arguments">> => Args}. + +list_queues() -> + %% exclude exclusive queues, they cannot be restored + [queue_definition(Q) || Q <- lists:filter(fun(Q0) -> + amqqueue:get_exclusive_owner(Q0) =:= none + end, + rabbit_amqqueue:list())]. + +queue_definition(Q) -> + #resource{virtual_host = VHost, name = Name} = amqqueue:get_name(Q), + Type = case amqqueue:get_type(Q) of + rabbit_classic_queue -> classic; + rabbit_quorum_queue -> quorum; + T -> T + end, + Arguments = [{Key, Value} || {Key, _Type, Value} <- amqqueue:get_arguments(Q)], + #{ + <<"vhost">> => VHost, + <<"name">> => Name, + <<"type">> => Type, + <<"durable">> => amqqueue:is_durable(Q), + <<"auto_delete">> => amqqueue:is_auto_delete(Q), + <<"arguments">> => maps:from_list(Arguments) + }. + +list_bindings() -> + [binding_definition(B) || B <- rabbit_binding:list_explicit()]. + +binding_definition(#binding{source = S, + key = RoutingKey, + destination = D, + args = Args}) -> + Arguments = [{Key, Value} || {Key, _Type, Value} <- Args], + #{ + <<"source">> => S#resource.name, + <<"vhost">> => S#resource.virtual_host, + <<"destination">> => D#resource.name, + <<"destination_type">> => D#resource.kind, + <<"routing_key">> => RoutingKey, + <<"arguments">> => maps:from_list(Arguments) + }. + +list_vhosts() -> + [vhost_definition(V) || V <- rabbit_vhost:all()]. + +vhost_definition(VHost) -> + #{ + <<"name">> => vhost:get_name(VHost), + <<"limits">> => vhost:get_limits(VHost), + <<"metadata">> => vhost:get_metadata(VHost) + }. + +list_users() -> + [begin + {ok, User} = rabbit_auth_backend_internal:lookup_user(pget(user, U)), + #{name => User#internal_user.username, + password_hash => base64:encode(User#internal_user.password_hash), + hashing_algorithm => rabbit_auth_backend_internal:hashing_module_for_user(User), + tags => tags_as_binaries(User#internal_user.tags) + } + end || U <- rabbit_auth_backend_internal:list_users()]. + +list_runtime_parameters() -> + [runtime_parameter_definition(P) || P <- rabbit_runtime_parameters:list()]. + +runtime_parameter_definition(Param) -> + #{ + <<"vhost">> => pget(vhost, Param), + <<"component">> => pget(component, Param), + <<"name">> => pget(name, Param), + <<"value">> => maps:from_list(pget(value, Param)) + }. + +list_global_runtime_parameters() -> + [global_runtime_parameter_definition(P) || P <- rabbit_runtime_parameters:list_global()]. + +global_runtime_parameter_definition(Param) -> + maps:from_list(Param). + +list_policies() -> + [policy_definition(P) || P <- rabbit_policy:list()]. + +policy_definition(Policy) -> + #{ + <<"vhost">> => pget(vhost, Policy), + <<"name">> => pget(name, Policy), + <<"pattern">> => pget(pattern, Policy), + <<"apply-to">> => pget('apply-to', Policy), + <<"priority">> => pget(priority, Policy), + <<"definition">> => maps:from_list(pget(definition, Policy)) + }. + +list_permissions() -> + [permission_definition(P) || P <- rabbit_auth_backend_internal:list_permissions()]. + +permission_definition(P) -> + maps:from_list(P). + +list_topic_permissions() -> + [topic_permission_definition(P) || P <- rabbit_auth_backend_internal:list_topic_permissions()]. + +topic_permission_definition(P) -> + maps:from_list(P). + +tags_as_binaries(Tags) -> + list_to_binary(string:join([atom_to_list(T) || T <- Tags], ",")). diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl index 86c11c4ad2..0d945929af 100644 --- a/src/rabbit_exchange.erl +++ b/src/rabbit_exchange.erl @@ -174,7 +174,7 @@ store_ram(X) -> (binary()) -> atom() | rabbit_types:connection_exit(). check_type(TypeBin) -> - case rabbit_registry:binary_to_type(TypeBin) of + case rabbit_registry:binary_to_type(rabbit_data_coercion:to_binary(TypeBin)) of {error, not_found} -> rabbit_misc:protocol_error( command_invalid, "unknown exchange type '~s'", [TypeBin]); diff --git a/src/rabbit_policy.erl b/src/rabbit_policy.erl index ff07bfa8ee..78157072e3 100644 --- a/src/rabbit_policy.erl +++ b/src/rabbit_policy.erl @@ -43,7 +43,7 @@ -export([register/0]). -export([invalidate/0, recover/0]). --export([name/1, name_op/1, effective_definition/1, get/2, get_arg/3, set/1]). +-export([name/1, name_op/1, effective_definition/1, merge_operator_definitions/2, get/2, get_arg/3, set/1]). -export([validate/5, notify/5, notify_clear/4]). -export([parse_set/7, set/7, delete/3, lookup/2, list/0, list/1, list_formatted/1, list_formatted/3, info_keys/0]). @@ -76,23 +76,23 @@ name0(Policy) -> pget(name, Policy). effective_definition(Q) when ?is_amqqueue(Q) -> Policy = amqqueue:get_policy(Q), OpPolicy = amqqueue:get_operator_policy(Q), - effective_definition0(Policy, OpPolicy); + merge_operator_definitions(Policy, OpPolicy); effective_definition(#exchange{policy = Policy, operator_policy = OpPolicy}) -> - effective_definition0(Policy, OpPolicy). - -effective_definition0(undefined, undefined) -> undefined; -effective_definition0(Policy, undefined) -> pget(definition, Policy); -effective_definition0(undefined, OpPolicy) -> pget(definition, OpPolicy); -effective_definition0(Policy, OpPolicy) -> - OpDefinition = pget(definition, OpPolicy, []), - Definition = pget(definition, Policy, []), - {Keys, _} = lists:unzip(Definition), - {OpKeys, _} = lists:unzip(OpDefinition), + merge_operator_definitions(Policy, OpPolicy). + +merge_operator_definitions(undefined, undefined) -> undefined; +merge_operator_definitions(Policy, undefined) -> pget(definition, Policy); +merge_operator_definitions(undefined, OpPolicy) -> pget(definition, OpPolicy); +merge_operator_definitions(Policy, OpPolicy) -> + OpDefinition = rabbit_data_coercion:to_map(pget(definition, OpPolicy, [])), + Definition = rabbit_data_coercion:to_map(pget(definition, Policy, [])), + Keys = maps:keys(Definition), + OpKeys = maps:keys(OpDefinition), lists:map(fun(Key) -> - case {pget(Key, Definition), pget(Key, OpDefinition)} of - {Val, undefined} -> {Key, Val}; - {undefined, Val} -> {Key, Val}; - {Val, OpVal} -> {Key, merge_policy_value(Key, Val, OpVal)} + case {maps:get(Key, Definition, undefined), maps:get(Key, OpDefinition, undefined)} of + {Val, undefined} -> {Key, Val}; + {undefined, OpVal} -> {Key, OpVal}; + {Val, OpVal} -> {Key, merge_policy_value(Key, Val, OpVal)} end end, lists:umerge(Keys, OpKeys)). @@ -142,11 +142,11 @@ get0(Name, Policy, OpPolicy) -> merge_policy_value(Name, PolicyVal, OpVal) -> case policy_merge_strategy(Name) of {ok, Module} -> Module:merge_policy_value(Name, PolicyVal, OpVal); - {error, not_found} -> PolicyVal + {error, not_found} -> rabbit_policies:merge_policy_value(Name, PolicyVal, OpVal) end. policy_merge_strategy(Name) -> - case rabbit_registry:binary_to_type(Name) of + case rabbit_registry:binary_to_type(rabbit_data_coercion:to_binary(Name)) of {error, not_found} -> {error, not_found}; T -> diff --git a/src/rabbit_vhost.erl b/src/rabbit_vhost.erl index 95758cec7f..dbc3d6344a 100644 --- a/src/rabbit_vhost.erl +++ b/src/rabbit_vhost.erl @@ -27,6 +27,7 @@ -export([dir/1, msg_store_dir_path/1, msg_store_dir_wildcard/0]). -export([delete_storage/1]). -export([vhost_down/1]). +-export([put_vhost/5]). %% %% API @@ -96,7 +97,12 @@ add(Name, Description, Tags, ActingUser) -> end. do_add(Name, Description, Tags, ActingUser) -> - rabbit_log:info("Adding vhost '~s' (description: '~s')", [Name, Description]), + case Description of + undefined -> + rabbit_log:info("Adding vhost '~s' without a description", [Name]); + Value -> + rabbit_log:info("Adding vhost '~s' (description: '~s')", [Name, Value]) + end, VHost = rabbit_misc:execute_mnesia_transaction( fun () -> case mnesia:wread({rabbit_vhost, Name}) of @@ -171,6 +177,48 @@ delete(VHost, ActingUser) -> rabbit_vhost_sup_sup:delete_on_all_nodes(VHost), ok. +put_vhost(Name, Description, Tags0, Trace, Username) -> + Tags = case Tags0 of + undefined -> <<"">>; + null -> <<"">>; + "undefined" -> <<"">>; + "null" -> <<"">>; + Other -> Other + end, + Result = case exists(Name) of + true -> ok; + false -> add(Name, Description, parse_tags(Tags), Username), + %% wait for up to 45 seconds for the vhost to initialise + %% on all nodes + case await_running_on_all_nodes(Name, 45000) of + ok -> + maybe_grant_full_permissions(Name, Username); + {error, timeout} -> + {error, timeout} + end + end, + case Trace of + true -> rabbit_trace:start(Name); + false -> rabbit_trace:stop(Name); + undefined -> ok + end, + Result. + +%% when definitions are loaded on boot, Username here will be ?INTERNAL_USER, +%% which does not actually exist +maybe_grant_full_permissions(_Name, ?INTERNAL_USER) -> + ok; +maybe_grant_full_permissions(Name, Username) -> + U = rabbit_auth_backend_internal:lookup_user(Username), + maybe_grant_full_permissions(U, Name, Username). + +maybe_grant_full_permissions({ok, _}, Name, Username) -> + rabbit_auth_backend_internal:set_permissions( + Username, Name, <<".*">>, <<".*">>, <<".*">>, Username); +maybe_grant_full_permissions(_, _Name, _Username) -> + ok. + + %% 50 ms -define(AWAIT_SAMPLE_INTERVAL, 50). diff --git a/test/config_schema_SUITE_data/rabbit.snippets b/test/config_schema_SUITE_data/rabbit.snippets index 078669abfe..0137ad7bc1 100644 --- a/test/config_schema_SUITE_data/rabbit.snippets +++ b/test/config_schema_SUITE_data/rabbit.snippets @@ -648,6 +648,15 @@ credential_validator.regexp = ^abc\\d+", []}, %% + %% Definitions + %% + + {definition_files, "load_definitions = test/definition_import_SUITE_data/case1.json", + [{rabbit, + [{load_definitions, "test/definition_import_SUITE_data/case1.json"}]}], + []}, + + %% %% Raft %% diff --git a/test/definition_import_SUITE.erl b/test/definition_import_SUITE.erl new file mode 100644 index 0000000000..fc49535f92 --- /dev/null +++ b/test/definition_import_SUITE.erl @@ -0,0 +1,143 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% https://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +%% + +%% This test suite covers the definitions import function +%% outside of the context of HTTP API (e.g. when definitions are +%% imported on boot). + +-module(definition_import_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-compile(export_all). + +all() -> + [ + {group, non_parallel_tests} + ]. + +groups() -> + [ + {non_parallel_tests, [], [ + %% Note: to make it easier to see which case failed, + %% these are intentionally not folded into a single case. + %% If generation becomes an alternative worth considering for these tests, + %% we'll just add a case that drives PropEr. + import_case1, + import_case2, + import_case3, + import_case4, + import_case5, + import_case6, + import_case7, + import_case8, + import_case9, + import_case10 + ]} + ]. + +%% ------------------------------------------------------------------- +%% Test suite setup/teardown. +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + inets:start(), + Config1 = rabbit_ct_helpers:set_config(Config, [ + {rmq_nodename_suffix, ?MODULE} + ]), + rabbit_ct_helpers:run_setup_steps(Config1, + rabbit_ct_broker_helpers:setup_steps() ++ + rabbit_ct_client_helpers:setup_steps()). +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config, + rabbit_ct_client_helpers:teardown_steps() ++ + rabbit_ct_broker_helpers:teardown_steps()). + +init_per_group(_, Config) -> + Config. + +end_per_group(_, Config) -> + Config. + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +end_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_finished(Config, Testcase). + +%% +%% Tests +%% + +import_case1(Config) -> import_file_case(Config, "case1"). +import_case2(Config) -> import_file_case(Config, "case2"). +import_case3(Config) -> import_file_case(Config, "case3"). +import_case4(Config) -> import_file_case(Config, "case4"). +import_case6(Config) -> import_file_case(Config, "case6"). +import_case7(Config) -> import_file_case(Config, "case7"). +import_case8(Config) -> import_file_case(Config, "case8"). + +import_case9(Config) -> import_from_directory_case(Config, "case9"). + +import_case10(Config) -> import_from_directory_case_fails(Config, "case10"). + +import_case5(Config) -> + import_file_case(Config, "case5"), + ?assertEqual(rabbit_ct_broker_helpers:rpc(Config, 0, + rabbit_runtime_parameters, value_global, + [mqtt_port_to_vhost_mapping]), + %% expect a proplist, see rabbitmq/rabbitmq-management#528 + [{<<"1883">>,<<"/">>}, + {<<"1884">>,<<"vhost2">>}]). + +import_file_case(Config, CaseName) -> + CasePath = filename:join(?config(data_dir, Config), CaseName ++ ".json"), + rabbit_ct_broker_helpers:rpc(Config, 0, ?MODULE, run_import_case, [CasePath]), + ok. + +import_from_directory_case(Config, CaseName) -> + import_from_directory_case_expect(Config, CaseName, ok). + +import_from_directory_case_fails(Config, CaseName) -> + import_from_directory_case_expect(Config, CaseName, error). + +import_from_directory_case_expect(Config, CaseName, Expected) -> + CasePath = filename:join(?config(data_dir, Config), CaseName), + ?assert(filelib:is_dir(CasePath)), + rabbit_ct_broker_helpers:rpc(Config, 0, + ?MODULE, run_directory_import_case, + [CasePath, Expected]), + ok. + +run_directory_import_case(Path, Expected) -> + ct:pal("Will load definitions from files under ~p~n", [Path]), + Result = rabbit_definitions:maybe_load_definitions_from(true, Path), + case Expected of + ok -> + ok = Result; + error -> + ?assertMatch({error, {failed_to_import_definitions, _, _}}, Result) + end. + +run_import_case(Path) -> + {ok, Body} = file:read_file(Path), + ct:pal("Successfully loaded a definition to import from ~p~n", [Path]), + case rabbit_definitions:import_raw(Body) of + ok -> ok; + {error, E} -> + ct:pal("Import case ~p failed: ~p~n", [Path, E]), + ct:fail({failure, Path, E}) + end. diff --git a/test/definition_import_SUITE_data/case1.json b/test/definition_import_SUITE_data/case1.json new file mode 100644 index 0000000000..b0785a5214 --- /dev/null +++ b/test/definition_import_SUITE_data/case1.json @@ -0,0 +1,99 @@ +{ + "rabbit_version": "3.6.9", + "users": [ + { + "name": "project_admin", + "password_hash": "A0EX\/2hiwrIDKFS+nEqwbCGcVxwEkDBFF3mBfkNW53KFFk64", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + } + ], + "vhosts": [ + { + "name": "\/" + } + ], + "permissions": [ + { + "user": "project_admin", + "vhost": "\/", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "policies": [ + { + "vhost": "\/", + "name": "nd-ns", + "pattern": "^project-nd-ns-", + "apply-to": "queues", + "definition": { + "expires": 120000, + "max-length": 10000 + }, + "priority": 1 + }, + { + "vhost": "\/", + "name": "nd-s", + "pattern": "^project-nd-s-", + "apply-to": "queues", + "definition": { + "expires": 1800000, + "max-length": 50000 + }, + "priority": 1 + }, + { + "vhost": "\/", + "name": "d-ns", + "pattern": "^project-d-ns-", + "apply-to": "queues", + "definition": { + "ha-mode": "exactly", + "ha-params": 3, + "ha-sync-mode": "automatic", + "expires": 604800000, + "ha-sync-batch-size": 100, + "queue-mode": "lazy" + }, + "priority": 1 + }, + { + "vhost": "\/", + "name": "d-s", + "pattern": "^project-d-s-", + "apply-to": "queues", + "definition": { + "ha-mode": "exactly", + "ha-params": 3, + "ha-sync-mode": "automatic", + "expires": 604800000, + "queue-master-locator": "min-masters", + "ha-sync-batch-size": 100, + "queue-mode": "lazy" + }, + "priority": 1 + } + ], + "queues": [ + + ], + "exchanges": [ + { + "name": "project.topic.default", + "vhost": "\/", + "type": "topic", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": { + + } + } + ], + "bindings": [ + + ] +}
\ No newline at end of file diff --git a/test/definition_import_SUITE_data/case10/case10a.json b/test/definition_import_SUITE_data/case10/case10a.json new file mode 100644 index 0000000000..1eec5ccb9e --- /dev/null +++ b/test/definition_import_SUITE_data/case10/case10a.json @@ -0,0 +1,67 @@ +{ + "rabbit_version": "3.7.13", + "users": [ + { + "name": "bunny_reader", + "password_hash": "ExmGdjBTmQEPxcW2z+dsOuPvjFbTBiYQgMByzfpE/IIXplYG", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + } + ], + "vhosts": [ + { + "name": "langohr_testbed" + }, + { + "name": "bunny_testbed" + }, + { + "name": "/" + } + ], + "permissions": [ + { + "user": "bunny_reader", + "vhost": "bunny_testbed", + "configure": "^---$", + "write": "^---$", + "read": ".*" + } + ], + "topic_permissions": [], + "parameters": [ + { + "component": "vhost-limits", + "name": "limits", + "value": { + "max-connections": 14000 + }, + "vhost": "/" + } + ], + "global_parameters": [ + { + "name": "cluster_name", + "value": "rabbit@localhost" + } + ], + "policies": [], + "queues": [ + { + "name": "bunny.basic_consume0.1364356981103202", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.1364356981103202", + "vhost": "bunny_testbed", + "durable": true, + "auto_delete": true, + "arguments": {} + } + ], + "exchanges": [], + "bindings": [] +} diff --git a/test/definition_import_SUITE_data/case10/case10b.json b/test/definition_import_SUITE_data/case10/case10b.json new file mode 100644 index 0000000000..9eb48e341e --- /dev/null +++ b/test/definition_import_SUITE_data/case10/case10b.json @@ -0,0 +1,595 @@ +{ + "rabbit_version": "3.7.13", + "users": [ + { + "name": "langohr", + "password_hash": "7p9PXlsYs92NlHSdNgPoDXmN77NqeGpzCTHpElq/wPS1eAEd", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + }, + { + "name": "bunny_reader", + "password_hash": "ExmGdjBTmQEPxcW2z+dsOuPvjFbTBiYQgMByzfpE/IIXplYG", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + }, + { + "name": "bunny_gem", + "password_hash": "8HH7uxmZS3FDldlYmHpFEE5+gWaeQaim8qpWIHkmNxuQK8xO", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + }, + { + "name": "guest2", + "password_hash": "E04A7cvvsaDJBezc3Sc2jCnywe9oS4DX18qFe4dwkjIr26gf", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "monitoring" + }, + { + "name": "guest", + "password_hash": "CPCbkNAHXgQ7vmrqwP9e7RWQsE8U2DqN7JA4ggS50c4LwDda", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "administrator" + }, + { + "name": "temp-user", + "password_hash": "CfUQkDeOYDrPkACDCjoF5zySbsXPIoMgNfv7FWfEpVFGegnL", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "management" + } + ], + "vhosts": [ + { + "name": "langohr_testbed" + }, + { + "name": "bunny_testbed" + }, + { + "name": "/" + }, + { + "name": "vhost3" + } + ], + "permissions": [ + { + "user": "bunny_reader", + "vhost": "bunny_testbed", + "configure": "^---$", + "write": "^---$", + "read": ".*" + }, + { + "user": "bunny_gem", + "vhost": "bunny_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "/", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "langohr", + "vhost": "langohr_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "bunny_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "langohr_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "vhost3", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "langohr", + "vhost": "/", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "temp-user", + "vhost": "/", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "topic_permissions": [], + "parameters": [ + { + "value": { + "expires": 3600000, + "uri": "amqp://localhost:5673" + }, + "vhost": "/", + "component": "federation-upstream", + "name": "up-hare" + }, + { + "value": { + "max-connections": 2000 + }, + "vhost": "/", + "component": "vhost-limits", + "name": "limits" + } + ], + "global_parameters": [ + { + "name": "cluster_name", + "value": "rabbit@localhost" + } + ], + "policies": [], + "queues": [ + { + "name": "bunny.basic_consume0.7103611911099639", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.6091120557781405", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.8661861002262826", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.3682573609392056", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.14855593896585362", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.9534242141484872", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.9434723539955824", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.12235844522013617", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.8370997977912426", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.4548488370639835", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.2289868670635532", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.00797124769641977", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "amq.gen-xddEPq9wHSNZKQbPK8pi3A", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": false, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.5195700828676673", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "bunny.basic_consume0.3071859764599716", + "vhost": "bunny_testbed", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "return", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "q1", + "vhost": "/", + "durable": true, + "auto_delete": false, + "arguments": {} + }, + { + "name": "declareArgs-deliveries-dead-letter", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "test.rabbitmq-basic-nack", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "langohr.test.recovery.q1", + "vhost": "/", + "durable": true, + "auto_delete": true, + "arguments": {} + }, + { + "name": "langohr.tests2.queues.client-named.durable.non-exclusive.non-auto-deleted", + "vhost": "/", + "durable": true, + "auto_delete": false, + "arguments": {} + }, + { + "name": "test.tx.rollback", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "test-integration-declared-passive-queue", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "test.recover", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "amq.gen-7EZF7WjGIQFDoXexVF-e8w", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": { + "x-message-ttl": 1500 + } + }, + { + "name": "test.integration.channel.error", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "confirm", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "test.rabbitmq-message-ttl", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": { + "x-message-ttl": 100 + } + }, + { + "name": "declareWithTTL", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": { + "x-message-ttl": 9000000 + } + }, + { + "name": "test.tx.commit", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "test.get-ok", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "langohr.tests2.queues.non-auto-deleted1", + "vhost": "/", + "durable": false, + "auto_delete": true, + "arguments": {} + }, + { + "name": "qv3", + "vhost": "vhost3", + "durable": true, + "auto_delete": false, + "arguments": {} + } + ], + "exchanges": [ + { + "name": "bunny.tests.exchanges.fanout", + "vhost": "bunny_testbed", + "type": "fanout", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "declareArgs-dead-letter", + "vhost": "/", + "type": "fanout", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.topic5", + "vhost": "/", + "type": "topic", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.extensions.altexchanges.direct1", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": { + "alternate-exchange": "langohr.extensions.altexchanges.fanout1" + } + }, + { + "name": "langohr.tests.exchanges.fanout1", + "vhost": "/", + "type": "fanout", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.direct3", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.topic4", + "vhost": "/", + "type": "topic", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.test.recovery.fanout2", + "vhost": "/", + "type": "fanout", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.fanout3", + "vhost": "/", + "type": "fanout", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.direct4", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.topic2", + "vhost": "/", + "type": "topic", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "test-integration-declared-passive-exchange", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "test-channel-still-exists", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.topic1", + "vhost": "/", + "type": "topic", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.fanout2", + "vhost": "/", + "type": "fanout", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.direct1", + "vhost": "/", + "type": "direct", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.direct2", + "vhost": "/", + "type": "direct", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.headers2", + "vhost": "/", + "type": "headers", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.topic3", + "vhost": "/", + "type": "topic", + "durable": false, + "auto_delete": true, + "internal": false, + "arguments": {} + }, + { + "name": "langohr.tests.exchanges.fanout4", + "vhost": "/", + "type": "fanout", + "durable": false, + "auto_delete": false, + "internal": false, + "arguments": {} + } + ], + "bindings": [ + { + "source": "amq.fanout", + "vhost": "/", + "destination": "langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted", + "destination_type": "queue", + "routing_key": "", + "arguments": {} + }, + { + "source": "declareArgs-dead-letter", + "vhost": "/", + "destination": "declareArgs-deliveries-dead-letter", + "destination_type": "queue", + "routing_key": "#", + "arguments": {} + } + ] +} diff --git a/test/definition_import_SUITE_data/case2.json b/test/definition_import_SUITE_data/case2.json new file mode 100644 index 0000000000..0f0a014681 --- /dev/null +++ b/test/definition_import_SUITE_data/case2.json @@ -0,0 +1,49 @@ +{ + "rabbit_version": "3.7.0-rc.1", + "users": [ + { + "name": "guest", + "password_hash": "A0EX\/2hiwrIDKFS+nEqwbCGcVxwEkDBFF3mBfkNW53KFFk64", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "administrator" + } + ], + "vhosts": [ + { + "name": "\/" + } + ], + "permissions": [ + { + "user": "guest", + "vhost": "\/", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "topic_permissions": [ + + ], + "parameters": [ + + ], + "global_parameters": [ + { + "name": "cluster_name", + "value": "rabbit@mercurio" + } + ], + "policies": [ + + ], + "queues": [ + + ], + "exchanges": [ + + ], + "bindings": [ + + ] +} diff --git a/test/definition_import_SUITE_data/case3.json b/test/definition_import_SUITE_data/case3.json new file mode 100644 index 0000000000..963039f254 --- /dev/null +++ b/test/definition_import_SUITE_data/case3.json @@ -0,0 +1 @@ +{"rabbit_version":"3.7.0-alpha.381","users":[{"name":"admin","password_hash":"Edl2rJd/zLC187M1SKibRoTb6+xGkvkqoKWEq0kdNUbNLyLJ","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"administrator"}],"vhosts":[{"name":"/"}],"permissions":[{"user":"admin","vhost":"/","configure":".*","write":".*","read":".*"}],"topic_permissions":[],"parameters":[],"global_parameters":[{"name":"cluster_name","value":"rmq-gcp-37"}],"policies":[{"vhost":"/","name":"2-queue-replicas","pattern":".*","apply-to":"queues","definition":{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"},"priority":0}],"queues":[{"name":"wr-vary-load-lazy-persistent-1","vhost":"/","durable":true,"auto_delete":false,"arguments":{"x-queue-mode":"lazy"}},{"name":"wr-vary-load-lazy-transient-1","vhost":"/","durable":true,"auto_delete":false,"arguments":{"x-queue-mode":"lazy"}},{"name":"wr-vary-load-2","vhost":"/","durable":true,"auto_delete":false,"arguments":{"x-queue-mode":"default"}},{"name":"wr-vary-load-1","vhost":"/","durable":true,"auto_delete":false,"arguments":{"x-queue-mode":"default"}},{"name":"aliveness-test","vhost":"/","durable":false,"auto_delete":false,"arguments":{}}],"exchanges":[],"bindings":[{"source":"amq.direct","vhost":"/","destination":"wr-vary-load-2","destination_type":"queue","routing_key":"wr-vary-load-2","arguments":{}},{"source":"amq.direct","vhost":"/","destination":"wr-vary-load-lazy-persistent-1","destination_type":"queue","routing_key":"wr-vary-load-lazy-persistent-1","arguments":{}},{"source":"amq.direct","vhost":"/","destination":"wr-vary-load-lazy-transient-1","destination_type":"queue","routing_key":"wr-vary-load-lazy-transient-1","arguments":{}}]}
\ No newline at end of file diff --git a/test/definition_import_SUITE_data/case4.json b/test/definition_import_SUITE_data/case4.json new file mode 100644 index 0000000000..f5223ff3a2 --- /dev/null +++ b/test/definition_import_SUITE_data/case4.json @@ -0,0 +1,49 @@ +{ + "bindings": [], + "exchanges": [], + "parameters": [], + "permissions": [ + { + "configure": ".*", + "read": ".*", + "user": "guest", + "vhost": "/", + "write": ".*" + } + ], + "policies": [ + { + "apply-to": "all", + "definition": { + "queue-master-locator": "client-local" + }, + "name": "abc", + "pattern": "^abc\\.", + "priority": 0, + "vhost": "/" + } + ], + "queues": [ + { + "arguments": {}, + "auto_delete": false, + "durable": false, + "name": "abc.def", + "vhost": "/" + } + ], + "rabbit_version": "0.0.0", + "users": [ + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "name": "guest", + "password_hash": "QM532K822VTbYBFbwSZEnT8jkH8TT0dPsUtja6vL0myfsrmk", + "tags": "administrator" + } + ], + "vhosts": [ + { + "name": "/" + } + ] +} diff --git a/test/definition_import_SUITE_data/case5.json b/test/definition_import_SUITE_data/case5.json new file mode 100644 index 0000000000..607dfd3d1f --- /dev/null +++ b/test/definition_import_SUITE_data/case5.json @@ -0,0 +1,63 @@ +{ + "rabbit_version": "3.7.2", + "users": [ + { + "name": "guest", + "password_hash": "PD4MQV8Ivcprh1\/yUS9x7jkpbXtWIZLTQ0tvnZPncpI6Ui0a", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "administrator" + } + ], + "vhosts": [ + { + "name": "\/" + }, + { + "name": "vhost2" + } + ], + "permissions": [ + { + "user": "guest", + "vhost": "\/", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "vhost2", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "topic_permissions": [ + + ], + "parameters": [ + + ], + "global_parameters": [ + { + "name": "mqtt_port_to_vhost_mapping", + "value": { + "1883": "\/", + "1884": "vhost2" + } + }, + { + "name": "cluster_name", + "value": "rabbitmq@localhost" + } + ], + "policies": [ + ], + "queues": [ + ], + "exchanges": [ + ], + "bindings": [ + + ] +} diff --git a/test/definition_import_SUITE_data/case6.json b/test/definition_import_SUITE_data/case6.json new file mode 100644 index 0000000000..c0debb7de1 --- /dev/null +++ b/test/definition_import_SUITE_data/case6.json @@ -0,0 +1,47 @@ +{ + "rabbit_version": "3.7.3+10.g41ec73b", + "users": [ + { + "name": "guest", + "password_hash": "J+UiUxNQ3I8uPn6Lo2obWcl93VgXgbw4R+xhl3L5zHwkRFZG", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "administrator" + } + ], + "vhosts": [ + { + "name": "/" + } + ], + "permissions": [ + { + "user": "guest", + "vhost": "/", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "topic_permissions": [], + "parameters": [ + { + "value": { + "max-queues": 456, + "max-connections": 123 + }, + "vhost": "/", + "component": "vhost-limits", + "name": "limits" + } + ], + "global_parameters": [ + { + "name": "cluster_name", + "value": "rabbit@localhost.localdomain" + } + ], + "policies": [], + "queues": [], + "exchanges": [], + "bindings": [] +}
\ No newline at end of file diff --git a/test/definition_import_SUITE_data/case7.json b/test/definition_import_SUITE_data/case7.json new file mode 100644 index 0000000000..7a8e0174ac --- /dev/null +++ b/test/definition_import_SUITE_data/case7.json @@ -0,0 +1,398 @@ + + +{ + "rabbit_version": "3.7.4", + "users": [ + { + "name": "bunny_reader", + "password_hash": "rgJkcwpypdpIVhbLDj7CaCtFVg6Dyj3yQDcCbhyn29u49c88", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + }, + { + "name": "bunny_gem", + "password_hash": "fHFOkIlJ8iohrhN4IQXIzIDrxsOfaekv97wA1W\/0N\/uxTWjE", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "" + }, + { + "name": "guest", + "password_hash": "ujflQBzsAaAfbNSLAy4y2iG9mMpgATaH5oXQfPLkxOhE1yzH", + "hashing_algorithm": "rabbit_password_hashing_sha256", + "tags": "administrator" + } + ], + "vhosts": [ + { + "name": "bunny_testbed" + }, + { + "name": "\/" + } + ], + "permissions": [ + { + "user": "bunny_reader", + "vhost": "bunny_testbed", + "configure": "^---$", + "write": "^---$", + "read": ".*" + }, + { + "user": "guest", + "vhost": "\/", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "bunny_gem", + "vhost": "bunny_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + }, + { + "user": "guest", + "vhost": "bunny_testbed", + "configure": ".*", + "write": ".*", + "read": ".*" + } + ], + "topic_permissions": [ + + ], + "parameters": [ + { + "value": { + "pattern": "^apd\\\\.mce\\\\.estarchive.*$", + "definition": { + "max-length-bytes": 200000000 + }, + "priority": 0, + "apply-to": "queues" + }, + "vhost": "\/", + "component": "operator_policy", + "name": "apd-mce-estarchive" + } + ], + "global_parameters": [ + { + "name": "cluster_name", + "value": "rabbit@warp10" + } + ], + "policies": [ + + ], + "queues": [ + { + "name": "test", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "reply", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "ack-test", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "nack-test", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "redelivered-test", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "unsub02", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "known3", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "ack-test-tx", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "stomp-subscription-As-CQ37wutHLc9H0PmjIPw", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "unsub01", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "test-receipt-tx", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "unsub03", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "test2", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "known", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "unsub04", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "stomp-subscription-j7FLeUn7ehTatYVNiBy6UA", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "ir", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "nack-multi", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "test-receipt", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "reliability", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "duplicate-consumer-tag-test2", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "test-multi", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "test3", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "stomp-subscription-tMbeqL30tjlgaXMmaFM6Ew", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "nack-test-no-requeue", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "ack-test-individual", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "known2", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "custom-header", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + }, + { + "name": "stomp-subscription-eWSXV2ty1R7VqfsnULKEkA", + "vhost": "\/", + "durable": true, + "auto_delete": false, + "arguments": { + + } + } + ], + "exchanges": [ + + ], + "bindings": [ + { + "source": "amq.topic", + "vhost": "\/", + "destination": "stomp-subscription-tMbeqL30tjlgaXMmaFM6Ew", + "destination_type": "queue", + "routing_key": "durable", + "arguments": { + + } + }, + { + "source": "amq.topic", + "vhost": "\/", + "destination": "stomp-subscription-eWSXV2ty1R7VqfsnULKEkA", + "destination_type": "queue", + "routing_key": "durable-separate", + "arguments": { + + } + }, + { + "source": "amq.topic", + "vhost": "\/", + "destination": "stomp-subscription-j7FLeUn7ehTatYVNiBy6UA", + "destination_type": "queue", + "routing_key": "durable-separate", + "arguments": { + + } + }, + { + "source": "amq.topic", + "vhost": "\/", + "destination": "stomp-subscription-As-CQ37wutHLc9H0PmjIPw", + "destination_type": "queue", + "routing_key": "durable-shared", + "arguments": { + + } + } + ] +} diff --git a/test/definition_import_SUITE_data/case8.json b/test/definition_import_SUITE_data/case8.json new file mode 100644 index 0000000000..1deb55b45c --- /dev/null +++ b/test/definition_import_SUITE_data/case8.json @@ -0,0 +1,17 @@ +{ + "rabbit_version": "3.8.0+beta.1.6.g0c7c7d9", + "parameters": [ + { + "value": { + "max-connections": 6767 + }, + "vhost": "/", + "component": "vhost-limits", + "name": "limits" + } + ], + "policies": [], + "queues": [], + "exchanges": [], + "bindings": [] +}
\ No newline at end of file diff --git a/test/definition_import_SUITE_data/case9/case9a.json b/test/definition_import_SUITE_data/case9/case9a.json new file mode 100644 index 0000000000..2e7a77962d --- /dev/null +++ b/test/definition_import_SUITE_data/case9/case9a.json @@ -0,0 +1 @@ +{"rabbit_version":"3.7.13","users":[{"name":"langohr","password_hash":"7p9PXlsYs92NlHSdNgPoDXmN77NqeGpzCTHpElq/wPS1eAEd","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"bunny_reader","password_hash":"ExmGdjBTmQEPxcW2z+dsOuPvjFbTBiYQgMByzfpE/IIXplYG","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"bunny_gem","password_hash":"8HH7uxmZS3FDldlYmHpFEE5+gWaeQaim8qpWIHkmNxuQK8xO","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"guest","password_hash":"CPCbkNAHXgQ7vmrqwP9e7RWQsE8U2DqN7JA4ggS50c4LwDda","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"administrator"},{"name":"temp-user","password_hash":"CfUQkDeOYDrPkACDCjoF5zySbsXPIoMgNfv7FWfEpVFGegnL","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"management"}],"vhosts":[{"name":"langohr_testbed"},{"name":"bunny_testbed"},{"name":"/"}],"permissions":[{"user":"bunny_reader","vhost":"bunny_testbed","configure":"^---$","write":"^---$","read":".*"},{"user":"bunny_gem","vhost":"bunny_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"langohr","vhost":"langohr_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"bunny_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"langohr_testbed","configure":".*","write":".*","read":".*"},{"user":"langohr","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"temp-user","vhost":"/","configure":".*","write":".*","read":".*"}],"topic_permissions":[],"parameters":[],"global_parameters":[{"name":"cluster_name","value":"rabbit@localhost"}],"policies":[],"queues":[{"name":"bunny.basic_consume0.1364356981103202","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"return","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"q1","vhost":"/","durable":true,"auto_delete":false,"arguments":{}},{"name":"declareArgs-deliveries-dead-letter","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.rabbitmq-basic-nack","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.test.recovery.q1","vhost":"/","durable":true,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.client-named.durable.non-exclusive.non-auto-deleted","vhost":"/","durable":true,"auto_delete":false,"arguments":{}},{"name":"test.tx.rollback","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test-integration-declared-passive-queue","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.recover","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"amq.gen-7EZF7WjGIQFDoXexVF-e8w","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":1500}},{"name":"test.integration.channel.error","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"confirm","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.rabbitmq-message-ttl","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":100}},{"name":"declareWithTTL","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":9000000}},{"name":"test.tx.commit","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.get-ok","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.non-auto-deleted1","vhost":"/","durable":false,"auto_delete":true,"arguments":{}}],"exchanges":[{"name":"declareArgs-dead-letter","vhost":"/","type":"fanout","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic5","vhost":"/","type":"topic","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.extensions.altexchanges.direct1","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{"alternate-exchange":"langohr.extensions.altexchanges.fanout1"}},{"name":"langohr.tests.exchanges.fanout1","vhost":"/","type":"fanout","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct3","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic4","vhost":"/","type":"topic","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout3","vhost":"/","type":"fanout","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct4","vhost":"/","type":"direct","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic2","vhost":"/","type":"topic","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"test-integration-declared-passive-exchange","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"test-channel-still-exists","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic1","vhost":"/","type":"topic","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout2","vhost":"/","type":"fanout","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct1","vhost":"/","type":"direct","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct2","vhost":"/","type":"direct","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.headers2","vhost":"/","type":"headers","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic3","vhost":"/","type":"topic","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.test.recovery.fanout1","vhost":"/","type":"fanout","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout4","vhost":"/","type":"fanout","durable":false,"auto_delete":false,"internal":false,"arguments":{}}],"bindings":[{"source":"amq.fanout","vhost":"/","destination":"langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted","destination_type":"queue","routing_key":"","arguments":{}},{"source":"declareArgs-dead-letter","vhost":"/","destination":"declareArgs-deliveries-dead-letter","destination_type":"queue","routing_key":"#","arguments":{}}]}
\ No newline at end of file diff --git a/test/definition_import_SUITE_data/case9/case9b.json b/test/definition_import_SUITE_data/case9/case9b.json new file mode 100644 index 0000000000..7cadd58b17 --- /dev/null +++ b/test/definition_import_SUITE_data/case9/case9b.json @@ -0,0 +1 @@ +{"rabbit_version":"3.7.13","users":[{"name":"langohr","password_hash":"7p9PXlsYs92NlHSdNgPoDXmN77NqeGpzCTHpElq/wPS1eAEd","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"bunny_reader","password_hash":"ExmGdjBTmQEPxcW2z+dsOuPvjFbTBiYQgMByzfpE/IIXplYG","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"bunny_gem","password_hash":"8HH7uxmZS3FDldlYmHpFEE5+gWaeQaim8qpWIHkmNxuQK8xO","hashing_algorithm":"rabbit_password_hashing_sha256","tags":""},{"name":"guest2","password_hash":"E04A7cvvsaDJBezc3Sc2jCnywe9oS4DX18qFe4dwkjIr26gf","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"monitoring"},{"name":"guest","password_hash":"CPCbkNAHXgQ7vmrqwP9e7RWQsE8U2DqN7JA4ggS50c4LwDda","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"administrator"},{"name":"temp-user","password_hash":"CfUQkDeOYDrPkACDCjoF5zySbsXPIoMgNfv7FWfEpVFGegnL","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"management"}],"vhosts":[{"name":"langohr_testbed"},{"name":"bunny_testbed"},{"name":"/"},{"name":"vhost3"}],"permissions":[{"user":"bunny_reader","vhost":"bunny_testbed","configure":"^---$","write":"^---$","read":".*"},{"user":"bunny_gem","vhost":"bunny_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"langohr","vhost":"langohr_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"bunny_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"langohr_testbed","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"vhost3","configure":".*","write":".*","read":".*"},{"user":"langohr","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"temp-user","vhost":"/","configure":".*","write":".*","read":".*"}],"topic_permissions":[],"parameters":[{"value":{"max-connections":2000},"vhost":"/","component":"vhost-limits","name":"limits"}],"global_parameters":[{"name":"cluster_name","value":"rabbit@localhost"}],"policies":[],"queues":[{"name":"bunny.basic_consume0.7103611911099639","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.6091120557781405","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.8661861002262826","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.3682573609392056","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.14855593896585362","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.9534242141484872","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.9434723539955824","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.12235844522013617","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.8370997977912426","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.4548488370639835","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.2289868670635532","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.00797124769641977","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"amq.gen-xddEPq9wHSNZKQbPK8pi3A","vhost":"bunny_testbed","durable":false,"auto_delete":false,"arguments":{}},{"name":"bunny.basic_consume0.5195700828676673","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"bunny.basic_consume0.3071859764599716","vhost":"bunny_testbed","durable":false,"auto_delete":true,"arguments":{}},{"name":"return","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"q1","vhost":"/","durable":true,"auto_delete":false,"arguments":{}},{"name":"declareArgs-deliveries-dead-letter","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.rabbitmq-basic-nack","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.test.recovery.q1","vhost":"/","durable":true,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.client-named.durable.non-exclusive.non-auto-deleted","vhost":"/","durable":true,"auto_delete":false,"arguments":{}},{"name":"test.tx.rollback","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test-integration-declared-passive-queue","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.recover","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"amq.gen-7EZF7WjGIQFDoXexVF-e8w","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":1500}},{"name":"test.integration.channel.error","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"confirm","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.rabbitmq-message-ttl","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":100}},{"name":"declareWithTTL","vhost":"/","durable":false,"auto_delete":true,"arguments":{"x-message-ttl":9000000}},{"name":"test.tx.commit","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"test.get-ok","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"langohr.tests2.queues.non-auto-deleted1","vhost":"/","durable":false,"auto_delete":true,"arguments":{}},{"name":"qv3","vhost":"vhost3","durable":true,"auto_delete":false,"arguments":{}}],"exchanges":[{"name":"bunny.tests.exchanges.fanout","vhost":"bunny_testbed","type":"fanout","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"declareArgs-dead-letter","vhost":"/","type":"fanout","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic5","vhost":"/","type":"topic","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.extensions.altexchanges.direct1","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{"alternate-exchange":"langohr.extensions.altexchanges.fanout1"}},{"name":"langohr.tests.exchanges.fanout1","vhost":"/","type":"fanout","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct3","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic4","vhost":"/","type":"topic","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.test.recovery.fanout2","vhost":"/","type":"fanout","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout3","vhost":"/","type":"fanout","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct4","vhost":"/","type":"direct","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic2","vhost":"/","type":"topic","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"test-integration-declared-passive-exchange","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"test-channel-still-exists","vhost":"/","type":"direct","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic1","vhost":"/","type":"topic","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout2","vhost":"/","type":"fanout","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct1","vhost":"/","type":"direct","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.direct2","vhost":"/","type":"direct","durable":true,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.headers2","vhost":"/","type":"headers","durable":false,"auto_delete":false,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.topic3","vhost":"/","type":"topic","durable":false,"auto_delete":true,"internal":false,"arguments":{}},{"name":"langohr.tests.exchanges.fanout4","vhost":"/","type":"fanout","durable":false,"auto_delete":false,"internal":false,"arguments":{}}],"bindings":[{"source":"amq.fanout","vhost":"/","destination":"langohr.tests2.queues.client-named.non-durable.non-exclusive.auto-deleted","destination_type":"queue","routing_key":"","arguments":{}},{"source":"declareArgs-dead-letter","vhost":"/","destination":"declareArgs-deliveries-dead-letter","destination_type":"queue","routing_key":"#","arguments":{}}]}
\ No newline at end of file diff --git a/test/unit_SUITE.erl b/test/unit_SUITE.erl index 3ffe3f013e..2bea590342 100644 --- a/test/unit_SUITE.erl +++ b/test/unit_SUITE.erl @@ -49,6 +49,7 @@ groups() -> rabbitmqctl_encode, pmerge, plmerge, + merge_operator_policy_definitions, priority_queue, rabbit_direct_extract_extra_auth_props, {resource_monitor, [parallel], [ @@ -809,6 +810,76 @@ plmerge(_Config) -> [{a, 1}, {b, 2}, {c, 3}, {d, 4}] = rabbit_misc:plmerge(P1, P2), passed. +merge_operator_policy_definitions(_Config) -> + P1 = undefined, + P2 = [{definition, [{<<"message-ttl">>, 3000}]}], + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, P2)), + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P2, P1)), + + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(P1, rabbit_data_coercion:to_map(P2))), + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions(rabbit_data_coercion:to_map(P2), P1)), + + ?assertEqual(undefined, rabbit_policy:merge_operator_definitions(undefined, undefined)), + + ?assertEqual([], rabbit_policy:merge_operator_definitions([], [])), + ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, [])), + ?assertEqual([], rabbit_policy:merge_operator_definitions(#{}, #{})), + ?assertEqual([], rabbit_policy:merge_operator_definitions([], #{})), + + %% operator policy takes precedence + ?assertEqual([{<<"message-ttl">>, 3000}], rabbit_policy:merge_operator_definitions( + [{definition, [ + {<<"message-ttl">>, 5000} + ]}], + [{definition, [ + {<<"message-ttl">>, 3000} + ]}] + )), + + ?assertEqual([{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}], + rabbit_policy:merge_operator_definitions( + [{definition, [ + {<<"message-ttl">>, 5000}, + {<<"delivery-limit">>, 20} + ]}], + [{definition, [ + {<<"message-ttl">>, 3000} + ]}]) + ), + + ?assertEqual( + [{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}, + {<<"unknown">>, <<"value">>}], + + rabbit_policy:merge_operator_definitions( + #{definition => #{ + <<"message-ttl">> => 5000, + <<"delivery-limit">> => 20 + }}, + #{definition => #{ + <<"message-ttl">> => 3000, + <<"unknown">> => <<"value">> + }}) + ), + + ?assertEqual( + [{<<"delivery-limit">>, 20}, + {<<"message-ttl">>, 3000}], + + rabbit_policy:merge_operator_definitions( + #{definition => #{ + <<"message-ttl">> => 5000, + <<"delivery-limit">> => 20 + }}, + [{definition, [ + {<<"message-ttl">>, 3000} + ]}]) + ), + + passed. + table_codec(_Config) -> %% FIXME this does not test inexact numbers (double and float) yet, %% because they won't pass the equality assertions |
