diff options
| author | Michael Klishin <mklishin@pivotal.io> | 2016-10-14 07:32:40 +0800 |
|---|---|---|
| committer | Michael Klishin <mklishin@pivotal.io> | 2016-10-14 07:32:40 +0800 |
| commit | 0454457f4ef429d6b9d0337aa43fa738da3b5d72 (patch) | |
| tree | c6c8acb02f6e9b1dfc017ad90782f4b56f948ab6 | |
| parent | 45c728a4a5b637521a17f0472ed29a2a4187763a (diff) | |
| parent | fdd9f295d8b33a0774b3fa1f9753ff044fcfee15 (diff) | |
| download | rabbitmq-server-git-0454457f4ef429d6b9d0337aa43fa738da3b5d72.tar.gz | |
Merge branch 'master' into rabbitmq-server-486
Conflicts:
src/rabbit.app.src
29 files changed, 910 insertions, 2020 deletions
diff --git a/.gitignore b/.gitignore index c3358da939..7af1ad4260 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ /logs/ /plugins/ /test/ct.cover.spec +/test/config_schema_SUITE_data/schema/** /xrefr rabbit.d diff --git a/docs/rabbitmq.conf.example b/docs/rabbitmq.conf.example index 7e60c53da4..f03145b447 100644 --- a/docs/rabbitmq.conf.example +++ b/docs/rabbitmq.conf.example @@ -307,14 +307,14 @@ ## See http://www.rabbitmq.com/clustering.html#auto-config for ## further details. ## -# cluster_nodes.disc.rabbit = rabbit@my.host.com - -## You can define multiple nodes -# cluster_nodes.disc.hare = hare@my.host.com - -## There can be also ram nodes. -## Ram nodes should not be defined together with disk nodes -# cluster_nodes.ram.rabbit = rabbit@my.host.com +# autocluster.classic_config.nodes.node1 = rabbit1@hostname +# autocluster.classic_config.nodes.node2 = rabbit2@hostname +# autocluster.classic_config.nodes.node3 = rabbit3@hostname +# autocluster.classic_config.nodes.node4 = rabbit4@hostname + +## This node's type can be configured. If you are not sure +## what node type to use, always use 'disc'. +# autocluster.classic_config.node_type = disc ## Interval (in milliseconds) at which we send keepalive messages ## to other cluster members. Note that this is not the same thing diff --git a/include/rabbit_cli.hrl b/include/rabbit_cli.hrl index 19cae2fc0a..53be9fcda0 100644 --- a/include/rabbit_cli.hrl +++ b/include/rabbit_cli.hrl @@ -31,6 +31,13 @@ -define(ONLINE_OPT, "--online"). -define(LOCAL_OPT, "--local"). +-define(DECODE_OPT, "--decode"). +-define(CIPHER_OPT, "--cipher"). +-define(HASH_OPT, "--hash"). +-define(ITERATIONS_OPT, "--iterations"). +-define(LIST_CIPHERS_OPT, "--list-ciphers"). +-define(LIST_HASHES_OPT, "--list-hashes"). + -define(NODE_DEF(Node), {?NODE_OPT, {option, Node}}). -define(QUIET_DEF, {?QUIET_OPT, flag}). -define(VHOST_DEF, {?VHOST_OPT, {option, "/"}}). @@ -47,6 +54,13 @@ -define(OFFLINE_DEF, {?OFFLINE_OPT, flag}). -define(ONLINE_DEF, {?ONLINE_OPT, flag}). -define(LOCAL_DEF, {?LOCAL_OPT, flag}). +-define(DECODE_DEF, {?DECODE_OPT, flag}). +-define(CIPHER_DEF, {?CIPHER_OPT, {option, atom_to_list(rabbit_pbe:default_cipher())}}). +-define(HASH_DEF, {?HASH_OPT, {option, atom_to_list(rabbit_pbe:default_hash())}}). +-define(ITERATIONS_DEF, {?ITERATIONS_OPT, {option, integer_to_list(rabbit_pbe:default_iterations())}}). +-define(LIST_CIPHERS_DEF, {?LIST_CIPHERS_OPT, flag}). +-define(LIST_HASHES_DEF, {?LIST_HASHES_OPT, flag}). + %% Subset of standartized exit codes from sysexits.h, see %% https://github.com/rabbitmq/rabbitmq-server/issues/396 for discussion. diff --git a/priv/schema/rabbitmq.schema b/priv/schema/rabbitmq.schema index bf9cccbcb8..687101dd74 100644 --- a/priv/schema/rabbitmq.schema +++ b/priv/schema/rabbitmq.schema @@ -764,20 +764,27 @@ end}. %% %% {cluster_nodes, {['rabbit@my.host.com'], disc}}, -{mapping, "cluster_nodes.disc.$node", "rabbit.cluster_nodes", +{mapping, "autocluster.classic_config.nodes.$node", "rabbit.cluster_nodes", [{datatype, atom}]}. -{mapping, "cluster_nodes.ram.$node", "rabbit.cluster_nodes", - [{datatype, atom}]}. +{mapping, "autocluster.classic_config.node_type", "rabbit.cluster_nodes", [ + {datatype, {enum, [disc, disk, ram]}}, + {default, disc} +]}. {translation, "rabbit.cluster_nodes", fun(Conf) -> - DiskNodes = [ V || {_, V} <- cuttlefish_variable:filter_by_prefix("cluster_nodes.disc", Conf)], - RamNodes = [ V || {_, V} <- cuttlefish_variable:filter_by_prefix("cluster_nodes.ram", Conf)], - - case {DiskNodes, RamNodes} of - {_, []} -> {DiskNodes, disc}; - {[], _} -> {RamNodes, ram} + Nodes = [V || {_, V} <- cuttlefish_variable:filter_by_prefix("autocluster.classic_config.nodes", Conf)], + + case Nodes of + [] -> cuttlefish:unset(); + Other -> + case cuttlefish:conf_get("autocluster.classic_config.node_type", Conf, disc) of + disc -> {Other, disc}; + % Always cast to `disc` + disk -> {Other, disc}; + ram -> {Other, ram} + end end end}. diff --git a/src/rabbit.app.src b/src/rabbit.app.src index 87401662c8..b22ef7ae5b 100644 --- a/src/rabbit.app.src +++ b/src/rabbit.app.src @@ -108,6 +108,13 @@ %% used by rabbit_peer_discovery_classic_config {cluster_nodes, {[], disc}}, + {decoder_config, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, undefined} + ]}, + %% rabbitmq-server-973 {lazy_queue_explicit_gc_run_operation_threshold, 250} ]}]}. diff --git a/src/rabbit.erl b/src/rabbit.erl index 5db2c40b66..089fc0dd1c 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -24,7 +24,7 @@ start_fhc/0]). -export([start/2, stop/1, prep_stop/1]). -export([start_apps/1, stop_apps/1]). --export([log_locations/0, config_files/0]). %% for testing and mgmt-agent +-export([log_locations/0, config_files/0, decrypt_config/2]). %% for testing and mgmt-agent -ifdef(TEST). @@ -465,6 +465,38 @@ stop_and_halt() -> start_apps(Apps) -> app_utils:load_applications(Apps), + + DecoderConfig = case application:get_env(rabbit, decoder_config) of + undefined -> + []; + {ok, Val} -> + Val + end, + PassPhrase = case proplists:get_value(passphrase, DecoderConfig) of + prompt -> + IoDevice = get_input_iodevice(), + io:setopts(IoDevice, [{echo, false}]), + PP = lists:droplast(io:get_line(IoDevice, + "\nPlease enter the passphrase to unlock encrypted " + "configuration entries.\n\nPassphrase: ")), + io:setopts(IoDevice, [{echo, true}]), + io:format(IoDevice, "~n", []), + PP; + {file, Filename} -> + {ok, File} = file:read_file(Filename), + [PP|_] = binary:split(File, [<<"\r\n">>, <<"\n">>]), + PP; + PP -> + PP + end, + Algo = { + proplists:get_value(cipher, DecoderConfig, rabbit_pbe:default_cipher()), + proplists:get_value(hash, DecoderConfig, rabbit_pbe:default_hash()), + proplists:get_value(iterations, DecoderConfig, rabbit_pbe:default_iterations()), + PassPhrase + }, + decrypt_config(Apps, Algo), + OrderedApps = app_utils:app_dependency_order(Apps, false), case lists:member(rabbit, Apps) of false -> rabbit_boot_steps:run_boot_steps(Apps); %% plugin activation @@ -473,6 +505,78 @@ start_apps(Apps) -> ok = app_utils:start_applications(OrderedApps, handle_app_error(could_not_start)). +%% This function retrieves the correct IoDevice for requesting +%% input. The problem with using the default IoDevice is that +%% the Erlang shell prevents us from getting the input. +%% +%% Instead we therefore look for the io process used by the +%% shell and if it can't be found (because the shell is not +%% started e.g with -noshell) we use the 'user' process. +%% +%% This function will not work when either -oldshell or -noinput +%% options are passed to erl. +get_input_iodevice() -> + case whereis(user) of + undefined -> user; + User -> + case group:interfaces(User) of + [] -> + user; + [{user_drv, Drv}] -> + case user_drv:interfaces(Drv) of + [] -> + user; + [{current_group, IoDevice}] -> + IoDevice + end + end + end. + +decrypt_config([], _) -> + ok; +decrypt_config([App|Apps], Algo) -> + decrypt_app(App, application:get_all_env(App), Algo), + decrypt_config(Apps, Algo). + +decrypt_app(_, [], _) -> + ok; +decrypt_app(App, [{Key, Value}|Tail], Algo) -> + try begin + case decrypt(Value, Algo) of + Value -> + ok; + NewValue -> + application:set_env(App, Key, NewValue) + end + end + catch + exit:{bad_configuration, decoder_config} -> + exit({bad_configuration, decoder_config}); + _:Msg -> + rabbit_log:info("Error while decrypting key '~p'. Please check encrypted value, passphrase, and encryption configuration~n", [Key]), + exit({decryption_error, {key, Key}, Msg}) + end, + decrypt_app(App, Tail, Algo). + +decrypt({encrypted, _}, {_, _, _, undefined}) -> + exit({bad_configuration, decoder_config}); +decrypt({encrypted, EncValue}, {Cipher, Hash, Iterations, Password}) -> + rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, Password, EncValue); +decrypt(List, Algo) when is_list(List) -> + decrypt_list(List, Algo, []); +decrypt(Value, _) -> + Value. + +%% We make no distinction between strings and other lists. +%% When we receive a string, we loop through each element +%% and ultimately return the string unmodified, as intended. +decrypt_list([], _, Acc) -> + lists:reverse(Acc); +decrypt_list([{Key, Value}|Tail], Algo, Acc) when Key =/= encrypted -> + decrypt_list(Tail, Algo, [{Key, decrypt(Value, Algo)}|Acc]); +decrypt_list([Value|Tail], Algo, Acc) -> + decrypt_list(Tail, Algo, [decrypt(Value, Algo)|Acc]). + stop_apps(Apps) -> ok = app_utils:stop_applications( Apps, handle_app_error(error_during_shutdown)), diff --git a/src/rabbit_control_main.erl b/src/rabbit_control_main.erl index f48f0349aa..1619f25494 100644 --- a/src/rabbit_control_main.erl +++ b/src/rabbit_control_main.erl @@ -97,7 +97,8 @@ {trace_off, [?VHOST_DEF]}, set_vm_memory_high_watermark, set_disk_free_limit, - help + help, + {encode, [?DECODE_DEF, ?CIPHER_DEF, ?HASH_DEF, ?ITERATIONS_DEF, ?LIST_CIPHERS_DEF, ?LIST_HASHES_DEF]} ]). -define(GLOBAL_QUERIES, @@ -119,7 +120,7 @@ [stop, stop_app, start_app, wait, reset, force_reset, rotate_logs, join_cluster, change_cluster_node_type, update_cluster_nodes, forget_cluster_node, rename_cluster_node, cluster_status, status, - environment, eval, force_boot, help, hipe_compile]). + environment, eval, force_boot, help, hipe_compile, encode]). %% [Command | {Command, DefaultTimeoutInMilliSeconds}] -define(COMMANDS_WITH_TIMEOUT, @@ -613,6 +614,17 @@ action(eval, Node, [Expr], _Opts, _Inform) -> action(help, _Node, _Args, _Opts, _Inform) -> io:format("~s", [rabbit_ctl_usage:usage()]); +action(encode, _Node, Args, Opts, _Inform) -> + ListCiphers = lists:member({?LIST_CIPHERS_OPT, true}, Opts), + ListHashes = lists:member({?LIST_HASHES_OPT, true}, Opts), + Decode = lists:member({?DECODE_OPT, true}, Opts), + Cipher = list_to_atom(proplists:get_value(?CIPHER_OPT, Opts)), + Hash = list_to_atom(proplists:get_value(?HASH_OPT, Opts)), + Iterations = list_to_integer(proplists:get_value(?ITERATIONS_OPT, Opts)), + + {_, Msg} = rabbit_control_pbe:encode(ListCiphers, ListHashes, Decode, Cipher, Hash, Iterations, Args), + io:format(Msg ++ "~n"); + action(Command, Node, Args, Opts, Inform) -> %% For backward compatibility, run commands accepting a timeout with %% the default timeout. diff --git a/src/rabbit_control_pbe.erl b/src/rabbit_control_pbe.erl new file mode 100644 index 0000000000..2fa2c90a6e --- /dev/null +++ b/src/rabbit_control_pbe.erl @@ -0,0 +1,79 @@ +% 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 http://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-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_control_pbe). + +-export([encode/7]). + +% for testing purposes +-export([evaluate_input_as_term/1]). + +encode(ListCiphers, _ListHashes, _Decode, _Cipher, _Hash, _Iterations, _Args) when ListCiphers -> + {ok, io_lib:format("~p", [rabbit_pbe:supported_ciphers()])}; + +encode(_ListCiphers, ListHashes, _Decode, _Cipher, _Hash, _Iterations, _Args) when ListHashes -> + {ok, io_lib:format("~p", [rabbit_pbe:supported_hashes()])}; + +encode(_ListCiphers, _ListHashes, Decode, Cipher, Hash, Iterations, Args) -> + CipherExists = lists:member(Cipher, rabbit_pbe:supported_ciphers()), + HashExists = lists:member(Hash, rabbit_pbe:supported_hashes()), + encode_encrypt_decrypt(CipherExists, HashExists, Decode, Cipher, Hash, Iterations, Args). + +encode_encrypt_decrypt(CipherExists, _HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) when CipherExists =:= false -> + {error, io_lib:format("The requested cipher is not supported", [])}; + +encode_encrypt_decrypt(_CipherExists, HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) when HashExists =:= false -> + {error, io_lib:format("The requested hash is not supported", [])}; + +encode_encrypt_decrypt(_CipherExists, _HashExists, _Decode, _Cipher, _Hash, Iterations, _Args) when Iterations =< 0 -> + {error, io_lib:format("The requested number of iterations is incorrect", [])}; + +encode_encrypt_decrypt(_CipherExists, _HashExists, Decode, Cipher, Hash, Iterations, Args) when length(Args) == 2, Decode =:= false -> + [Value, PassPhrase] = Args, + try begin + TermValue = evaluate_input_as_term(Value), + Result = rabbit_pbe:encrypt_term(Cipher, Hash, Iterations, list_to_binary(PassPhrase), TermValue), + {ok, io_lib:format("~p", [{encrypted, Result}])} + end + catch + _:Msg -> {error, io_lib:format("Error during cipher operation: ~p", [Msg])} + end; + +encode_encrypt_decrypt(_CipherExists, _HashExists, Decode, Cipher, Hash, Iterations, Args) when length(Args) == 2, Decode -> + [Value, PassPhrase] = Args, + try begin + TermValue = evaluate_input_as_term(Value), + TermToDecrypt = case TermValue of + {encrypted, EncryptedTerm} -> + EncryptedTerm; + _ -> + TermValue + end, + Result = rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, list_to_binary(PassPhrase), TermToDecrypt), + {ok, io_lib:format("~p", [Result])} + end + catch + _:Msg -> {error, io_lib:format("Error during cipher operation: ~p", [Msg])} + end; + +encode_encrypt_decrypt(_CipherExists, _HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) -> + {error, io_lib:format("Please provide a value to encode/decode and a passphrase", [])}. + +evaluate_input_as_term(Input) -> + {ok,Tokens,_EndLine} = erl_scan:string(Input ++ "."), + {ok,AbsForm} = erl_parse:parse_exprs(Tokens), + {value,TermValue,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()), + TermValue. diff --git a/src/rabbit_mirror_queue_mode_nodes.erl b/src/rabbit_mirror_queue_mode_nodes.erl index e63f340373..31c55722a5 100644 --- a/src/rabbit_mirror_queue_mode_nodes.erl +++ b/src/rabbit_mirror_queue_mode_nodes.erl @@ -32,29 +32,37 @@ description() -> [{description, <<"Mirror queue to specified nodes">>}]. -suggested_queue_nodes(Nodes0, MNode, _SNodes, SSNodes, Poss) -> - Nodes1 = [list_to_atom(binary_to_list(Node)) || Node <- Nodes0], +suggested_queue_nodes(PolicyNodes0, CurrentMaster, _SNodes, SSNodes, NodesRunningRabbitMQ) -> + PolicyNodes1 = [list_to_atom(binary_to_list(Node)) || Node <- PolicyNodes0], %% If the current master is not in the nodes specified, then what we want %% to do depends on whether there are any synchronised slaves. If there %% are then we can just kill the current master - the admin has asked for %% a migration and we should give it to them. If there are not however %% then we must keep the master around so as not to lose messages. - Nodes = case SSNodes of - [] -> lists:usort([MNode | Nodes1]); - _ -> Nodes1 - end, - Unavailable = Nodes -- Poss, - Available = Nodes -- Unavailable, - case Available of + + PolicyNodes = case SSNodes of + [] -> lists:usort([CurrentMaster | PolicyNodes1]); + _ -> PolicyNodes1 + end, + Unavailable = PolicyNodes -- NodesRunningRabbitMQ, + AvailablePolicyNodes = PolicyNodes -- Unavailable, + case AvailablePolicyNodes of [] -> %% We have never heard of anything? Not much we can do but %% keep the master alive. - {MNode, []}; - _ -> case lists:member(MNode, Available) of - true -> {MNode, Available -- [MNode]}; + {CurrentMaster, []}; + _ -> case lists:member(CurrentMaster, AvailablePolicyNodes) of + true -> {CurrentMaster, + AvailablePolicyNodes -- [CurrentMaster]}; false -> %% Make sure the new master is synced! In order to %% get here SSNodes must not be empty. - [NewMNode | _] = SSNodes, - {NewMNode, Available -- [NewMNode]} + SyncPolicyNodes = [Node || + Node <- AvailablePolicyNodes, + lists:member(Node, SSNodes)], + NewMaster = case SyncPolicyNodes of + [Node | _] -> Node; + [] -> erlang:hd(SSNodes) + end, + {NewMaster, AvailablePolicyNodes -- [NewMaster]} end end. diff --git a/src/rabbit_pbe.erl b/src/rabbit_pbe.erl new file mode 100644 index 0000000000..f4998d4a13 --- /dev/null +++ b/src/rabbit_pbe.erl @@ -0,0 +1,194 @@ +%% 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 http://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-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_pbe). + +-export([supported_ciphers/0, supported_hashes/0, default_cipher/0, default_hash/0, default_iterations/0]). +-export([encrypt_term/5, decrypt_term/5]). +-export([encrypt/5, decrypt/5]). + +%% Supported ciphers and hashes + +supported_ciphers() -> + proplists:get_value(ciphers, crypto:supports()) + -- [aes_ctr, aes_ecb, des_ecb, blowfish_ecb, rc4, aes_gcm]. + +supported_hashes() -> + proplists:get_value(hashs, crypto:supports()) + -- [md4, ripemd160]. + +%% Default encryption parameters (keep those in sync with rabbit.app.src) +default_cipher() -> + aes_cbc256. + +default_hash() -> + sha512. + +default_iterations() -> + 1000. + +%% Encryption/decryption of arbitrary Erlang terms. + +encrypt_term(Cipher, Hash, Iterations, PassPhrase, Term) -> + encrypt(Cipher, Hash, Iterations, PassPhrase, term_to_binary(Term)). + +decrypt_term(Cipher, Hash, Iterations, PassPhrase, Base64Binary) -> + binary_to_term(decrypt(Cipher, Hash, Iterations, PassPhrase, Base64Binary)). + +%% The cipher for encryption is from the list of supported ciphers. +%% The hash for generating the key from the passphrase is from the list +%% of supported hashes. See crypto:supports/0 to obtain both lists. +%% The key is generated by applying the hash N times with N >= 1. +%% +%% The encrypt/5 function returns a base64 binary and the decrypt/5 +%% function accepts that same base64 binary. + +-spec encrypt(crypto:block_cipher(), crypto:hash_algorithms(), + pos_integer(), iodata(), binary()) -> binary(). +encrypt(Cipher, Hash, Iterations, PassPhrase, ClearText) -> + Salt = crypto:strong_rand_bytes(16), + Ivec = crypto:strong_rand_bytes(iv_length(Cipher)), + Key = make_key(Cipher, Hash, Iterations, PassPhrase, Salt), + Binary = crypto:block_encrypt(Cipher, Key, Ivec, pad(Cipher, ClearText)), + base64:encode(<< Salt/binary, Ivec/binary, Binary/binary >>). + +-spec decrypt(crypto:block_cipher(), crypto:hash_algorithms(), + pos_integer(), iodata(), binary()) -> binary(). +decrypt(Cipher, Hash, Iterations, PassPhrase, Base64Binary) -> + IvLength = iv_length(Cipher), + << Salt:16/binary, Ivec:IvLength/binary, Binary/bits >> = base64:decode(Base64Binary), + Key = make_key(Cipher, Hash, Iterations, PassPhrase, Salt), + unpad(crypto:block_decrypt(Cipher, Key, Ivec, Binary)). + +%% Generate a key from a passphrase. + +make_key(Cipher, Hash, Iterations, PassPhrase, Salt) -> + Key = pbdkdf2(PassPhrase, Salt, Iterations, key_length(Cipher), + fun crypto:hmac/4, Hash, hash_length(Hash)), + if + Cipher =:= des3_cbc; Cipher =:= des3_cbf; Cipher =:= des3_cfb; Cipher =:= des_ede3 -> + << A:8/binary, B:8/binary, C:8/binary >> = Key, + [A, B, C]; + true -> + Key + end. + +%% Functions to pad/unpad input to a multiplier of block size. + +pad(Cipher, Data) -> + BlockSize = block_size(Cipher), + N = BlockSize - (byte_size(Data) rem BlockSize), + Pad = list_to_binary(lists:duplicate(N, N)), + <<Data/binary, Pad/binary>>. + +unpad(Data) -> + N = binary:last(Data), + binary:part(Data, 0, byte_size(Data) - N). + +%% These functions are necessary because the current Erlang crypto interface +%% is lacking interfaces to the following OpenSSL functions: +%% +%% * int EVP_MD_size(const EVP_MD *md); +%% * int EVP_CIPHER_iv_length(const EVP_CIPHER *e); +%% * int EVP_CIPHER_key_length(const EVP_CIPHER *e); +%% * int EVP_CIPHER_block_size(const EVP_CIPHER *e); + +hash_length(md4) -> 16; +hash_length(md5) -> 16; +hash_length(sha) -> 20; +hash_length(sha224) -> 28; +hash_length(sha256) -> 32; +hash_length(sha384) -> 48; +hash_length(sha512) -> 64. + +iv_length(des_cbc) -> 8; +iv_length(des_cfb) -> 8; +iv_length(des3_cbc) -> 8; +iv_length(des3_cbf) -> 8; +iv_length(des3_cfb) -> 8; +iv_length(des_ede3) -> 8; +iv_length(blowfish_cbc) -> 8; +iv_length(blowfish_cfb64) -> 8; +iv_length(blowfish_ofb64) -> 8; +iv_length(rc2_cbc) -> 8; +iv_length(aes_cbc) -> 16; +iv_length(aes_cbc128) -> 16; +iv_length(aes_cfb8) -> 16; +iv_length(aes_cfb128) -> 16; +iv_length(aes_cbc256) -> 16; +iv_length(aes_ige256) -> 32. + +key_length(des_cbc) -> 8; +key_length(des_cfb) -> 8; +key_length(des3_cbc) -> 24; +key_length(des3_cbf) -> 24; +key_length(des3_cfb) -> 24; +key_length(des_ede3) -> 24; +key_length(blowfish_cbc) -> 16; +key_length(blowfish_cfb64) -> 16; +key_length(blowfish_ofb64) -> 16; +key_length(rc2_cbc) -> 16; +key_length(aes_cbc) -> 16; +key_length(aes_cbc128) -> 16; +key_length(aes_cfb8) -> 16; +key_length(aes_cfb128) -> 16; +key_length(aes_cbc256) -> 32; +key_length(aes_ige256) -> 16. + +block_size(aes_cbc256) -> 32; +block_size(aes_cbc128) -> 32; +block_size(aes_ige256) -> 32; +block_size(aes_cbc) -> 32; +block_size(_) -> 8. + +%% The following was taken from OTP's lib/public_key/src/pubkey_pbe.erl +%% +%% This is an undocumented interface to password-based encryption algorithms. +%% These functions have been copied here to stay compatible with R16B03. + +%%-------------------------------------------------------------------- +-spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), atom(), integer()) + -> binary(). +%% +%% Description: Implements password based decryption key derive function 2. +%% Exported mainly for testing purposes. +%%-------------------------------------------------------------------- +pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfHash, PrfOutputLen)-> + NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen), + NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen , + blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt, + Count, Prf, PrfHash, PrfOutputLen, <<>>). + +blocks(1, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) -> + <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen), + <<Acc/binary, XorSum/binary>>; +blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) -> + XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen), + blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf, PrfHash, + PrfLen, <<Acc/binary, XorSum/binary>>). + +xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen) -> + Result = Prf(PrfHash, Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen), + do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, Result). + +do_xor_sum(_, _, _, _, _, 0, Acc) -> + Acc; +do_xor_sum(Prf, PrfHash, PrfLen, Prev, Password, Count, Acc) -> + Result = Prf(PrfHash, Password, Prev, PrfLen), + do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)). + +ceiling(Float) -> + erlang:round(Float + 0.5). diff --git a/src/rabbit_vhost_limit.erl b/src/rabbit_vhost_limit.erl index bd79f4dd45..b933c31402 100644 --- a/src/rabbit_vhost_limit.erl +++ b/src/rabbit_vhost_limit.erl @@ -21,12 +21,14 @@ -include("rabbit.hrl"). -export([register/0]). --export([parse_set/2, clear/1]). +-export([parse_set/2, set/2, clear/1]). +-export([list/0, list/1]). +-export([update_limit/3, clear_limit/2, get_limit/2]). -export([validate/5, notify/4, notify_clear/3]). -export([connection_limit/1, queue_limit/1, is_over_queue_limit/1, is_over_connection_limit/1]). --import(rabbit_misc, [pget/2]). +-import(rabbit_misc, [pget/2, pget/3]). -rabbit_boot_step({?MODULE, [{description, "vhost limit parameters"}, @@ -57,6 +59,21 @@ connection_limit(VirtualHost) -> queue_limit(VirtualHost) -> get_limit(VirtualHost, <<"max-queues">>). +-spec list() -> [{rabbit_types:vhost(), rabbit_types:infos()}]. + +list() -> + case rabbit_runtime_parameters:list_component(<<"vhost-limits">>) of + [] -> []; + Params -> [ {pget(vhost, Param), pget(value, Param)} + || Param <- Params, + pget(value, Param) =/= undefined, + pget(name, Param) == <<"limits">> ] + end. + +-spec list(rabbit_types:vhost()) -> rabbit_types:infos(). + +list(VHost) -> + rabbit_runtime_parameters:value(VHost, <<"vhost-limits">>, <<"limits">>, []). -spec is_over_connection_limit(rabbit_types:vhost()) -> {true, non_neg_integer()} | false. @@ -122,6 +139,22 @@ clear(VHost) -> rabbit_runtime_parameters:clear_any(VHost, <<"vhost-limits">>, <<"limits">>). +update_limit(VHost, Name, Value) -> + OldDef = case rabbit_runtime_parameters:list(VHost, <<"vhost-limits">>) of + [] -> []; + [Param] -> pget(value, Param, []) + end, + NewDef = [{Name, Value} | lists:keydelete(Name, 1, OldDef)], + set(VHost, NewDef). + +clear_limit(VHost, Name) -> + OldDef = case rabbit_runtime_parameters:list(VHost, <<"vhost-limits">>) of + [] -> []; + [Param] -> pget(value, Param, []) + end, + NewDef = lists:keydelete(Name, 1, OldDef), + set(VHost, NewDef). + vhost_limit_validation() -> [{<<"max-connections">>, fun rabbit_parameter_validation:integer/2, optional}, {<<"max-queues">>, fun rabbit_parameter_validation:integer/2, optional}]. diff --git a/test/config_schema_SUITE.erl b/test/config_schema_SUITE.erl index 79e7220e98..09eb4678cd 100644 --- a/test/config_schema_SUITE.erl +++ b/test/config_schema_SUITE.erl @@ -39,7 +39,19 @@ groups() -> init_per_suite(Config) -> rabbit_ct_helpers:log_environment(), - rabbit_ct_helpers:run_setup_steps(Config). + Config1 = rabbit_ct_helpers:run_setup_steps(Config), + DepsDir = ?config(erlang_mk_depsdir, Config1), + Schemas = filelib:wildcard(DepsDir ++ "/*/priv/schema/*.schema"), + ct:pal("Schemas ~p~n", [Schemas]), + SchemaDir = filename:join(?config(data_dir, Config1), "schema"), + file:make_dir(SchemaDir), + ct:pal("Schema DIR ~p~n", [SchemaDir]), + [ copy_to(Schema, SchemaDir) || Schema <- Schemas ], + rabbit_ct_helpers:set_config(Config1, [{schema_dir, SchemaDir}]). + +copy_to(File, Dir) -> + BaseName = filename:basename(File), + {ok, _} = file:copy(File, Dir ++ "/" ++ BaseName). end_per_suite(Config) -> rabbit_ct_helpers:run_teardown_steps(Config). @@ -57,13 +69,11 @@ init_per_testcase(Testcase, Config) -> ]), Config2 = case Testcase of run_snippets -> - SchemaDir = filename:join(?config(data_dir, Config1), "schema"), ResultsDir = filename:join(?config(priv_dir, Config1), "results"), Snippets = filename:join(?config(data_dir, Config1), "snippets.config"), ok = file:make_dir(ResultsDir), rabbit_ct_helpers:set_config(Config1, [ - {schema_dir, SchemaDir}, {results_dir, ResultsDir}, {conf_snippets, Snippets} ]) @@ -89,12 +99,21 @@ run_snippets(Config) -> run_snippets1(Config) -> {ok, [Snippets]} = file:consult(?config(conf_snippets, Config)), lists:map( - fun({N, S, C, P}) -> ok = test_snippet(Config, {integer_to_list(N), S, []}, C, P); - ({N, S, A, C, P}) -> ok = test_snippet(Config, {integer_to_list(N), S, A}, C, P) + fun({N, S, C, P}) -> ok = test_snippet(Config, {snippet_id(N), S, []}, C, P); + ({N, S, A, C, P}) -> ok = test_snippet(Config, {snippet_id(N), S, A}, C, P) end, Snippets), passed. +snippet_id(N) when is_integer(N) -> + integer_to_list(N); +snippet_id(F) when is_float(F) -> + float_to_list(F); +snippet_id(A) when is_atom(A) -> + atom_to_list(A); +snippet_id(L) when is_list(L) -> + L. + test_snippet(Config, Snippet, Expected, _Plugins) -> {ConfFile, AdvancedFile} = write_snippet(Config, Snippet), {ok, GeneratedFile} = generate_config(Config, ConfFile, AdvancedFile), diff --git a/test/config_schema_SUITE_data/schema/rabbitmq.schema b/test/config_schema_SUITE_data/schema/rabbitmq.schema deleted file mode 100644 index bf9cccbcb8..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq.schema +++ /dev/null @@ -1,980 +0,0 @@ -% ============================== -% Rabbit app section -% ============================== - -%% -%% Network Connectivity -%% ==================== -%% - -%% By default, RabbitMQ will listen on all interfaces, using -%% the standard (reserved) AMQP port. -%% -%% {tcp_listeners, [5672]}, -%% To listen on a specific interface, provide a tuple of {IpAddress, Port}. -%% For example, to listen only on localhost for both IPv4 and IPv6: -%% -%% {tcp_listeners, [{"127.0.0.1", 5672}, -%% {"[::1]", 5672}]}, - -{mapping, "listeners.tcp", "rabbit.tcp_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "listeners.tcp.$name", "rabbit.tcp_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbit.tcp_listeners", -fun(Conf) -> - case cuttlefish:conf_get("listeners.tcp", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("listeners.tcp", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -%% SSL listeners are configured in the same fashion as TCP listeners, -%% including the option to control the choice of interface. -%% -%% {ssl_listeners, [5671]}, - -{mapping, "listeners.ssl", "rabbit.ssl_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "listeners.ssl.$name", "rabbit.ssl_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbit.ssl_listeners", -fun(Conf) -> - case cuttlefish:conf_get("listeners.ssl", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("listeners.ssl", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -%% Number of Erlang processes that will accept connections for the TCP -%% and SSL listeners. -%% -%% {num_tcp_acceptors, 10}, -%% {num_ssl_acceptors, 1}, - -{mapping, "num_acceptors.ssl", "rabbit.num_ssl_acceptors", [ - {datatype, integer} -]}. - -{mapping, "num_acceptors.tcp", "rabbit.num_tcp_acceptors", [ - {datatype, integer} -]}. - - -%% Maximum time for AMQP 0-8/0-9/0-9-1 handshake (after socket connection -%% and SSL handshake), in milliseconds. -%% -%% {handshake_timeout, 10000}, - -{mapping, "handshake_timeout", "rabbit.handshake_timeout", [ - {datatype, integer} -]}. - -%% Set to 'true' to perform reverse DNS lookups when accepting a -%% connection. Hostnames will then be shown instead of IP addresses -%% in rabbitmqctl and the management plugin. -%% -%% {reverse_dns_lookups, true}, - -{mapping, "reverse_dns_lookups", "rabbit.reverse_dns_lookups", [ - {datatype, {enum, [true, false]}} -]}. - -{mapping, "erlang.K", "vm_args.+K", [ - {default, "true"}, - {level, advanced} -]}. - -%% -%% Security / AAA -%% ============== -%% - -%% The default "guest" user is only permitted to access the server -%% via a loopback interface (e.g. localhost). -%% {loopback_users, [<<"guest">>]}, -%% -%% Uncomment the following line if you want to allow access to the -%% guest user from anywhere on the network. -%% {loopback_users, []}, - -{mapping, "loopback_users", "rabbit.loopback_users", [ - {datatype, {enum, [none]}} -]}. - -{mapping, "loopback_users.$user", "rabbit.loopback_users", [ - {datatype, atom} -]}. - -{translation, "rabbit.loopback_users", -fun(Conf) -> - None = cuttlefish:conf_get("loopback_users", Conf, undefined), - case None of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("loopback_users", Conf), - [ list_to_binary(U) || {["loopback_users", U], V} <- Settings, V == true ] - end -end}. - -%% Configuring SSL. -%% See http://www.rabbitmq.com/ssl.html for full documentation. -%% -%% {ssl_options, [{cacertfile, "/path/to/testca/cacert.pem"}, -%% {certfile, "/path/to/server/cert.pem"}, -%% {keyfile, "/path/to/server/key.pem"}, -%% {verify, verify_peer}, -%% {fail_if_no_peer_cert, false}]}, - -%% SSL options section ======================================================== - -{mapping, "ssl_allow_poodle_attack", "rabbit.ssl_allow_poodle_attack", -[{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options", "rabbit.ssl_options", [ - {datatype, {enum, [none]}} -]}. - -{translation, "rabbit.ssl_options", -fun(Conf) -> - case cuttlefish:conf_get("ssl_options", Conf, undefined) of - none -> []; - _ -> cuttlefish:invalid("Invalid ssl_options") - end -end}. - -{mapping, "ssl_options.verify", "rabbit.ssl_options.verify", [ - {datatype, {enum, [verify_peer, verify_none]}}]}. - -{mapping, "ssl_options.fail_if_no_peer_cert", "rabbit.ssl_options.fail_if_no_peer_cert", [ - {datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.cacertfile", "rabbit.ssl_options.cacertfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "ssl_options.certfile", "rabbit.ssl_options.certfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "ssl_options.cacerts.$name", "rabbit.ssl_options.cacerts", - [{datatype, string}]}. - -{translation, "rabbit.ssl_options.cacerts", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("ssl_options.cacerts", Conf), - [ list_to_binary(V) || {_, V} <- Settings ] -end}. - -{mapping, "ssl_options.cert", "rabbit.ssl_options.cert", - [{datatype, string}]}. - -{translation, "rabbit.ssl_options.cert", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("ssl_options.cert", Conf)) -end}. - -{mapping, "ssl_options.client_renegotiation", "rabbit.ssl_options.client_renegotiation", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.crl_check", "rabbit.ssl_options.crl_check", - [{datatype, [{enum, [true, false, peer, best_effort]}]}]}. - -{mapping, "ssl_options.depth", "rabbit.ssl_options.depth", - [{datatype, integer}, {validators, ["byte"]}]}. - -{mapping, "ssl_options.dh", "rabbit.ssl_options.dh", - [{datatype, string}]}. - -{translation, "rabbit.ssl_options.dh", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("ssl_options.dh", Conf)) -end}. - -{mapping, "ssl_options.dhfile", "rabbit.ssl_options.dhfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "ssl_options.honor_cipher_order", "rabbit.ssl_options.honor_cipher_order", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.key.RSAPrivateKey", "rabbit.ssl_options.key", - [{datatype, string}]}. - -{mapping, "ssl_options.key.DSAPrivateKey", "rabbit.ssl_options.key", - [{datatype, string}]}. - -{mapping, "ssl_options.key.PrivateKeyInfo", "rabbit.ssl_options.key", - [{datatype, string}]}. - -{translation, "rabbit.ssl_options.key", -fun(Conf) -> - case cuttlefish_variable:filter_by_prefix("ssl_options.key", Conf) of - [{[_,_,Key], Val}|_] -> {list_to_atom(Key), list_to_binary(Val)}; - _ -> undefined - end -end}. - -{mapping, "ssl_options.keyfile", "rabbit.ssl_options.keyfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "ssl_options.log_alert", "rabbit.ssl_options.log_alert", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.password", "rabbit.ssl_options.password", - [{datatype, string}]}. - -{mapping, "ssl_options.psk_identity", "rabbit.ssl_options.psk_identity", - [{datatype, string}]}. - -{mapping, "ssl_options.reuse_sessions", "rabbit.ssl_options.reuse_sessions", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.secure_renegotiate", "rabbit.ssl_options.secure_renegotiate", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "ssl_options.versions.$version", "rabbit.ssl_options.versions", - [{datatype, atom}]}. - -{translation, "rabbit.ssl_options.versions", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("ssl_options.versions", Conf), - [ V || {_, V} <- Settings ] -end}. - -%% =========================================================================== - -%% Choose the available SASL mechanism(s) to expose. -%% The two default (built in) mechanisms are 'PLAIN' and -%% 'AMQPLAIN'. Additional mechanisms can be added via -%% plugins. -%% -%% See http://www.rabbitmq.com/authentication.html for more details. -%% -%% {auth_mechanisms, ['PLAIN', 'AMQPLAIN']}, - -{mapping, "auth_mechanisms.$name", "rabbit.auth_mechanisms", [ - {datatype, atom}]}. - -{translation, "rabbit.auth_mechanisms", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("auth_mechanisms", Conf), - [ V || {_, V} <- Settings ] -end}. - - -%% Select an authentication backend to use. RabbitMQ provides an -%% internal backend in the core. -%% -%% {auth_backends, [rabbit_auth_backend_internal]}, - -{translation, "rabbit.auth_backends", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("auth_backends", Conf), - BackendModule = fun - (internal) -> rabbit_auth_backend_internal; - (ldap) -> rabbit_auth_backend_ldap; - (http) -> rabbit_auth_backend_http; - (amqp) -> rabbit_auth_backend_amqp; - (dummy) -> rabbit_auth_backend_dummy; - (Other) when is_atom(Other) -> Other; - (_) -> cuttlefish:invalid("Unknown/unsupported auth backend") - end, - AuthBackends = [{Num, {default, BackendModule(V)}} || {["auth_backends", Num], V} <- Settings], - AuthNBackends = [{Num, {authn, BackendModule(V)}} || {["auth_backends", Num, "authn"], V} <- Settings], - AuthZBackends = [{Num, {authz, BackendModule(V)}} || {["auth_backends", Num, "authz"], V} <- Settings], - Backends = lists:foldl( - fun({NumStr, {Type, V}}, Acc) -> - Num = case catch list_to_integer(NumStr) of - N when is_integer(N) -> N; - Err -> - cuttlefish:invalid( - iolist_to_binary(io_lib:format( - "Auth backend position in the chain should be an integer ~p", [Err]))) - end, - NewVal = case dict:find(Num, Acc) of - {ok, {AuthN, AuthZ}} -> - case {Type, AuthN, AuthZ} of - {authn, undefined, _} -> - {V, AuthZ}; - {authz, _, undefined} -> - {AuthN, V}; - _ -> - cuttlefish:invalid( - iolist_to_binary( - io_lib:format( - "Auth backend already defined for the ~pth ~p backend", - [Num, Type]))) - end; - error -> - case Type of - authn -> {V, undefined}; - authz -> {undefined, V}; - default -> {V, V} - end - end, - dict:store(Num, NewVal, Acc) - end, - dict:new(), - AuthBackends ++ AuthNBackends ++ AuthZBackends), - lists:map( - fun - ({Num, {undefined, AuthZ}}) -> - cuttlefish:warn( - io_lib:format( - "Auth backend undefined for the ~pth authz backend. Using ~p", - [Num, AuthZ])), - {AuthZ, AuthZ}; - ({Num, {AuthN, undefined}}) -> - cuttlefish:warn( - io_lib:format( - "Authz backend undefined for the ~pth authn backend. Using ~p", - [Num, AuthN])), - {AuthN, AuthN}; - ({_Num, {Auth, Auth}}) -> Auth; - ({_Num, {AuthN, AuthZ}}) -> {AuthN, AuthZ} - end, - lists:keysort(1, dict:to_list(Backends))) -end}. - -{mapping, "auth_backends.$num", "rabbit.auth_backends", [ - {datatype, atom} -]}. - -{mapping, "auth_backends.$num.authn", "rabbit.auth_backends",[ - {datatype, atom} -]}. - -{mapping, "auth_backends.$num.authz", "rabbit.auth_backends",[ - {datatype, atom} -]}. - -%% This pertains to both the rabbitmq_auth_mechanism_ssl plugin and -%% STOMP ssl_cert_login configurations. See the rabbitmq_stomp -%% configuration section later in this file and the README in -%% https://github.com/rabbitmq/rabbitmq-auth-mechanism-ssl for further -%% details. -%% -%% To use the SSL cert's CN instead of its DN as the username -%% -%% {ssl_cert_login_from, common_name}, - -{mapping, "ssl_cert_login_from", "rabbit.ssl_cert_login_from", [ - {datatype, {enum, [distinguished_name, common_name]}} -]}. - -%% SSL handshake timeout, in milliseconds. -%% -%% {ssl_handshake_timeout, 5000}, - -{mapping, "ssl_handshake_timeout", "rabbit.ssl_handshake_timeout", [ - {datatype, integer} -]}. - -%% Password hashing implementation. Will only affect newly -%% created users. To recalculate hash for an existing user -%% it's necessary to update her password. -%% -%% When importing definitions exported from versions earlier -%% than 3.6.0, it is possible to go back to MD5 (only do this -%% as a temporary measure!) by setting this to rabbit_password_hashing_md5. -%% -%% To use SHA-512, set to rabbit_password_hashing_sha512. -%% -%% {password_hashing_module, rabbit_password_hashing_sha256}, - -{mapping, "password_hashing_module", "rabbit.password_hashing_module", [ - {datatype, atom} -]}. - -%% -%% Default User / VHost -%% ==================== -%% - -%% On first start RabbitMQ will create a vhost and a user. These -%% config items control what gets created. See -%% http://www.rabbitmq.com/access-control.html for further -%% information about vhosts and access control. -%% -%% {default_vhost, <<"/">>}, -%% {default_user, <<"guest">>}, -%% {default_pass, <<"guest">>}, -%% {default_permissions, [<<".*">>, <<".*">>, <<".*">>]}, - -{mapping, "default_vhost", "rabbit.default_vhost", [ - {datatype, string} -]}. - -{translation, "rabbit.default_vhost", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("default_vhost", Conf)) -end}. - -{mapping, "default_user", "rabbit.default_user", [ - {datatype, string} -]}. - -{translation, "rabbit.default_user", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("default_user", Conf)) -end}. - -{mapping, "default_pass", "rabbit.default_pass", [ - {datatype, string} -]}. - -{translation, "rabbit.default_pass", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("default_pass", Conf)) -end}. - -{mapping, "default_permissions.configure", "rabbit.default_permissions", [ - {datatype, string} -]}. - -{mapping, "default_permissions.read", "rabbit.default_permissions", [ - {datatype, string} -]}. - -{mapping, "default_permissions.write", "rabbit.default_permissions", [ - {datatype, string} -]}. - -{translation, "rabbit.default_permissions", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("default_permissions", Conf), - Configure = proplists:get_value(["default_permissions", "configure"], Settings), - Read = proplists:get_value(["default_permissions", "read"], Settings), - Write = proplists:get_value(["default_permissions", "write"], Settings), - [list_to_binary(Configure), list_to_binary(Read), list_to_binary(Write)] -end}. - -%% Tags for default user -%% -%% For more details about tags, see the documentation for the -%% Management Plugin at http://www.rabbitmq.com/management.html. -%% -%% {default_user_tags, [administrator]}, - -{mapping, "default_user_tags.$tag", "rabbit.default_user_tags", - [{datatype, {enum, [true, false]}}]}. - -{translation, "rabbit.default_user_tags", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("default_user_tags", Conf), - [ list_to_atom(Key) || {[_,Key], Val} <- Settings, Val == true ] -end}. - -%% -%% Additional network and protocol related configuration -%% ===================================================== -%% - -%% Set the default AMQP heartbeat delay (in seconds). -%% -%% {heartbeat, 600}, - -{mapping, "heartbeat", "rabbit.heartbeat", [{datatype, integer}]}. - -%% Set the max permissible size of an AMQP frame (in bytes). -%% -%% {frame_max, 131072}, - -{mapping, "frame_max", "rabbit.frame_max", [{datatype, bytesize}]}. - -%% Set the max frame size the server will accept before connection -%% tuning occurs -%% -%% {initial_frame_max, 4096}, - -{mapping, "initial_frame_max", "rabbit.initial_frame_max", [{datatype, bytesize}]}. - -%% Set the max permissible number of channels per connection. -%% 0 means "no limit". -%% -%% {channel_max, 128}, - -{mapping, "channel_max", "rabbit.channel_max", [{datatype, integer}]}. - -%% Customising Socket Options. -%% -%% See (http://www.erlang.org/doc/man/inet.html#setopts-2) for -%% further documentation. -%% -%% {tcp_listen_options, [{backlog, 128}, -%% {nodelay, true}, -%% {exit_on_close, false}]}, - -%% TCP listener section ====================================================== - -{mapping, "tcp_listen_options", "rabbit.tcp_listen_options", [ - {datatype, {enum, [none]}}]}. - -{translation, "rabbit.tcp_listen_options", -fun(Conf) -> - case cuttlefish:conf_get("tcp_listen_options", Conf, undefined) of - none -> []; - _ -> cuttlefish:invalid("Invalid tcp_listen_options") - end -end}. - -{mapping, "tcp_listen_options.backlog", "rabbit.tcp_listen_options.backlog", [ - {datatype, integer} -]}. - -{mapping, "tcp_listen_options.nodelay", "rabbit.tcp_listen_options.nodelay", [ - {datatype, {enum, [true, false]}} -]}. - -{mapping, "tcp_listen_options.buffer", "rabbit.tcp_listen_options.buffer", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.delay_send", "rabbit.tcp_listen_options.delay_send", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.dontroute", "rabbit.tcp_listen_options.dontroute", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.exit_on_close", "rabbit.tcp_listen_options.exit_on_close", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.fd", "rabbit.tcp_listen_options.fd", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.high_msgq_watermark", "rabbit.tcp_listen_options.high_msgq_watermark", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.high_watermark", "rabbit.tcp_listen_options.high_watermark", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.keepalive", "rabbit.tcp_listen_options.keepalive", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.low_msgq_watermark", "rabbit.tcp_listen_options.low_msgq_watermark", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.low_watermark", "rabbit.tcp_listen_options.low_watermark", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.port", "rabbit.tcp_listen_options.port", - [{datatype, integer}, {validators, ["port"]}]}. - -{mapping, "tcp_listen_options.priority", "rabbit.tcp_listen_options.priority", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.recbuf", "rabbit.tcp_listen_options.recbuf", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.send_timeout", "rabbit.tcp_listen_options.send_timeout", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.send_timeout_close", "rabbit.tcp_listen_options.send_timeout_close", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.sndbuf", "rabbit.tcp_listen_options.sndbuf", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.tos", "rabbit.tcp_listen_options.tos", - [{datatype, integer}]}. - -{mapping, "tcp_listen_options.linger.on", "rabbit.tcp_listen_options.linger", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "tcp_listen_options.linger.timeout", "rabbit.tcp_listen_options.linger", - [{datatype, integer}, {validators, ["non_negative_integer"]}]}. - -{translation, "rabbit.tcp_listen_options.linger", -fun(Conf) -> - LingerOn = cuttlefish:conf_get("tcp_listen_options.linger.on", Conf, false), - LingerTimeout = cuttlefish:conf_get("tcp_listen_options.linger.timeout", Conf, 0), - {LingerOn, LingerTimeout} -end}. - - -%% ========================================================================== - -%% -%% Resource Limits & Flow Control -%% ============================== -%% -%% See http://www.rabbitmq.com/memory.html for full details. - -%% Memory-based Flow Control threshold. -%% -%% {vm_memory_high_watermark, 0.4}, - -%% Alternatively, we can set a limit (in bytes) of RAM used by the node. -%% -%% {vm_memory_high_watermark, {absolute, 1073741824}}, -%% -%% Or you can set absolute value using memory units (with RabbitMQ 3.6.0+). -%% -%% {vm_memory_high_watermark, {absolute, "1024M"}}, -%% -%% Supported units suffixes: -%% -%% kb, KB: kibibytes (2^10 bytes) -%% mb, MB: mebibytes (2^20) -%% gb, GB: gibibytes (2^30) - -{mapping, "vm_memory_high_watermark.relative", "rabbit.vm_memory_high_watermark", [ - {datatype, float}]}. - -{mapping, "vm_memory_high_watermark.absolute", "rabbit.vm_memory_high_watermark", [ - {datatype, [integer, string]}]}. - - -{translation, "rabbit.vm_memory_high_watermark", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("vm_memory_high_watermark", Conf), - Absolute = proplists:get_value(["vm_memory_high_watermark", "absolute"], Settings), - Relative = proplists:get_value(["vm_memory_high_watermark", "relative"], Settings), - case {Absolute, Relative} of - {undefined, undefined} -> cuttlefish:invalid("No vm watermark defined"); - {_, undefined} -> {absolute, Absolute}; - _ -> Relative - end -end}. - -%% Fraction of the high watermark limit at which queues start to -%% page message out to disc in order to free up memory. -%% -%% Values greater than 0.9 can be dangerous and should be used carefully. -%% -%% {vm_memory_high_watermark_paging_ratio, 0.5}, - -{mapping, "vm_memory_high_watermark_paging_ratio", - "rabbit.vm_memory_high_watermark_paging_ratio", - [{datatype, float}, {validators, ["less_than_1"]}]}. - -%% Interval (in milliseconds) at which we perform the check of the memory -%% levels against the watermarks. -%% -%% {memory_monitor_interval, 2500}, - -{mapping, "memory_monitor_interval", "rabbit.memory_monitor_interval", - [{datatype, integer}]}. - -%% Set disk free limit (in bytes). Once free disk space reaches this -%% lower bound, a disk alarm will be set - see the documentation -%% listed above for more details. -%% -%% {disk_free_limit, 50000000}, -%% -%% Or you can set it using memory units (same as in vm_memory_high_watermark) -%% with RabbitMQ 3.6.0+. -%% {disk_free_limit, "50MB"}, -%% {disk_free_limit, "50000kB"}, -%% {disk_free_limit, "2GB"}, - -%% Alternatively, we can set a limit relative to total available RAM. -%% -%% Values lower than 1.0 can be dangerous and should be used carefully. -%% {disk_free_limit, {mem_relative, 2.0}}, - -{mapping, "disk_free_limit.relative", "rabbit.disk_free_limit", [ - {datatype, float}]}. - -{mapping, "disk_free_limit.absolute", "rabbit.disk_free_limit", [ - {datatype, [integer, string]}]}. - - -{translation, "rabbit.disk_free_limit", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("disk_free_limit", Conf), - Absolute = proplists:get_value(["disk_free_limit", "absolute"], Settings), - Relative = proplists:get_value(["disk_free_limit", "relative"], Settings), - case {Absolute, Relative} of - {undefined, undefined} -> cuttlefish:invalid("No disk limit defined"); - {_, undefined} -> Absolute; - _ -> {mem_relative, Relative} - end -end}. - -%% -%% Clustering -%% ===================== -%% - -%% How to respond to cluster partitions. -%% See http://www.rabbitmq.com/partitions.html for further details. -%% -%% {cluster_partition_handling, ignore}, - -{mapping, "cluster_partition_handling", "rabbit.cluster_partition_handling", - [{datatype, {enum, [ignore, pause_minority, autoheal, pause_if_all_down]}}]}. - -{mapping, "cluster_partition_handling.pause_if_all_down.recover", - "rabbit.cluster_partition_handling", - [{datatype, {enum, [ignore, autoheal]}}]}. - -{mapping, "cluster_partition_handling.pause_if_all_down.nodes.$name", - "rabbit.cluster_partition_handling", - [{datatype, atom}]}. - -{translation, "rabbit.cluster_partition_handling", -fun(Conf) -> - case cuttlefish:conf_get("cluster_partition_handling", Conf) of - pause_if_all_down -> - PauseIfAllDownNodes = cuttlefish_variable:filter_by_prefix( - "cluster_partition_handling.pause_if_all_down.nodes", - Conf), - case PauseIfAllDownNodes of - [] -> - cuttlefish:invalid("Nodes required for pause_if_all_down"); - _ -> - Nodes = [ V || {K,V} <- PauseIfAllDownNodes ], - PauseIfAllDownRecover = cuttlefish:conf_get( - "cluster_partition_handling.pause_if_all_down.recover", - Conf), - case PauseIfAllDownRecover of - Recover when Recover == ignore; Recover == autoheal -> - {pause_if_all_down, Nodes, Recover}; - Invalid -> - cuttlefish:invalid("Recover strategy required for pause_if_all_down") - end - end; - Other -> Other - end -end}. - -%% Mirror sync batch size, in messages. Increasing this will speed -%% up syncing but total batch size in bytes must not exceed 2 GiB. -%% Available in RabbitMQ 3.6.0 or later. -%% -%% {mirroring_sync_batch_size, 4096}, - -{mapping, "mirroring_sync_batch_size", "rabbit.mirroring_sync_batch_size", - [{datatype, bytesize}, {validators, ["size_less_than_2G"]}]}. - -%% Make clustering happen *automatically* at startup - only applied -%% to nodes that have just been reset or started for the first time. -%% See http://www.rabbitmq.com/clustering.html#auto-config for -%% further details. -%% -%% {cluster_nodes, {['rabbit@my.host.com'], disc}}, - -{mapping, "cluster_nodes.disc.$node", "rabbit.cluster_nodes", - [{datatype, atom}]}. - -{mapping, "cluster_nodes.ram.$node", "rabbit.cluster_nodes", - [{datatype, atom}]}. - -{translation, "rabbit.cluster_nodes", -fun(Conf) -> - DiskNodes = [ V || {_, V} <- cuttlefish_variable:filter_by_prefix("cluster_nodes.disc", Conf)], - RamNodes = [ V || {_, V} <- cuttlefish_variable:filter_by_prefix("cluster_nodes.ram", Conf)], - - case {DiskNodes, RamNodes} of - {_, []} -> {DiskNodes, disc}; - {[], _} -> {RamNodes, ram} - end -end}. - - -%% Interval (in milliseconds) at which we send keepalive messages -%% to other cluster members. Note that this is not the same thing -%% as net_ticktime; missed keepalive messages will not cause nodes -%% to be considered down. -%% -%% {cluster_keepalive_interval, 10000}, - -{mapping, "cluster_keepalive_interval", "rabbit.cluster_keepalive_interval", - [{datatype, integer}]}. - - -{mapping, "queue_master_locator", "rabbit.queue_master_locator", - [{datatype, string}]}. - -{translation, "rabbit.queue_master_locator", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("queue_master_locator", Conf)) -end}. - -%% -%% Statistics Collection -%% ===================== -%% - -%% Set (internal) statistics collection granularity. -%% -%% {collect_statistics, none}, - -{mapping, "collect_statistics", "rabbit.collect_statistics", - [{datatype, {enum, [none, coarse, fine]}}]}. - -%% Statistics collection interval (in milliseconds). Increasing -%% this will reduce the load on management database. -%% -%% {collect_statistics_interval, 5000}, - -{mapping, "collect_statistics_interval", "rabbit.collect_statistics_interval", - [{datatype, integer}]}. - -%% -%% Misc/Advanced Options -%% ===================== -%% -%% NB: Change these only if you understand what you are doing! -%% - -%% Explicitly enable/disable hipe compilation. -%% -%% {hipe_compile, true}, - -{mapping, "hipe_compile", "rabbit.hipe_compile", - [{datatype, {enum, [true, false]}}]}. - -%% Timeout used when waiting for Mnesia tables in a cluster to -%% become available. -%% -%% {mnesia_table_loading_timeout, 30000}, - -{mapping, "mnesia_table_loading_timeout", "rabbit.mnesia_table_loading_timeout", - [{datatype, integer}]}. - -%% Size in bytes below which to embed messages in the queue index. See -%% http://www.rabbitmq.com/persistence-conf.html -%% -%% {queue_index_embed_msgs_below, 4096} - -{mapping, "queue_index_embed_msgs_below", "rabbit.queue_index_embed_msgs_below", - [{datatype, bytesize}]}. - -% ========================== -% Lager section -% ========================== - -{mapping, "log.dir", "lager.log_root", [ - {datatype, string}, - {validators, ["dir_writable"]}]}. - -{mapping, "log.console", "lager.handlers", [ - {datatype, {enum, [true, false]}} -]}. - -{mapping, "log.syslog", "lager.handlers", [ - {datatype, {enum, [true, false]}} -]}. -{mapping, "log.file", "lager.handlers", [ - {datatype, [{enum, [false]}, string]} -]}. - -{mapping, "log.file.level", "lager.handlers", [ - {datatype, {enum, [debug, info, warning, error]}} -]}. -{mapping, "log.$handler.level", "lager.handlers", [ - {datatype, {enum, [debug, info, warning, error]}} -]}. -{mapping, "log.file.rotation.date", "lager.handlers", [ - {datatype, string} -]}. -{mapping, "log.file.rotation.size", "lager.handlers", [ - {datatype, integer} -]}. -{mapping, "log.file.rotation.count", "lager.handlers", [ - {datatype, integer} -]}. - -{mapping, "log.syslog.identity", "lager.handlers", [ - {datatype, string} -]}. -{mapping, "log.syslog.facility", "lager.handlers", [ - {datatype, atom} -]}. - -{translation, "lager.handlers", -fun(Conf) -> - ConsoleHandler = case cuttlefish:conf_get("log.console", Conf, false) of - true -> - ConsoleLevel = cuttlefish:conf_get("log.console.level", Conf, info), - [{lager_console_backend, ConsoleLevel}]; - false -> [] - end, - FileHandler = case cuttlefish:conf_get("log.file", Conf, false) of - false -> []; - File -> - FileLevel = cuttlefish:conf_get("log.file.level", Conf, info), - RotationDate = cuttlefish:conf_get("log.file.rotation.date", Conf, ""), - RotationSize = cuttlefish:conf_get("log.file.rotation.size", Conf, 0), - RotationCount = cuttlefish:conf_get("log.file.rotation.count", Conf, 10), - [{lager_file_backend, [{file, File}, - {level, FileLevel}, - {date, RotationDate}, - {size, RotationSize}, - {count, RotationCount}]}] - end, - SyslogHandler = case cuttlefish:conf_get("log.syslog", Conf, false) of - false -> []; - true -> - SyslogLevel = cuttlefish:conf_get("log.syslog.level", Conf, info), - Identity = cuttlefish:conf_get("log.syslog.identity", Conf), - Facility = cuttlefish:conf_get("log.syslog.facility", Conf), - [{lager_syslog_backend, [Identity, Facility, SyslogLevel]}] - end, - case ConsoleHandler ++ FileHandler ++ SyslogHandler of - [] -> undefined; - Other -> Other - end -end}. - - -% =============================== -% Validators -% =============================== - -{validator, "size_less_than_2G", "Byte size should be less than 2G and greater than 0", -fun(Size) when is_integer(Size) -> - Size > 0 andalso Size < 2147483648 -end}. - -{validator, "less_than_1", "Flooat is not beetween 0 and 1", -fun(Float) when is_float(Float) -> - Float > 0 andalso Float < 1 -end}. - -{validator, "port", "Invalid port number", -fun(Port) when is_integer(Port) -> - Port > 0 andalso Port < 65535 -end}. - -{validator, "byte", "Integer is not 0<i<255", -fun(Int) when is_integer(Int) -> - Int > 0 andalso Int < 255 -end}. - -{validator, "dir_writable", "Cannot create file in dir", -fun(Dir) -> - TestFile = filename:join(Dir, "test_file"), - file:delete(TestFile), - Res = ok == file:write_file(TestFile, <<"test">>), - file:delete(TestFile), - Res -end}. - -{validator, "file_accessible", "file doesnt exist or unaccessible", -fun(File) -> - ReadFile = file:read_file_info(File), - element(1, ReadFile) == ok -end}. - -{validator, "is_ip", "string is a valid IP address", -fun(IpStr) -> - Res = inet:parse_address(IpStr), - element(1, Res) == ok -end}. - -{validator, "non_negative_integer", "number should be greater or equal to zero", -fun(Int) when is_integer(Int) -> - Int >= 0 -end}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_amqp1_0.schema b/test/config_schema_SUITE_data/schema/rabbitmq_amqp1_0.schema deleted file mode 100644 index e6cfb68262..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_amqp1_0.schema +++ /dev/null @@ -1,31 +0,0 @@ -%% ---------------------------------------------------------------------------- -%% RabbitMQ AMQP 1.0 Support -%% -%% See https://github.com/rabbitmq/rabbitmq-amqp1.0/blob/stable/README.md -%% for details -%% ---------------------------------------------------------------------------- - -% {rabbitmq_amqp1_0,[ -%% Connections that are not authenticated with SASL will connect as this -%% account. See the README for more information. -%% -%% Please note that setting this will allow clients to connect without -%% authenticating! -%% -%% {default_user, "guest"}, -{mapping, "amqp1_0.default_user", "rabbitmq_amqp1_0.default_user", - [{datatype, [{enum, [none]}, string]}]}. -%% Enable protocol strict mode. See the README for more information. -%% -%% {protocol_strict_mode, false} -% ]}, -{mapping, "amqp1_0.protocol_strict_mode", "rabbitmq_amqp1_0.protocol_strict_mode", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "amqp1_0.default_vhost", "rabbitmq_amqp1_0.default_vhost", - [{datatype, string}]}. - -{translation , "rabbitmq_amqp1_0.default_vhost", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("amqp1_0.default_vhost", Conf)) -end}.
\ No newline at end of file diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_amqp.schema b/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_amqp.schema deleted file mode 100644 index a30efb6c03..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_amqp.schema +++ /dev/null @@ -1,27 +0,0 @@ -{mapping, "rabbitmq_auth_backend_amqp.username", "rabbitmq_auth_backend_amqp.username", - [{datatype, string}]}. - -{translation, "rabbitmq_auth_backend_amqp.username", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("rabbitmq_auth_backend_amqp.username", Conf)) -end}. - -{mapping, "rabbitmq_auth_backend_amqp.vhost", "rabbitmq_auth_backend_amqp.vhost", - [{datatype, string}]}. - -{translation, "rabbitmq_auth_backend_amqp.vhost", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("rabbitmq_auth_backend_amqp.vhost", Conf)) -end}. - -{mapping, "rabbitmq_auth_backend_amqp.exchange", "rabbitmq_auth_backend_amqp.exchange", - [{datatype, string}]}. - -{translation, "rabbitmq_auth_backend_amqp.exchange", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("rabbitmq_auth_backend_amqp.exchange", Conf)) -end}. - - -{mapping, "rabbitmq_auth_backend_amqp.timeout", "rabbitmq_auth_backend_amqp.timeout", - [{datatype, [{enum, [infinity]}, integer]}]}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_http.schema b/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_http.schema deleted file mode 100644 index f10eb6710b..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_http.schema +++ /dev/null @@ -1,15 +0,0 @@ - -%% ========================================================================== -%% ---------------------------------------------------------------------------- -%% RabbitMQ HTTP Authorization -%% -%% ---------------------------------------------------------------------------- - -{mapping, "rabbitmq_auth_backend_http.user_path", "rabbitmq_auth_backend_http.user_path", - [{datatype, string}, {validators, ["uri"]}]}. - -{mapping, "rabbitmq_auth_backend_http.vhost_path", "rabbitmq_auth_backend_http.vhost_path", - [{datatype, string}, {validators, ["uri"]}]}. - -{mapping, "rabbitmq_auth_backend_http.resource_path", "rabbitmq_auth_backend_http.resource_path", - [{datatype, string}, {validators, ["uri"]}]}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_ldap.schema b/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_ldap.schema deleted file mode 100644 index 334fd014c1..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_auth_backend_ldap.schema +++ /dev/null @@ -1,183 +0,0 @@ -%% ---------------------------------------------------------------------------- -%% RabbitMQ LDAP Plugin -%% -%% See http://www.rabbitmq.com/ldap.html for details. -%% -%% ---------------------------------------------------------------------------- - -% {rabbitmq_auth_backend_ldap, -% [ -%% -%% Connecting to the LDAP server(s) -%% ================================ -%% - -%% Specify servers to bind to. You *must* set this in order for the plugin -%% to work properly. -%% -%% {servers, ["your-server-name-goes-here"]}, - -{mapping, "rabbitmq_auth_backend_ldap.servers", "rabbitmq_auth_backend_ldap.servers", - [{datatype, {enum, [none]}}]}. - -{mapping, "rabbitmq_auth_backend_ldap.servers.$server", "rabbitmq_auth_backend_ldap.servers", - [{datatype, string}]}. - -{translation, "rabbitmq_auth_backend_ldap.servers", -fun(Conf) -> - case cuttlefish:conf_get("rabbitmq_auth_backend_ldap.servers", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("rabbitmq_auth_backend_ldap.servers", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -%% Connect to the LDAP server using SSL -%% -%% {use_ssl, false}, - -{mapping, "rabbitmq_auth_backend_ldap.use_ssl", "rabbitmq_auth_backend_ldap.use_ssl", - [{datatype, {enum, [true, false]}}]}. - -%% Specify the LDAP port to connect to -%% -%% {port, 389}, - -{mapping, "rabbitmq_auth_backend_ldap.port", "rabbitmq_auth_backend_ldap.port", - [{datatype, integer}]}. - -%% LDAP connection timeout, in milliseconds or 'infinity' -%% -%% {timeout, infinity}, - -{mapping, "rabbitmq_auth_backend_ldap.timeout", "rabbitmq_auth_backend_ldap.timeout", - [{datatype, [integer, {atom, infinity}]}]}. - -%% Enable logging of LDAP queries. -%% One of -%% - false (no logging is performed) -%% - true (verbose logging of the logic used by the plugin) -%% - network (as true, but additionally logs LDAP network traffic) -%% -%% Defaults to false. -%% -%% {log, false}, - -{mapping, "rabbitmq_auth_backend_ldap.log", "rabbitmq_auth_backend_ldap.log", - [{datatype, {enum, [true, false, network]}}]}. - -%% -%% Authentication -%% ============== -%% - -%% Pattern to convert the username given through AMQP to a DN before -%% binding -%% -%% {user_dn_pattern, "cn=${username},ou=People,dc=example,dc=com"}, - -{mapping, "rabbitmq_auth_backend_ldap.user_dn_pattern", "rabbitmq_auth_backend_ldap.user_dn_pattern", - [{datatype, string}]}. - -%% Alternatively, you can convert a username to a Distinguished -%% Name via an LDAP lookup after binding. See the documentation for -%% full details. - -%% When converting a username to a dn via a lookup, set these to -%% the name of the attribute that represents the user name, and the -%% base DN for the lookup query. -%% -%% {dn_lookup_attribute, "userPrincipalName"}, -%% {dn_lookup_base, "DC=gopivotal,DC=com"}, - -{mapping, "rabbitmq_auth_backend_ldap.dn_lookup_attribute", "rabbitmq_auth_backend_ldap.dn_lookup_attribute", - [{datatype, [{enum, [none]}, string]}]}. - -{mapping, "rabbitmq_auth_backend_ldap.dn_lookup_base", "rabbitmq_auth_backend_ldap.dn_lookup_base", - [{datatype, [{enum, [none]}, string]}]}. - -{mapping, "rabbitmq_auth_backend_ldap.dn_lookup_bind", "rabbitmq_auth_backend_ldap.dn_lookup_bind", - [{datatype, [{enum, [as_user]}]}]}. - -{mapping, "rabbitmq_auth_backend_ldap.dn_lookup_bind.user_dn", "rabbitmq_auth_backend_ldap.dn_lookup_bind", - [{datatype, [string]}]}. - -{mapping, "rabbitmq_auth_backend_ldap.dn_lookup_bind.password", "rabbitmq_auth_backend_ldap.dn_lookup_bind", - [{datatype, [string]}]}. - -{translation, "rabbitmq_auth_backend_ldap.dn_lookup_bind", -fun(Conf) -> - case cuttlefish:conf_get("rabbitmq_auth_backend_ldap.dn_lookup_bind", Conf, undefined) of - as_user -> as_user; - _ -> - User = cuttlefish:conf_get("rabbitmq_auth_backend_ldap.dn_lookup_bind.user_dn", Conf), - Pass = cuttlefish:conf_get("rabbitmq_auth_backend_ldap.dn_lookup_bind.password", Conf), - case {User, Pass} of - {undefined, _} -> as_user; - {_, undefined} -> as_user; - _ -> {User, Pass} - end - end -end}. - -%% Controls how to bind for authorisation queries and also to -%% retrieve the details of users logging in without presenting a -%% password (e.g., SASL EXTERNAL). -%% One of -%% - as_user (to bind as the authenticated user - requires a password) -%% - anon (to bind anonymously) -%% - {UserDN, Password} (to bind with a specified user name and password) -%% -%% Defaults to 'as_user'. -%% -%% {other_bind, as_user}, - -{mapping, "rabbitmq_auth_backend_ldap.other_bind", "rabbitmq_auth_backend_ldap.other_bind", - [{datatype, {enum, [as_user, anon]}}]}. - -{mapping, "rabbitmq_auth_backend_ldap.other_bind.user_dn", "rabbitmq_auth_backend_ldap.other_bind", - [{datatype, string}]}. - -{mapping, "rabbitmq_auth_backend_ldap.other_bind.password", "rabbitmq_auth_backend_ldap.other_bind", - [{datatype, string}]}. - -{translation, "rabbitmq_auth_backend_ldap.other_bind", -fun(Conf) -> - case cuttlefish:conf_get("rabbitmq_auth_backend_ldap.other_bind", Conf, undefined) of - as_user -> as_user; - anon -> anon; - _ -> - User = cuttlefish:conf_get("rabbitmq_auth_backend_ldap.other_bind.user_dn", Conf), - Pass = cuttlefish:conf_get("rabbitmq_auth_backend_ldap.other_bind.password", Conf), - case {User, Pass} of - {undefined, _} -> as_user; - {_, undefined} -> as_user; - _ -> {User, Pass} - end - end -end}. - -%% -%% Authorisation -%% ============= -%% - -%% The LDAP plugin can perform a variety of queries against your -%% LDAP server to determine questions of authorisation. See -%% http://www.rabbitmq.com/ldap.html#authorisation for more -%% information. - -%% Set the query to use when determining vhost access -%% -%% {vhost_access_query, {in_group, -%% "ou=${vhost}-users,ou=vhosts,dc=example,dc=com"}}, - -%% Set the query to use when determining resource (e.g., queue) access -%% -%% {resource_access_query, {constant, true}}, - -%% Set queries to determine which tags a user has -%% -%% {tag_queries, []} -% ]}, diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_clusterer.schema b/test/config_schema_SUITE_data/schema/rabbitmq_clusterer.schema deleted file mode 100644 index ba127f00c1..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_clusterer.schema +++ /dev/null @@ -1,58 +0,0 @@ -{mapping, "clusterer.config", "rabbitmq_clusterer.config", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{translation, "rabbitmq_clusterer.config", -fun(Conf) -> - case cuttlefish:conf_get("clusterer.config", Conf, undefined) of - String when is_list(String) -> - case cuttlefish_variable:filter_by_prefix("clusterer", Conf) of - [{["clusterer", "config"], String}] -> String; - _ -> cuttlefish:invalid("Config for clusterer defined in "++ - String ++ " file. " ++ - "All other clusterer configurations should be removed") - end; - _ -> [] - end -end}. - -{mapping, "clusterer.version", "rabbitmq_clusterer.config.version", - [{datatype, integer}]}. - -{mapping, "clusterer.nodes.$node", "rabbitmq_clusterer.config.nodes", - [{datatype, atom}]}. - -{mapping, "clusterer.nodes.ram.$node", "rabbitmq_clusterer.config.nodes", - [{datatype, atom}]}. - -{mapping, "clusterer.nodes.disk.$node", "rabbitmq_clusterer.config.nodes", - [{datatype, atom}]}. - -{mapping, "clusterer.nodes.disc.$node", "rabbitmq_clusterer.config.nodes", - [{datatype, atom}]}. - -{translation, "rabbitmq_clusterer.config.nodes", -fun(Conf) -> - DiskNodes = cuttlefish_variable:filter_by_prefix("clusterer.nodes", Conf) - ++ cuttlefish_variable:filter_by_prefix("clusterer.nodes.disk", Conf) - ++ cuttlefish_variable:filter_by_prefix("clusterer.nodes.disc", Conf), - RamNodes = cuttlefish_variable:filter_by_prefix("clusterer.nodes.ram", Conf), - [{Node, disk} || {_, Node} <- DiskNodes] ++ [{Node, ram} || Node <- RamNodes] -end}. - -{mapping, "clusterer.gospel", "rabbitmq_clusterer.config.gospel", - [{datatype, {enum, [reset]}}]}. - -{mapping, "clusterer.gospel.node", "rabbitmq_clusterer.config.gospel", - [{datatype, atom}]}. - -{translation, "rabbitmq_clusterer.config.gospel", -fun(Conf) -> - case cuttlefish:conf_get("clusterer.gospel", Conf, undefined) of - reset -> reset; - _ -> - {node, cuttlefish:conf_get("clusterer.gospel.node", Conf)} - end -end}. - - - diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_management.schema b/test/config_schema_SUITE_data/schema/rabbitmq_management.schema deleted file mode 100644 index 7ac6d21b93..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_management.schema +++ /dev/null @@ -1,203 +0,0 @@ -%% ---------------------------------------------------------------------------- -%% RabbitMQ Management Plugin -%% -%% See http://www.rabbitmq.com/management.html for details -%% ---------------------------------------------------------------------------- - - % {rabbitmq_management, - % [%% Pre-Load schema definitions from the following JSON file. See -%% http://www.rabbitmq.com/management.html#load-definitions -%% -%% {load_definitions, "/path/to/schema.json"}, -{mapping, "management.load_definitions", "rabbitmq_management.load_definitions", - [{datatype, string}, - {validators, ["file_accessible"]}]}. - -%% Log all requests to the management HTTP API to a file. -%% -%% {http_log_dir, "/path/to/access.log"}, - -{mapping, "management.http_log_dir", "rabbitmq_management.http_log_dir", - [{datatype, string}]}. - - -%% Change the port on which the HTTP listener listens, -%% specifying an interface for the web server to bind to. -%% Also set the listener to use SSL and provide SSL options. -%% -%% {listener, [{port, 12345}, -%% {ip, "127.0.0.1"}, -%% {ssl, true}, -%% {ssl_opts, [{cacertfile, "/path/to/cacert.pem"}, -%% {certfile, "/path/to/cert.pem"}, -%% {keyfile, "/path/to/key.pem"}]}]}, - -{mapping, "management.listener.port", "rabbitmq_management.listener.port", - [{datatype, integer}]}. - -{mapping, "management.listener.ip", "rabbitmq_management.listener.ip", - [{datatype, string}, - {validators, ["is_ip"]}]}. - -{mapping, "management.listener.ssl", "rabbitmq_management.listener.ssl", - [{datatype, {enum, [true, false]}}]}. - - -%% SSL options section ======================================================== - -{mapping, "management.listener.ssl_opts", "rabbitmq_management.listener.ssl_opts", [ - {datatype, {enum, [none]}} -]}. - -{translation, "rabbitmq_management.listener.ssl_opts", -fun(Conf) -> - case cuttlefish:conf_get("management.listener.ssl_opts", Conf, undefined) of - none -> []; - _ -> cuttlefish:invalid("Invalid management.listener.ssl_opts") - end -end}. - -{mapping, "management.listener.ssl_opts.verify", "rabbitmq_management.listener.ssl_opts.verify", [ - {datatype, {enum, [verify_peer, verify_none]}}]}. - -{mapping, "management.listener.ssl_opts.fail_if_no_peer_cert", "rabbitmq_management.listener.ssl_opts.fail_if_no_peer_cert", [ - {datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.cacertfile", "rabbitmq_management.listener.ssl_opts.cacertfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "management.listener.ssl_opts.certfile", "rabbitmq_management.listener.ssl_opts.certfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "management.listener.ssl_opts.cacerts.$name", "rabbitmq_management.listener.ssl_opts.cacerts", - [{datatype, string}]}. - -{translation, "rabbitmq_management.listener.ssl_opts.cacerts", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("management.listener.ssl_opts.cacerts", Conf), - [ list_to_binary(V) || {_, V} <- Settings ] -end}. - -{mapping, "management.listener.ssl_opts.cert", "rabbitmq_management.listener.ssl_opts.cert", - [{datatype, string}]}. - -{translation, "rabbitmq_management.listener.ssl_opts.cert", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("management.listener.ssl_opts.cert", Conf)) -end}. - -{mapping, "management.listener.ssl_opts.client_renegotiation", "rabbitmq_management.listener.ssl_opts.client_renegotiation", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.crl_check", "rabbitmq_management.listener.ssl_opts.crl_check", - [{datatype, [{enum, [true, false, peer, best_effort]}]}]}. - -{mapping, "management.listener.ssl_opts.depth", "rabbitmq_management.listener.ssl_opts.depth", - [{datatype, integer}, {validators, ["byte"]}]}. - -{mapping, "management.listener.ssl_opts.dh", "rabbitmq_management.listener.ssl_opts.dh", - [{datatype, string}]}. - -{translation, "rabbitmq_management.listener.ssl_opts.dh", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("management.listener.ssl_opts.dh", Conf)) -end}. - -{mapping, "management.listener.ssl_opts.dhfile", "rabbitmq_management.listener.ssl_opts.dhfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "management.listener.ssl_opts.honor_cipher_order", "rabbitmq_management.listener.ssl_opts.honor_cipher_order", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.key.RSAPrivateKey", "rabbitmq_management.listener.ssl_opts.key", - [{datatype, string}]}. - -{mapping, "management.listener.ssl_opts.key.DSAPrivateKey", "rabbitmq_management.listener.ssl_opts.key", - [{datatype, string}]}. - -{mapping, "management.listener.ssl_opts.key.PrivateKeyInfo", "rabbitmq_management.listener.ssl_opts.key", - [{datatype, string}]}. - -{translation, "rabbitmq_management.listener.ssl_opts.key", -fun(Conf) -> - case cuttlefish_variable:filter_by_prefix("management.listener.ssl_opts.key", Conf) of - [{[_,_,Key], Val}|_] -> {list_to_atom(Key), list_to_binary(Val)}; - _ -> undefined - end -end}. - -{mapping, "management.listener.ssl_opts.keyfile", "rabbitmq_management.listener.ssl_opts.keyfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. - -{mapping, "management.listener.ssl_opts.log_alert", "rabbitmq_management.listener.ssl_opts.log_alert", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.password", "rabbitmq_management.listener.ssl_opts.password", - [{datatype, string}]}. - -{mapping, "management.listener.ssl_opts.psk_identity", "rabbitmq_management.listener.ssl_opts.psk_identity", - [{datatype, string}]}. - -{mapping, "management.listener.ssl_opts.reuse_sessions", "rabbitmq_management.listener.ssl_opts.reuse_sessions", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.secure_renegotiate", "rabbitmq_management.listener.ssl_opts.secure_renegotiate", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "management.listener.ssl_opts.versions.$version", "rabbitmq_management.listener.ssl_opts.versions", - [{datatype, atom}]}. - -{translation, "rabbitmq_management.listener.ssl_opts.versions", -fun(Conf) -> - Settings = cuttlefish_variable:filter_by_prefix("management.listener.ssl_opts.versions", Conf), - [ V || {_, V} <- Settings ] -end}. - -%% =========================================================================== - - -%% One of 'basic', 'detailed' or 'none'. See -%% http://www.rabbitmq.com/management.html#fine-stats for more details. -%% {rates_mode, basic}, -{mapping, "management.rates_mode", "rabbitmq_management.rates_mode", - [{datatype, {enum, [basic, detailed, none]}}]}. - -%% Configure how long aggregated data (such as message rates and queue -%% lengths) is retained. Please read the plugin's documentation in -%% http://www.rabbitmq.com/management.html#configuration for more -%% details. -%% -%% {sample_retention_policies, -%% [{global, [{60, 5}, {3600, 60}, {86400, 1200}]}, -%% {basic, [{60, 5}, {3600, 60}]}, -%% {detailed, [{10, 5}]}]} -% ]}, - -{mapping, "management.sample_retention_policies.$section.$interval", - "rabbitmq_management.sample_retention_policies", - [{datatype, integer}]}. - -{translation, "rabbitmq_management.sample_retention_policies", -fun(Conf) -> - Global = cuttlefish_variable:filter_by_prefix("management.sample_retention_policies.global", Conf), - Basic = cuttlefish_variable:filter_by_prefix("management.sample_retention_policies.basic", Conf), - Detailed = cuttlefish_variable:filter_by_prefix("management.sample_retention_policies.detailed", Conf), - TranslateKey = fun("minute") -> 60; - ("hour") -> 3600; - ("day") -> 86400; - (Other) -> list_to_integer(Other) - end, - TranslatePolicy = fun(Section) -> - [ {TranslateKey(Key), Val} || {[_,_,_,Key], Val} <- Section ] - end, - [{global, TranslatePolicy(Global)}, - {basic, TranslatePolicy(Basic)}, - {detailed, TranslatePolicy(Detailed)}] -end}. - - -{validator, "is_dir", "is not directory", -fun(File) -> - ReadFile = file:list_dir(File), - element(1, ReadFile) == ok -end}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_metronome.schema b/test/config_schema_SUITE_data/schema/rabbitmq_metronome.schema deleted file mode 100644 index 53cf8f003e..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_metronome.schema +++ /dev/null @@ -1,9 +0,0 @@ - -{mapping, "metronome.exchange", "rabbitmq_metronome.exchange", - [{datatype, string}]}. - -{translation, "rabbitmq_metronome.exchange", -fun(Conf) -> - Exchange = cuttlefish:conf_get("metronome.exchange", Conf), - list_to_binary(Exchange) -end}.
\ No newline at end of file diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_mqtt.schema b/test/config_schema_SUITE_data/schema/rabbitmq_mqtt.schema deleted file mode 100644 index ffda10beaa..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_mqtt.schema +++ /dev/null @@ -1,248 +0,0 @@ -%% ---------------------------------------------------------------------------- -%% RabbitMQ MQTT Adapter -%% -%% See https://github.com/rabbitmq/rabbitmq-mqtt/blob/stable/README.md -%% for details -%% ---------------------------------------------------------------------------- - -% {rabbitmq_mqtt, -% [%% Set the default user name and password. Will be used as the default login -%% if a connecting client provides no other login details. -%% -%% Please note that setting this will allow clients to connect without -%% authenticating! -%% -%% {default_user, <<"guest">>}, -%% {default_pass, <<"guest">>}, - -{mapping, "mqtt.default_user", "rabbitmq_mqtt.default_user", [ - {datatype, string} -]}. - -{mapping, "mqtt.default_pass", "rabbitmq_mqtt.default_pass", [ - {datatype, string} -]}. - -{translation, "rabbitmq_mqtt.default_user", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("mqtt.default_user", Conf)) -end}. - -{translation, "rabbitmq_mqtt.default_pass", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("mqtt.default_pass", Conf)) -end}. - -%% Enable anonymous access. If this is set to false, clients MUST provide -%% login information in order to connect. See the default_user/default_pass -%% configuration elements for managing logins without authentication. -%% -%% {allow_anonymous, true}, - -{mapping, "mqtt.allow_anonymous", "rabbitmq_mqtt.allow_anonymous", - [{datatype, {enum, [true, false]}}]}. - -%% If you have multiple chosts, specify the one to which the -%% adapter connects. -%% -%% {vhost, <<"/">>}, - -{mapping, "mqtt.vhost", "rabbitmq_mqtt.vhost", [{datatype, string}]}. - -{translation, "rabbitmq_mqtt.vhost", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("mqtt.vhost", Conf)) -end}. - -%% Specify the exchange to which messages from MQTT clients are published. -%% -%% {exchange, <<"amq.topic">>}, - -{mapping, "mqtt.exchange", "rabbitmq_mqtt.exchange", [{datatype, string}]}. - -{translation, "rabbitmq_mqtt.exchange", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("mqtt.exchange", Conf)) -end}. - -%% Specify TTL (time to live) to control the lifetime of non-clean sessions. -%% -%% {subscription_ttl, 1800000}, -{mapping, "mqtt.subscription_ttl", "rabbitmq_mqtt.subscription_ttl", [ - {datatype, [{enum, [undefined, infinity]}, integer]} -]}. - -{translation, "rabbitmq_mqtt.subscription_ttl", -fun(Conf) -> - case cuttlefish:conf_get("mqtt.subscription_ttl", Conf, undefined) of - undefined -> undefined; - infinity -> undefined; - Ms -> Ms - end -end}. - -%% Set the prefetch count (governing the maximum number of unacknowledged -%% messages that will be delivered). -%% -%% {prefetch, 10}, -{mapping, "mqtt.prefetch", "rabbitmq_mqtt.prefetch", - [{datatype, integer}]}. - - -{mapping, "mqtt.retained_message_store", "rabbitmq_mqtt.retained_message_store", - [{datatype, atom}]}. - -{mapping, "mqtt.retained_message_store_dets_sync_interval", "rabbitmq_mqtt.retained_message_store_dets_sync_interval", - [{datatype, integer}]}. - - - -%% TCP/SSL Configuration (as per the broker configuration). -%% -%% {tcp_listeners, [1883]}, -%% {ssl_listeners, []}, - -{mapping, "mqtt.listeners.tcp", "rabbitmq_mqtt.tcp_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "mqtt.listeners.tcp.$name", "rabbitmq_mqtt.tcp_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbitmq_mqtt.tcp_listeners", -fun(Conf) -> - case cuttlefish:conf_get("mqtt.listeners.tcp", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("mqtt.listeners.tcp", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -{mapping, "mqtt.listeners.ssl", "rabbitmq_mqtt.ssl_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "mqtt.listeners.ssl.$name", "rabbitmq_mqtt.ssl_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbitmq_mqtt.ssl_listeners", -fun(Conf) -> - case cuttlefish:conf_get("mqtt.listeners.ssl", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("mqtt.listeners.ssl", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -%% Number of Erlang processes that will accept connections for the TCP -%% and SSL listeners. -%% -%% {num_tcp_acceptors, 10}, -%% {num_ssl_acceptors, 1}, - -{mapping, "mqtt.num_acceptors.ssl", "rabbitmq_mqtt.num_ssl_acceptors", [ - {datatype, integer} -]}. - -{mapping, "mqtt.num_acceptors.tcp", "rabbitmq_mqtt.num_tcp_acceptors", [ - {datatype, integer} -]}. - -{mapping, "mqtt.ssl_cert_login", "rabbitmq_mqtt.ssl_cert_login", [ - {datatype, {enum, [true, false]}}]}. - - -%% TCP/Socket options (as per the broker configuration). -%% -%% {tcp_listen_options, [{backlog, 128}, -%% {nodelay, true}]} -% ]}, - -%% TCP listener section ====================================================== - -{mapping, "mqtt.tcp_listen_options", "rabbitmq_mqtt.rabbit.tcp_listen_options", [ - {datatype, {enum, [none]}}]}. - -{translation, "rabbitmq_mqtt.rabbit.tcp_listen_options", -fun(Conf) -> - case cuttlefish:conf_get("mqtt.tcp_listen_options") of - none -> []; - _ -> cuttlefish:invalid("Invalid mqtt.tcp_listen_options") - end -end}. - -{mapping, "mqtt.tcp_listen_options.backlog", "rabbitmq_mqtt.tcp_listen_options.backlog", [ - {datatype, integer} -]}. - -{mapping, "mqtt.tcp_listen_options.nodelay", "rabbitmq_mqtt.tcp_listen_options.nodelay", [ - {datatype, {enum, [true, false]}} -]}. - -{mapping, "mqtt.tcp_listen_options.buffer", "rabbitmq_mqtt.tcp_listen_options.buffer", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.delay_send", "rabbitmq_mqtt.tcp_listen_options.delay_send", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.dontroute", "rabbitmq_mqtt.tcp_listen_options.dontroute", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.exit_on_close", "rabbitmq_mqtt.tcp_listen_options.exit_on_close", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.fd", "rabbitmq_mqtt.tcp_listen_options.fd", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.high_msgq_watermark", "rabbitmq_mqtt.tcp_listen_options.high_msgq_watermark", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.high_watermark", "rabbitmq_mqtt.tcp_listen_options.high_watermark", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.keepalive", "rabbitmq_mqtt.tcp_listen_options.keepalive", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.low_msgq_watermark", "rabbitmq_mqtt.tcp_listen_options.low_msgq_watermark", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.low_watermark", "rabbitmq_mqtt.tcp_listen_options.low_watermark", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.port", "rabbitmq_mqtt.tcp_listen_options.port", - [{datatype, integer}, {validators, ["port"]}]}. - -{mapping, "mqtt.tcp_listen_options.priority", "rabbitmq_mqtt.tcp_listen_options.priority", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.recbuf", "rabbitmq_mqtt.tcp_listen_options.recbuf", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.send_timeout", "rabbitmq_mqtt.tcp_listen_options.send_timeout", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.send_timeout_close", "rabbitmq_mqtt.tcp_listen_options.send_timeout_close", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.sndbuf", "rabbitmq_mqtt.tcp_listen_options.sndbuf", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.tos", "rabbitmq_mqtt.tcp_listen_options.tos", - [{datatype, integer}]}. - -{mapping, "mqtt.tcp_listen_options.linger.on", "rabbitmq_mqtt.tcp_listen_options.linger", - [{datatype, {enum, [true, false]}}]}. - -{mapping, "mqtt.tcp_listen_options.linger.timeout", "rabbitmq_mqtt.tcp_listen_options.linger", - [{datatype, integer}]}. - -{translation, "rabbitmq_mqtt.tcp_listen_options.linger", -fun(Conf) -> - LingerOn = cuttlefish:conf_get("mqtt.tcp_listen_options.linger.on", Conf, false), - LingerTimeout = cuttlefish:conf_get("mqtt.tcp_listen_options.linger.timeout", Conf, 0), - {LingerOn, LingerTimeout} -end}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_stomp.schema b/test/config_schema_SUITE_data/schema/rabbitmq_stomp.schema deleted file mode 100644 index b7619f0b28..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_stomp.schema +++ /dev/null @@ -1,110 +0,0 @@ -%% ========================================================================== -%% ---------------------------------------------------------------------------- -%% RabbitMQ Stomp Adapter -%% -%% See http://www.rabbitmq.com/stomp.html for details -%% ---------------------------------------------------------------------------- - -% {rabbitmq_stomp, -% [%% Network Configuration - the format is generally the same as for the broker - -%% Listen only on localhost (ipv4 & ipv6) on a specific port. -%% {tcp_listeners, [{"127.0.0.1", 61613}, -%% {"::1", 61613}]}, - -{mapping, "stomp.listeners.tcp", "rabbitmq_stomp.tcp_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "stomp.listeners.tcp.$name", "rabbitmq_stomp.tcp_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbitmq_stomp.tcp_listeners", -fun(Conf) -> - case cuttlefish:conf_get("stomp.listeners.tcp", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("stomp.listeners.tcp", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -{mapping, "stomp.listeners.ssl", "rabbitmq_stomp.ssl_listeners",[ - {datatype, {enum, [none]}} -]}. - -{mapping, "stomp.listeners.ssl.$name", "rabbitmq_stomp.ssl_listeners",[ - {datatype, [integer, ip]} -]}. - -{translation, "rabbitmq_stomp.ssl_listeners", -fun(Conf) -> - case cuttlefish:conf_get("stomp.listeners.ssl", Conf, undefined) of - none -> []; - _ -> - Settings = cuttlefish_variable:filter_by_prefix("stomp.listeners.ssl", Conf), - [ V || {_, V} <- Settings ] - end -end}. - -%% Number of Erlang processes that will accept connections for the TCP -%% and SSL listeners. -%% -%% {num_tcp_acceptors, 10}, -%% {num_ssl_acceptors, 1}, - -{mapping, "stomp.num_acceptors.ssl", "rabbitmq_stomp.num_ssl_acceptors", [ - {datatype, integer} -]}. - -{mapping, "stomp.num_acceptors.tcp", "rabbitmq_stomp.num_tcp_acceptors", [ - {datatype, integer} -]}. - -%% Additional SSL options - -%% Extract a name from the client's certificate when using SSL. -%% -%% {ssl_cert_login, true}, - -{mapping, "stomp.ssl_cert_login", "rabbitmq_stomp.ssl_cert_login", - [{datatype, {enum, [true, false]}}]}. - -%% Set a default user name and password. This is used as the default login -%% whenever a CONNECT frame omits the login and passcode headers. -%% -%% Please note that setting this will allow clients to connect without -%% authenticating! -%% -%% {default_user, [{login, "guest"}, -%% {passcode, "guest"}]}, - -{mapping, "stomp.default_vhost", "rabbitmq_stomp.default_vhost", [ - {datatype, string} -]}. - -{translation, "rabbitmq_stomp.default_vhost", -fun(Conf) -> - list_to_binary(cuttlefish:conf_get("stomp.default_vhost", Conf, "/")) -end}. - -{mapping, "stomp.default_user", "rabbitmq_stomp.default_user.login", [ - {datatype, string} -]}. - -{mapping, "stomp.default_pass", "rabbitmq_stomp.default_user.passcode", [ - {datatype, string} -]}. - -%% If a default user is configured, or you have configured use SSL client -%% certificate based authentication, you can choose to allow clients to -%% omit the CONNECT frame entirely. If set to true, the client is -%% automatically connected as the default user or user supplied in the -%% SSL certificate whenever the first frame sent on a session is not a -%% CONNECT frame. -%% -%% {implicit_connect, true} -% ]}, -{mapping, "stomp.implicit_connect", "rabbitmq_stomp.implicit_connect", - [{datatype, {enum, [true, false]}}]}. diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_web_mqtt.schema b/test/config_schema_SUITE_data/schema/rabbitmq_web_mqtt.schema deleted file mode 100644 index acdab62c32..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_web_mqtt.schema +++ /dev/null @@ -1,44 +0,0 @@ -{mapping, "web_mqtt.num_acceptors.tcp", "rabbitmq_web_mqtt.num_tcp_acceptors", - [{datatype, integer}]}. -{mapping, "web_mqtt.num_acceptors.ssl", "rabbitmq_web_mqtt.num_ssl_acceptors", - [{datatype, integer}]}. - -{mapping, "web_mqtt.tcp.port", "rabbitmq_web_mqtt.tcp_config.port", - [{datatype, integer}]}. -{mapping, "web_mqtt.tcp.backlog", "rabbitmq_web_mqtt.tcp_config.backlog", - [{datatype, integer}]}. -{mapping, "web_mqtt.tcp.ip", "rabbitmq_web_mqtt.tcp_config.ip", - [{datatype, string}, {validators, ["is_ip"]}]}. - - -{mapping, "web_mqtt.ssl.port", "rabbitmq_web_mqtt.ssl_config.port", - [{datatype, integer}]}. -{mapping, "web_mqtt.ssl.backlog", "rabbitmq_web_mqtt.ssl_config.backlog", - [{datatype, integer}]}. -{mapping, "web_mqtt.ssl.ip", "rabbitmq_web_mqtt.ssl_config.ip", - [{datatype, string}, {validators, ["is_ip"]}]}. -{mapping, "web_mqtt.ssl.certfile", "rabbitmq_web_mqtt.ssl_config.certfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_mqtt.ssl.keyfile", "rabbitmq_web_mqtt.ssl_config.keyfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_mqtt.ssl.cacertfile", "rabbitmq_web_mqtt.ssl_config.cacertfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_mqtt.ssl.password", "rabbitmq_web_mqtt.ssl_config.password", - [{datatype, string}]}. - - -{mapping, "web_mqtt.cowboy_opts.max_empty_lines", "rabbitmq_web_mqtt.cowboy_opts.max_empty_lines", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.max_header_name_length", "rabbitmq_web_mqtt.cowboy_opts.max_header_name_length", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.max_header_value_length", "rabbitmq_web_mqtt.cowboy_opts.max_header_value_length", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.max_headers", "rabbitmq_web_mqtt.cowboy_opts.max_headers", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.max_keepalive", "rabbitmq_web_mqtt.cowboy_opts.max_keepalive", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.max_request_line_length", "rabbitmq_web_mqtt.cowboy_opts.max_request_line_length", - [{datatype, integer}]}. -{mapping, "web_mqtt.cowboy_opts.timeout", "rabbitmq_web_mqtt.cowboy_opts.timeout", - [{datatype, integer}]}. - diff --git a/test/config_schema_SUITE_data/schema/rabbitmq_web_stomp.schema b/test/config_schema_SUITE_data/schema/rabbitmq_web_stomp.schema deleted file mode 100644 index 389da07d14..0000000000 --- a/test/config_schema_SUITE_data/schema/rabbitmq_web_stomp.schema +++ /dev/null @@ -1,64 +0,0 @@ -{mapping, "web_stomp.port", "rabbitmq_web_stomp.port", - [{datatype, integer}]}. - -{mapping, "web_stomp.ws_frame", "rabbitmq_web_stomp.ws_frame", - [{datatype, {enum, [binary, text]}}]}. - -{mapping, "web_stomp.num_acceptors.tcp", "rabbitmq_web_stomp.num_tcp_acceptors", - [{datatype, integer}]}. - -{mapping, "web_stomp.num_acceptors.ssl", "rabbitmq_web_stomp.num_ssl_acceptors", - [{datatype, integer}]}. - -{mapping, "web_stomp.tcp.port", "rabbitmq_web_stomp.tcp_config.port", - [{datatype, integer}]}. -{mapping, "web_stomp.tcp.backlog", "rabbitmq_web_stomp.tcp_config.backlog", - [{datatype, integer}]}. -{mapping, "web_stomp.tcp.ip", "rabbitmq_web_stomp.tcp_config.ip", - [{datatype, string}, {validators, ["is_ip"]}]}. - - -{mapping, "web_stomp.ssl.port", "rabbitmq_web_stomp.ssl_config.port", - [{datatype, integer}]}. -{mapping, "web_stomp.ssl.backlog", "rabbitmq_web_stomp.ssl_config.backlog", - [{datatype, integer}]}. -{mapping, "web_stomp.ssl.ip", "rabbitmq_web_stomp.ssl_config.ip", - [{datatype, string}, {validators, ["is_ip"]}]}. -{mapping, "web_stomp.ssl.certfile", "rabbitmq_web_stomp.ssl_config.certfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_stomp.ssl.keyfile", "rabbitmq_web_stomp.ssl_config.keyfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_stomp.ssl.cacertfile", "rabbitmq_web_stomp.ssl_config.cacertfile", - [{datatype, string}, {validators, ["file_accessible"]}]}. -{mapping, "web_stomp.ssl.password", "rabbitmq_web_stomp.ssl_config.password", - [{datatype, string}]}. - - -{mapping, "web_stomp.cowboy_opts.max_empty_lines", "rabbitmq_web_stomp.cowboy_opts.max_empty_lines", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.max_header_name_length", "rabbitmq_web_stomp.cowboy_opts.max_header_name_length", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.max_header_value_length", "rabbitmq_web_stomp.cowboy_opts.max_header_value_length", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.max_headers", "rabbitmq_web_stomp.cowboy_opts.max_headers", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.max_keepalive", "rabbitmq_web_stomp.cowboy_opts.max_keepalive", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.max_request_line_length", "rabbitmq_web_stomp.cowboy_opts.max_request_line_length", - [{datatype, integer}]}. -{mapping, "web_stomp.cowboy_opts.timeout", "rabbitmq_web_stomp.cowboy_opts.timeout", - [{datatype, integer}]}. - - -{mapping, "web_stomp.sockjs_opts.url", "rabbitmq_web_stomp.sockjs_opts.sockjs_url", - [{datatype, string}]}. -{mapping, "web_stomp.sockjs_opts.websocket", "rabbitmq_web_stomp.sockjs_opts.websocket", - [{datatype, {enum, [true, false]}}]}. -{mapping, "web_stomp.sockjs_opts.cookie_needed", "rabbitmq_web_stomp.sockjs_opts.cookie_needed", - [{datatype, {enum, [true, false]}}]}. -{mapping, "web_stomp.sockjs_opts.heartbeat_delay", "rabbitmq_web_stomp.sockjs_opts.heartbeat_delay", - [{datatype, integer}]}. -{mapping, "web_stomp.sockjs_opts.disconnect_delay", "rabbitmq_web_stomp.sockjs_opts.disconnect_delay", - [{datatype, integer}]}. -{mapping, "web_stomp.sockjs_opts.response_limit", "rabbitmq_web_stomp.sockjs_opts.response_limit", - [{datatype, integer}]}. diff --git a/test/config_schema_SUITE_data/snippets.config b/test/config_schema_SUITE_data/snippets.config index abfc28441e..8c4319fa53 100644 --- a/test/config_schema_SUITE_data/snippets.config +++ b/test/config_schema_SUITE_data/snippets.config @@ -94,12 +94,25 @@ default_permissions.write = .*", {default_permissions, [<<".*">>, <<".*">>, <<".*">>]}]}],[]} , {13, -"cluster_nodes.disc.1 = rabbit@hostname1 -cluster_nodes.disc.2 = rabbit@hostname2", +"autocluster.classic_config.nodes.peer1 = rabbit@hostname1 +autocluster.classic_config.nodes.peer2 = rabbit@hostname2 +autocluster.classic_config.node_type = disc", [{rabbit, [ {cluster_nodes, {[rabbit@hostname2,rabbit@hostname1], disc}} ]}],[]} , +{13.1, +"autocluster.classic_config.nodes.peer1 = rabbit@hostname1 +autocluster.classic_config.nodes.peer2 = rabbit@hostname2 +autocluster.classic_config.node_type = disk", +[{rabbit, [ + {cluster_nodes, {[rabbit@hostname2,rabbit@hostname1], disc}} +]}],[]} +, +{13.2, +"autocluster.classic_config.node_type = ram", +[],[]} +, {14, "tcp_listen_options.backlog = 128 tcp_listen_options.nodelay = true diff --git a/test/dynamic_ha_SUITE.erl b/test/dynamic_ha_SUITE.erl index bba7fad707..502e3a7e86 100644 --- a/test/dynamic_ha_SUITE.erl +++ b/test/dynamic_ha_SUITE.erl @@ -61,7 +61,8 @@ groups() -> ]}, {cluster_size_3, [], [ change_policy, - rapid_change + rapid_change, + nodes_policy_should_pick_master_from_its_params % FIXME: Re-enable those tests when the know issues are % fixed. %failing_random_policies, @@ -258,6 +259,48 @@ promote_on_shutdown(Config) -> durable = true}), ok. +nodes_policy_should_pick_master_from_its_params(Config) -> + [A | _] = rabbit_ct_broker_helpers:get_node_configs(Config, + nodename), + + Ch = rabbit_ct_client_helpers:open_channel(Config, A), + ?assertEqual(true, apply_policy_to_declared_queue(Config, Ch, [A], + [all])), + %% --> Master: A + %% Slaves: [B, C] or [C, B] + Info = find_queue(?QNAME, A), + SSPids = proplists:get_value(synchronised_slave_pids, Info), + + %% Choose slave that isn't the first sync slave. Cover a bug that always + %% chose the first, even if it was not part of the policy + LastSlave = node(lists:last(SSPids)), + ?assertEqual(true, apply_policy_to_declared_queue(Config, Ch, [A], + [{nodes, [LastSlave]}])), + %% --> Master: B or C (depends on the order of current slaves) + %% Slaves: [] + + %% Now choose a new master that isn't synchronised. The previous + %% policy made sure that the queue only runs on one node (the last + %% from the initial synchronised list). Thus, by taking the first + %% node from this list, we know it is not synchronised. + %% + %% Because the policy doesn't cover any synchronised slave, RabbitMQ + %% should instead use an existing synchronised slave as the new master, + %% even though that isn't in the policy. + ?assertEqual(true, apply_policy_to_declared_queue(Config, Ch, [A], + [{nodes, [LastSlave, A]}])), + %% --> Master: B or C (same as previous policy) + %% Slaves: [A] + + NewMaster = node(erlang:hd(SSPids)), + ?assertEqual(true, apply_policy_to_declared_queue(Config, Ch, [A], + [{nodes, [NewMaster]}])), + %% --> Master: B or C (the other one compared to previous policy) + %% Slaves: [] + + amqp_channel:call(Ch, #'queue.delete'{queue = ?QNAME}), + _ = rabbit_ct_broker_helpers:clear_policy(Config, A, ?POLICY). + random_policy(Config) -> run_proper(fun prop_random_policy/1, [Config]). @@ -364,9 +407,8 @@ prop_random_policy(Config) -> Policies, non_empty(list(policy_gen(Nodes))), test_random_policy(Config, Nodes, Policies)). -test_random_policy(Config, Nodes, Policies) -> +apply_policy_to_declared_queue(Config, Ch, Nodes, Policies) -> [NodeA | _] = Nodes, - Ch = rabbit_ct_client_helpers:open_channel(Config, NodeA), amqp_channel:call(Ch, #'queue.declare'{queue = ?QNAME}), %% Add some load so mirrors can be busy synchronising rabbit_ct_client_helpers:publish(Ch, ?QNAME, 100000), @@ -375,7 +417,12 @@ test_random_policy(Config, Nodes, Policies) -> %% Give it some time to generate all internal notifications timer:sleep(2000), %% Check the result - Result = wait_for_last_policy(?QNAME, NodeA, Policies, 30), + wait_for_last_policy(?QNAME, NodeA, Policies, 30). + +test_random_policy(Config, Nodes, Policies) -> + [NodeA | _] = Nodes, + Ch = rabbit_ct_client_helpers:open_channel(Config, NodeA), + Result = apply_policy_to_declared_queue(Config, Ch, Nodes, Policies), %% Cleanup amqp_channel:call(Ch, #'queue.delete'{queue = ?QNAME}), _ = rabbit_ct_broker_helpers:clear_policy(Config, NodeA, ?POLICY), diff --git a/test/unit_SUITE.erl b/test/unit_SUITE.erl index 5faeccdaab..b270a3a432 100644 --- a/test/unit_SUITE.erl +++ b/test/unit_SUITE.erl @@ -24,7 +24,8 @@ all() -> [ - {group, parallel_tests} + {group, parallel_tests}, + {group, sequential_tests} ]. groups() -> @@ -41,6 +42,10 @@ groups() -> ]}, content_framing, content_transcoding, + encrypt_decrypt, + encrypt_decrypt_term, + decrypt_config, + rabbitmqctl_encode, pg_local, pmerge, plmerge, @@ -63,12 +68,36 @@ groups() -> {vm_memory_monitor, [parallel], [ parse_line_linux ]} + ]}, + {sequential_tests, [], [ + decrypt_start_app, + decrypt_start_app_file, + decrypt_start_app_undefined, + decrypt_start_app_wrong_passphrase ]} ]. init_per_group(_, Config) -> Config. end_per_group(_, Config) -> Config. +init_per_testcase(TC, Config) when TC =:= decrypt_start_app; + TC =:= decrypt_start_app_file; + TC =:= decrypt_start_app_undefined -> + application:load(rabbit), + Config; +init_per_testcase(_, Config) -> + Config. + +end_per_testcase(TC, _Config) when TC =:= decrypt_start_app; + TC =:= decrypt_start_app_file; + TC =:= decrypt_start_app_undefined -> + application:unload(rabbit), + application:unload(rabbit_shovel_test); +end_per_testcase(decrypt_config, _Config) -> + application:unload(rabbit); +end_per_testcase(_TC, _Config) -> + ok. + %% ------------------------------------------------------------------- %% Argument parsing. %% ------------------------------------------------------------------- @@ -233,6 +262,254 @@ prepend_check(HeaderKey, HeaderTable, Headers) -> rabbit_misc:table_lookup(Invalid, HeaderKey), Headers1. +encrypt_decrypt(_Config) -> + %% Take all available block ciphers. + Hashes = rabbit_pbe:supported_hashes(), + Ciphers = rabbit_pbe:supported_ciphers(), + %% For each cipher, try to encrypt and decrypt data sizes from 0 to 64 bytes + %% with a random passphrase. + _ = [begin + PassPhrase = crypto:strong_rand_bytes(16), + Iterations = rand:uniform(100), + Data = crypto:strong_rand_bytes(64), + [begin + Expected = binary:part(Data, 0, Len), + Enc = rabbit_pbe:encrypt(C, H, Iterations, PassPhrase, Expected), + Expected = iolist_to_binary(rabbit_pbe:decrypt(C, H, Iterations, PassPhrase, Enc)) + end || Len <- lists:seq(0, byte_size(Data))] + end || H <- Hashes, C <- Ciphers], + ok. + +encrypt_decrypt_term(_Config) -> + %% Take all available block ciphers. + Hashes = rabbit_pbe:supported_hashes(), + Ciphers = rabbit_pbe:supported_ciphers(), + %% Different Erlang terms to try encrypting. + DataSet = [ + 10000, + [5672], + [{"127.0.0.1", 5672}, + {"::1", 5672}], + [{connection, info}, {channel, info}], + [{cacertfile, "/path/to/testca/cacert.pem"}, + {certfile, "/path/to/server/cert.pem"}, + {keyfile, "/path/to/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}], + [<<".*">>, <<".*">>, <<".*">>] + ], + _ = [begin + PassPhrase = crypto:strong_rand_bytes(16), + Iterations = rand:uniform(100), + Enc = rabbit_pbe:encrypt_term(C, H, Iterations, PassPhrase, Data), + Data = rabbit_pbe:decrypt_term(C, H, Iterations, PassPhrase, Enc) + end || H <- Hashes, C <- Ciphers, Data <- DataSet], + ok. + +decrypt_config(_Config) -> + %% Take all available block ciphers. + Hashes = rabbit_pbe:supported_hashes(), + Ciphers = rabbit_pbe:supported_ciphers(), + Iterations = [1, 10, 100, 1000], + %% Loop through all hashes, ciphers and iterations. + _ = [begin + PassPhrase = crypto:strong_rand_bytes(16), + do_decrypt_config({C, H, I, PassPhrase}) + end || H <- Hashes, C <- Ciphers, I <- Iterations], + ok. + +do_decrypt_config(Algo = {C, H, I, P}) -> + application:load(rabbit), + RabbitConfig = application:get_all_env(rabbit), + %% Encrypt a few values in configuration. + %% Common cases. + _ = [encrypt_value(Key, Algo) || Key <- [ + tcp_listeners, + num_tcp_acceptors, + ssl_options, + vm_memory_high_watermark, + default_pass, + default_permissions, + cluster_nodes, + auth_mechanisms, + msg_store_credit_disc_bound]], + %% Special case: encrypt a value in a list. + {ok, [LoopbackUser]} = application:get_env(rabbit, loopback_users), + EncLoopbackUser = rabbit_pbe:encrypt_term(C, H, I, P, LoopbackUser), + application:set_env(rabbit, loopback_users, [{encrypted, EncLoopbackUser}]), + %% Special case: encrypt a value in a key/value list. + {ok, TCPOpts} = application:get_env(rabbit, tcp_listen_options), + {_, Backlog} = lists:keyfind(backlog, 1, TCPOpts), + {_, Linger} = lists:keyfind(linger, 1, TCPOpts), + EncBacklog = rabbit_pbe:encrypt_term(C, H, I, P, Backlog), + EncLinger = rabbit_pbe:encrypt_term(C, H, I, P, Linger), + TCPOpts1 = lists:keyreplace(backlog, 1, TCPOpts, {backlog, {encrypted, EncBacklog}}), + TCPOpts2 = lists:keyreplace(linger, 1, TCPOpts1, {linger, {encrypted, EncLinger}}), + application:set_env(rabbit, tcp_listen_options, TCPOpts2), + %% Decrypt configuration. + rabbit:decrypt_config([rabbit], Algo), + %% Check that configuration was decrypted properly. + RabbitConfig = application:get_all_env(rabbit), + application:unload(rabbit), + ok. + +encrypt_value(Key, {C, H, I, P}) -> + {ok, Value} = application:get_env(rabbit, Key), + EncValue = rabbit_pbe:encrypt_term(C, H, I, P, Value), + application:set_env(rabbit, Key, {encrypted, EncValue}). + +decrypt_start_app(Config) -> + do_decrypt_start_app(Config, "hello"). + +decrypt_start_app_file(Config) -> + do_decrypt_start_app(Config, {file, ?config(data_dir, Config) ++ "/rabbit_shovel_test.passphrase"}). + +do_decrypt_start_app(Config, Passphrase) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, decoder_config, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, Passphrase} + ]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure *after* the decrypting has been done. + try + rabbit:start_apps([rabbit_shovel_test]) + catch _:_ -> + ok + end, + %% Check if the values have been decrypted. + {ok, Shovels} = application:get_env(rabbit_shovel_test, shovels), + {_, FirstShovel} = lists:keyfind(my_first_shovel, 1, Shovels), + {_, Sources} = lists:keyfind(sources, 1, FirstShovel), + {_, Brokers} = lists:keyfind(brokers, 1, Sources), + ["amqp://fred:secret@host1.domain/my_vhost", + "amqp://john:secret@host2.domain/my_vhost"] = Brokers, + ok. + +decrypt_start_app_undefined(Config) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, decoder_config, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000} + %% No passphrase option! + ]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure during decryption because the passphrase is missing. + try + rabbit:start_apps([rabbit_shovel_test]) + catch + exit:{bad_configuration,decoder_config} -> ok; + _:_ -> exit(unexpected_exception) + end. + +decrypt_start_app_wrong_passphrase(Config) -> + %% Configure rabbit for decrypting configuration. + application:set_env(rabbit, decoder_config, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, "wrong passphrase"} + ]), + %% Add the path to our test application. + code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), + %% Attempt to start our test application. + %% + %% We expect a failure during decryption because the passphrase is wrong. + try + rabbit:start_apps([rabbit_shovel_test]) + catch + exit:{decryption_error,_,_} -> ok; + _:_ -> exit(unexpected_exception) + end. + +rabbitmqctl_encode(_Config) -> + % list ciphers and hashes + {ok, _} = rabbit_control_pbe:encode(true, false, undefined, undefined, undefined, undefined, undefined), + {ok, _} = rabbit_control_pbe:encode(false, true, undefined, undefined, undefined, undefined, undefined), + % incorrect ciphers, hashes and iteration number + {error, _} = rabbit_control_pbe:encode(false, false, undefined, funny_cipher, undefined, undefined, undefined), + {error, _} = rabbit_control_pbe:encode(false, false, undefined, undefined, funny_hash, undefined, undefined), + {error, _} = rabbit_control_pbe:encode(false, false, undefined, undefined, undefined, -1, undefined), + {error, _} = rabbit_control_pbe:encode(false, false, undefined, undefined, undefined, 0, undefined), + % incorrect number of arguments + {error, _} = rabbit_control_pbe:encode( + false, false, + false, % encrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [] + ), + {error, _} = rabbit_control_pbe:encode( + false, false, + false, % encrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [undefined] + ), + {error, _} = rabbit_control_pbe:encode( + false, false, + false, % encrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [undefined, undefined, undefined] + ), + + % encrypt/decrypt + % string + rabbitmqctl_encode_encrypt_decrypt("foobar"), + % binary + rabbitmqctl_encode_encrypt_decrypt("<<\"foobar\">>"), + % tuple + rabbitmqctl_encode_encrypt_decrypt("{password,<<\"secret\">>}"), + + ok. + +rabbitmqctl_encode_encrypt_decrypt(Secret) -> + PassPhrase = "passphrase", + {ok, Output} = rabbit_control_pbe:encode( + false, false, + false, % encrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [Secret, PassPhrase] + ), + {encrypted, Encrypted} = rabbit_control_pbe:evaluate_input_as_term(lists:flatten(Output)), + + {ok, Result} = rabbit_control_pbe:encode( + false, false, + true, % decrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase] + ), + Secret = lists:flatten(Result), + % decrypt with {encrypted, ...} form as input + {ok, Result} = rabbit_control_pbe:encode( + false, false, + true, % decrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase] + ), + + % wrong passphrase + {error, _} = rabbit_control_pbe:encode( + false, false, + true, % decrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [Encrypted])), PassPhrase ++ " "] + ), + {error, _} = rabbit_control_pbe:encode( + false, false, + true, % decrypt + rabbit_pbe:default_cipher(), rabbit_pbe:default_hash(), rabbit_pbe:default_iterations(), + [lists:flatten(io_lib:format("~p", [{encrypted, Encrypted}])), PassPhrase ++ " "] + ) + . + %% ------------------------------------------------------------------- %% pg_local. %% ------------------------------------------------------------------- diff --git a/test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app b/test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app new file mode 100644 index 0000000000..a8481c9aa4 --- /dev/null +++ b/test/unit_SUITE_data/lib/rabbit_shovel_test/ebin/rabbit_shovel_test.app @@ -0,0 +1,46 @@ +{application, rabbit_shovel_test, + [{description, "Test .app file for tests for encrypting configuration"}, + {vsn, ""}, + {modules, []}, + {env, [ {shovels, [ {my_first_shovel, + [ {sources, + [ {brokers, [ {encrypted, <<"CfJXuka/uJYsqAtiJnwKpSY4moMPcOBh4sO8XDcdmhXbVYGKCDLKEilWPMfvOAQ2lN1BQneGn6bvDZi2+gDu6iHVKfafQAZSv8zcsVB3uYdBXFzqTCWO8TAsgG6LUMPT">>} + , {encrypted, <<"dBO6n+G1OiBwZeLXhvmNYeTE57nhBOmicUBF34zo4nQjerzQaNoEk8GA2Ts5PzMhYeO6U6Y9eEmheqIr9Gzh2duLZic65ZMQtIKNpWcZJllEhGpk7aV1COr23Yur9fWG">>} + ]} + , {declarations, [ {'exchange.declare', + [ {exchange, <<"my_fanout">>} + , {type, <<"fanout">>} + , durable + ]} + , {'queue.declare', + [{arguments, + [{<<"x-message-ttl">>, long, 60000}]}]} + , {'queue.bind', + [ {exchange, <<"my_direct">>} + , {queue, <<>>} + ]} + ]} + ]} + , {destinations, + [ {broker, "amqp://"} + , {declarations, [ {'exchange.declare', + [ {exchange, <<"my_direct">>} + , {type, <<"direct">>} + , durable + ]} + ]} + ]} + , {queue, <<>>} + , {prefetch_count, 10} + , {ack_mode, on_confirm} + , {publish_properties, [ {delivery_mode, 2} ]} + , {add_forward_headers, true} + , {publish_fields, [ {exchange, <<"my_direct">>} + , {routing_key, <<"from_shovel">>} + ]} + , {reconnect_delay, 5} + ]} + ]} + ]}, + + {applications, [kernel, stdlib]}]}. diff --git a/test/unit_SUITE_data/rabbit_shovel_test.passphrase b/test/unit_SUITE_data/rabbit_shovel_test.passphrase new file mode 100644 index 0000000000..ce01362503 --- /dev/null +++ b/test/unit_SUITE_data/rabbit_shovel_test.passphrase @@ -0,0 +1 @@ +hello |
