diff --git a/.gitignore b/.gitignore
index 7a7b6d9dc61a..a42a3ab53f68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,12 +6,15 @@
cover/
debug/
deps/
+debug/
doc/
ebin/
etc/
logs/
plugins/
+PACKAGES/
+
rabbit.d
# Generated sources files.
@@ -43,3 +46,5 @@ rabbitmq-server-*.zip
# Tracing tools
*-ttb
*.ti
+
+PACKAGES/*
diff --git a/.travis.yml b/.travis.yml
index 6d9dbc0b7137..da19ebc30273 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,6 @@
sudo: false
+services:
+ - docker
language: erlang
notifications:
email:
@@ -11,14 +13,20 @@ otp_release:
- "R16B03-1"
- "17.5"
- "18.0"
+env:
+ matrix:
+ - GROUP=1 GROUP=2
# The checkout made by Travis is a "detached HEAD". We switch back
# to a tag or a branch. This pleases our git_rmq fetch method in
# rabbitmq-components.mk and the proper tag/branch is selected in
# dependencies too.
-before_script: (test "$TRAVIS_TAG" && git checkout "$TRAVIS_TAG") || (test "$TRAVIS_BRANCH" && git checkout "$TRAVIS_BRANCH")
+before_script:
+ - ([ "${GROUP}" = "1" ] && ((test "$TRAVIS_TAG" && git checkout "$TRAVIS_TAG") || (test "$TRAVIS_BRANCH" && git checkout "$TRAVIS_BRANCH")) || /bin/true)
-script: travis_wait make tests
+script:
+ - ([ "${GROUP}" = "1" ] && travis_wait make tests)
+ - ([ "${GROUP}" = "2" ] && sh ./scripts/travis_test_ocf_ra.sh)
cache:
apt: true
diff --git a/Makefile b/Makefile
index 026c05edb468..924160849672 100644
--- a/Makefile
+++ b/Makefile
@@ -129,7 +129,8 @@ $(TARGETS_IN_RABBITMQ_TEST): $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \
grep -E '^xmlto version 0\.0\.([0-9]|1[1-8])$$' >/dev/null || \
opt='--stringparam man.indent.verbatims=0' ; \
xsltproc --novalid $(DOCS_DIR)/examples-to-end.xsl $< > $<.tmp && \
- (xmlto -o $(DOCS_DIR) $$opt man $< 2>&1 | (grep -qv '^Note: Writing' || :)) && \
+ xmlto -vv -o $(DOCS_DIR) $$opt man $< 2>&1 | (grep -v '^Note: Writing' || :) && \
+ test -f $@ && \
rm $<.tmp
# Use tmp files rather than a pipeline so that we get meaningful errors
@@ -336,7 +337,8 @@ SCRIPTS = rabbitmq-defaults \
rabbitmq-env \
rabbitmq-server \
rabbitmqctl \
- rabbitmq-plugins
+ rabbitmq-plugins \
+ cuttlefish
WINDOWS_SCRIPTS = rabbitmq-defaults.bat \
rabbitmq-echopid.bat \
@@ -344,7 +346,8 @@ WINDOWS_SCRIPTS = rabbitmq-defaults.bat \
rabbitmq-plugins.bat \
rabbitmq-server.bat \
rabbitmq-service.bat \
- rabbitmqctl.bat
+ rabbitmqctl.bat \
+ cuttlefish
UNIX_TO_DOS ?= todos
@@ -355,7 +358,7 @@ install: install-erlapp install-scripts
install-erlapp: dist
$(verbose) mkdir -p $(DESTDIR)$(RMQ_ERLAPP_DIR)
- $(inst_verbose) cp -r include ebin plugins LICENSE* INSTALL \
+ $(inst_verbose) cp -r include ebin plugins priv LICENSE* INSTALL \
$(DESTDIR)$(RMQ_ERLAPP_DIR)
$(verbose) echo "Put your EZs here and use rabbitmq-plugins to enable them." \
> $(DESTDIR)$(RMQ_ERLAPP_DIR)/plugins/README
@@ -385,18 +388,18 @@ install-man: manpages
$(inst_verbose) sections=$$(ls -1 docs/*.[1-9] \
| sed -E 's/.*\.([1-9])$$/\1/' | uniq | sort); \
for section in $$sections; do \
- mkdir -p $(DESTDIR)$(MANDIR)/man$$section; \
- for manpage in $(DOCS_DIR)/*.$$section; do \
- gzip < $$manpage \
+ mkdir -p $(DESTDIR)$(MANDIR)/man$$section; \
+ for manpage in $(DOCS_DIR)/*.$$section; do \
+ gzip < $$manpage \
> $(DESTDIR)$(MANDIR)/man$$section/$$(basename $$manpage).gz; \
- done; \
- done
+ done; \
+ done
install-windows: install-windows-erlapp install-windows-scripts install-windows-docs
install-windows-erlapp: dist
$(verbose) mkdir -p $(DESTDIR)$(WINDOWS_PREFIX)
- $(inst_verbose) cp -r include ebin plugins LICENSE* INSTALL \
+ $(inst_verbose) cp -r include ebin plugins priv LICENSE* INSTALL \
$(DESTDIR)$(WINDOWS_PREFIX)
$(verbose) echo "Put your EZs here and use rabbitmq-plugins.bat to enable them." \
> $(DESTDIR)$(WINDOWS_PREFIX)/plugins/README.txt
@@ -449,3 +452,4 @@ package-rpm-suse package-windows package-standalone-macosx \
package-generic-unix: $(PACKAGES_SOURCE_DIST_FILE)
$(verbose) $(MAKE) -C packaging $@ \
SOURCE_DIST_FILE=$(abspath $(PACKAGES_SOURCE_DIST_FILE))
+
diff --git a/docs/README-for-packages b/docs/README-for-packages
index 35a1523ac3fa..f26889b6408f 100644
--- a/docs/README-for-packages
+++ b/docs/README-for-packages
@@ -18,3 +18,7 @@ An example configuration file is provided in the same directory as
this README. Copy it to /etc/rabbitmq/rabbitmq.config to use it. The
RabbitMQ server must be restarted after changing the configuration
file.
+
+An example policy file for HA queues is provided in the same directory
+as this README. Copy and chmod +x it to
+/usr/local/sbin/set_rabbitmq_policy to use it with the Pacemaker OCF RA.
diff --git a/docs/advanced.config.example b/docs/advanced.config.example
new file mode 100644
index 000000000000..82a1c000e1a4
--- /dev/null
+++ b/docs/advanced.config.example
@@ -0,0 +1,109 @@
+[
+
+
+ %% ----------------------------------------------------------------------------
+ %% Advanced Erlang Networking/Clustering Options.
+ %%
+ %% See http://www.rabbitmq.com/clustering.html for details
+ %% ----------------------------------------------------------------------------
+ %% Sets the net_kernel tick time.
+ %% Please see http://erlang.org/doc/man/kernel_app.html and
+ %% http://www.rabbitmq.com/nettick.html for further details.
+ %%
+ %% {kernel, [{net_ticktime, 60}]},
+ %% ----------------------------------------------------------------------------
+ %% RabbitMQ Shovel Plugin
+ %%
+ %% See http://www.rabbitmq.com/shovel.html for details
+ %% ----------------------------------------------------------------------------
+
+ {rabbitmq_shovel,
+ [{shovels,
+ [%% A named shovel worker.
+ %% {my_first_shovel,
+ %% [
+
+ %% List the source broker(s) from which to consume.
+ %%
+ %% {sources,
+ %% [%% URI(s) and pre-declarations for all source broker(s).
+ %% {brokers, ["amqp://user:password@host.domain/my_vhost"]},
+ %% {declarations, []}
+ %% ]},
+
+ %% List the destination broker(s) to publish to.
+ %% {destinations,
+ %% [%% A singular version of the 'brokers' element.
+ %% {broker, "amqp://"},
+ %% {declarations, []}
+ %% ]},
+
+ %% Name of the queue to shovel messages from.
+ %%
+ %% {queue, <<"your-queue-name-goes-here">>},
+
+ %% Optional prefetch count.
+ %%
+ %% {prefetch_count, 10},
+
+ %% when to acknowledge messages:
+ %% - no_ack: never (auto)
+ %% - on_publish: after each message is republished
+ %% - on_confirm: when the destination broker confirms receipt
+ %%
+ %% {ack_mode, on_confirm},
+
+ %% Overwrite fields of the outbound basic.publish.
+ %%
+ %% {publish_fields, [{exchange, <<"my_exchange">>},
+ %% {routing_key, <<"from_shovel">>}]},
+
+ %% Static list of basic.properties to set on re-publication.
+ %%
+ %% {publish_properties, [{delivery_mode, 2}]},
+
+ %% The number of seconds to wait before attempting to
+ %% reconnect in the event of a connection failure.
+ %%
+ %% {reconnect_delay, 2.5}
+
+ %% ]} %% End of my_first_shovel
+ ]}
+ %% Rather than specifying some values per-shovel, you can specify
+ %% them for all shovels here.
+ %%
+ %% {defaults, [{prefetch_count, 0},
+ %% {ack_mode, on_confirm},
+ %% {publish_fields, []},
+ %% {publish_properties, [{delivery_mode, 2}]},
+ %% {reconnect_delay, 2.5}]}
+ ]},
+
+ {rabbitmq_auth_backend_ldap, [
+ %%
+ %% 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/docs/rabbitmq-server.service.example b/docs/rabbitmq-server.service.example
new file mode 100644
index 000000000000..5a8f1cd73e7c
--- /dev/null
+++ b/docs/rabbitmq-server.service.example
@@ -0,0 +1,17 @@
+# systemd unit example
+[Unit]
+Description=RabbitMQ broker
+After=syslog.target network.target
+
+[Service]
+Type=notify
+User=rabbitmq
+Group=rabbitmq
+NotifyAccess=all
+TimeoutStartSec=3600
+WorkingDirectory=/var/lib/rabbitmq
+ExecStart=/usr/lib/rabbitmq/bin/rabbitmq-server
+ExecStop=/usr/lib/rabbitmq/bin/rabbitmqctl stop
+
+[Install]
+WantedBy=multi-user.target
diff --git a/docs/rabbitmq.conf.example b/docs/rabbitmq.conf.example
new file mode 100644
index 000000000000..7e60c53da4f5
--- /dev/null
+++ b/docs/rabbitmq.conf.example
@@ -0,0 +1,736 @@
+# ======================================
+# RabbbitMQ broker section
+# ======================================
+
+## Network Connectivity
+## ====================
+##
+## By default, RabbitMQ will listen on all interfaces, using
+## the standard (reserved) AMQP port.
+##
+# listeners.tcp.default = 5672
+
+
+## To listen on a specific interface, provide an IP address with port.
+## For example, to listen only on localhost for both IPv4 and IPv6:
+##
+# IPv4
+# listeners.tcp.local = 127.0.0.1:5672
+# IPv6
+# listeners.tcp.local_v6 = ::1:5672
+
+## You can define multiple listeners using listener names
+# listeners.tcp.other_port = 5673
+# listeners.tcp.other_ip = 10.10.10.10:5672
+
+
+## SSL listeners are configured in the same fashion as TCP listeners,
+## including the option to control the choice of interface.
+##
+# listeners.ssl.default = 5671
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+# num_acceptors.tcp = 10
+# num_acceptors.ssl = 1
+
+
+## Maximum time for AMQP 0-8/0-9/0-9-1 handshake (after socket connection
+## and SSL handshake), in milliseconds.
+##
+# handshake_timeout = 10000
+
+## 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
+
+##
+## Security / AAA
+## ==============
+##
+
+## The default "guest" user is only permitted to access the server
+## via a loopback interface (e.g. localhost).
+## {loopback_users, [<<"guest">>]},
+##
+# loopback_users.guest = true
+
+## Uncomment the following line if you want to allow access to the
+## guest user from anywhere on the network.
+# loopback_users.guest = false
+
+## Configuring SSL.
+## See http://www.rabbitmq.com/ssl.html for full documentation.
+##
+# ssl_options.verify = verify_peer
+# ssl_options.fail_if_no_peer_cert = false
+# ssl_options.cacertfile = /path/to/cacert.pem
+# ssl_options.certfile = /path/to/cert.pem
+# ssl_options.keyfile = /path/to/key.pem
+
+## Select an authentication/authorisation backend to use.
+##
+## Alternative backends are provided by plugins, such as rabbitmq-auth-backend-ldap.
+##
+## NB: These settings require certain plugins to be enabled.
+## See http://www.rabbitmq.com/plugins.html and http://rabbitmq.com/access-control.html
+## for details.
+
+# auth_backends.1 = rabbit_auth_backend_internal
+
+## uses separate backends for authentication and authorisation,
+## see below.
+# auth_backends.1.authn = rabbit_auth_backend_ldap
+# auth_backends.1.authz = rabbit_auth_backend_internal
+
+## The rabbitmq_auth_backend_ldap plugin allows the broker to
+## perform authentication and authorisation by deferring to an
+## external LDAP server.
+##
+## For more information about configuring the LDAP backend, see
+## http://www.rabbitmq.com/ldap.html and http://rabbitmq.com/access-control.html.
+##
+## uses LDAP for both authentication and authorisation
+# auth_backends.1 = rabbit_auth_backend_ldap
+
+## uses HTTP service for both authentication and
+## authorisation
+# auth_backends.1 = rabbit_auth_backend_http
+
+## uses two backends in a chain: HTTP first, then internal
+# auth_backends.1 = rabbit_auth_backend_http
+# auth_backends.2 = rabbit_auth_backend_internal
+
+## Authentication
+## The built-in mechanisms are 'PLAIN',
+## 'AMQPLAIN', and 'EXTERNAL' Additional mechanisms can be added via
+## plugins.
+##
+## See http://www.rabbitmq.com/authentication.html for more details.
+##
+# auth_mechanisms.1 = PLAIN
+# auth_mechanisms.2 = AMQPLAIN
+
+## The rabbitmq-auth-mechanism-ssl plugin makes it possible to
+## authenticate a user based on the client's x509 (TLS) certificate.
+## See http://www.rabbitmq.com/authentication.html for more info.
+##
+## To use auth-mechanism-ssl, the EXTERNAL mechanism should
+## be enabled:
+##
+# auth_mechanisms.1 = PLAIN
+# auth_mechanisms.2 = AMQPLAIN
+# auth_mechanisms.3 = EXTERNAL
+
+## To force x509 certificate-based authentication on all clients,
+## exclude all other mechanisms (note: this will disable password-based
+## authentication even for the management UI!):
+##
+# auth_mechanisms.1 = EXTERNAL
+
+## 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
+
+## SSL handshake timeout, in milliseconds.
+##
+# ssl_handshake_timeout = 5000
+
+
+## Password hashing implementation. Will only affect newly
+## created users. To recalculate hash for an existing user
+## it's necessary to update her password.
+##
+## To use SHA-512, set to rabbit_password_hashing_sha512.
+##
+# password_hashing_module = rabbit_password_hashing_sha256
+
+## 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.
+##
+# password_hashing_module = rabbit_password_hashing_md5
+
+##
+## 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.configure = .*
+# default_permissions.read = .*
+# default_permissions.write = .*
+
+## 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 = true
+
+## Define other tags like this:
+# default_user_tags.management = true
+# default_user_tags.custom_tag = true
+
+##
+## Additional network and protocol related configuration
+## =====================================================
+##
+
+## Set the default AMQP 0-9-1 heartbeat interval (in seconds).
+## See http://rabbitmq.com/heartbeats.html for more details.
+##
+# heartbeat = 600
+
+## Set the max permissible size of an AMQP frame (in bytes).
+##
+# frame_max = 131072
+
+## Set the max frame size the server will accept before connection
+## tuning occurs
+##
+# initial_frame_max = 4096
+
+## Set the max permissible number of channels per connection.
+## 0 means "no limit".
+##
+# channel_max = 128
+
+## Customising Socket Options.
+##
+## See (http://www.erlang.org/doc/man/inet.html#setopts-2) for
+## further documentation.
+##
+
+# tcp_listen_options.backlog = 128
+# tcp_listen_options.nodelay = true
+# tcp_listen_options.exit_on_close = false
+
+##
+## Resource Limits & Flow Control
+## ==============================
+##
+## See http://www.rabbitmq.com/memory.html for full details.
+
+## Memory-based Flow Control threshold.
+##
+# vm_memory_high_watermark.relative = 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+).
+## Absolute watermark will be ignored if relative is defined!
+##
+# vm_memory_high_watermark.absolute = 2GB
+##
+## Supported units suffixes:
+##
+## kb, KB: kibibytes (2^10 bytes)
+## mb, MB: mebibytes (2^20)
+## gb, GB: gibibytes (2^30)
+
+
+
+## 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
+
+## Interval (in milliseconds) at which we perform the check of the memory
+## levels against the watermarks.
+##
+# memory_monitor_interval = 2500
+
+## 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.
+##
+## Absolute watermark will be ignored if relative is defined!
+# disk_free_limit.absolute = 50000
+
+## Or you can set it using memory units (same as in vm_memory_high_watermark)
+## with RabbitMQ 3.6.0+.
+# disk_free_limit.absolute = 500KB
+# disk_free_limit.absolute = 50mb
+# disk_free_limit.absolute = 5GB
+
+## 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.relative = 2.0
+
+##
+## Clustering
+## =====================
+##
+# cluster_partition_handling = ignore
+
+## pause_if_all_down strategy require additional configuration
+# cluster_partition_handling = pause_if_all_down
+
+## Recover strategy. Can be either 'autoheal' or 'ignore'
+# cluster_partition_handling.pause_if_all_down.recover = ignore
+
+## Node names to check
+# cluster_partition_handling.pause_if_all_down.nodes.1 = rabbit@localhost
+# cluster_partition_handling.pause_if_all_down.nodes.2 = hare@localhost
+
+## 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
+
+## 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.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
+
+## 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
+
+##
+## Statistics Collection
+## =====================
+##
+
+## Set (internal) statistics collection granularity.
+##
+## Can be none, coarse or fine
+# collect_statistics = none
+
+# collect_statistics = coarse
+
+## Statistics collection interval (in milliseconds). Increasing
+## this will reduce the load on management database.
+##
+# collect_statistics_interval = 5000
+
+##
+## Misc/Advanced Options
+## =====================
+##
+## NB: Change these only if you understand what you are doing!
+##
+
+## Explicitly enable/disable hipe compilation.
+##
+# hipe_compile = false
+
+## Timeout used when waiting for Mnesia tables in a cluster to
+## become available.
+##
+# mnesia_table_loading_timeout = 30000
+
+## 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
+
+## You can also set this size in memory units
+##
+# queue_index_embed_msgs_below = 4kb
+
+## ----------------------------------------------------------------------------
+## Advanced Erlang Networking/Clustering Options.
+##
+## See http://www.rabbitmq.com/clustering.html for details
+## ----------------------------------------------------------------------------
+
+# ======================================
+# Kernel section
+# ======================================
+
+# kernel.net_ticktime = 60
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Management Plugin
+##
+## See http://www.rabbitmq.com/management.html for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# Management section
+# =======================================
+
+## Pre-Load schema definitions from the following JSON file. See
+## http://www.rabbitmq.com/management.html#load-definitions
+##
+# management.load_definitions = /path/to/schema.json
+
+## Log all requests to the management HTTP API to a file.
+##
+# management.http_log_dir = /path/to/access.log
+
+## 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.
+##
+
+# QA: Maybe use IP type like in tcp_listener?
+# management.listener.port = 12345
+# management.listener.ip = 127.0.0.1
+# management.listener.ssl = true
+
+# management.listener.ssl_opts.cacertfile = /path/to/cacert.pem
+# management.listener.ssl_opts.certfile = /path/to/cert.pem
+# management.listener.ssl_opts.keyfile = /path/to/key.pem
+
+## One of 'basic', 'detailed' or 'none'. See
+## http://www.rabbitmq.com/management.html#fine-stats for more details.
+# management.rates_mode = basic
+
+## 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.
+## Your can use 'minute', 'hour' and '24hours' keys or integer key (in seconds)
+# management.sample_retention_policies.global.minute = 5
+# management.sample_retention_policies.global.hour = 60
+# management.sample_retention_policies.global.24hours = 1200
+
+# management.sample_retention_policies.basic.minute = 5
+# management.sample_retention_policies.basic.hour = 60
+
+# management.sample_retention_policies.detailed.10 = 5
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Shovel Plugin
+##
+## See http://www.rabbitmq.com/shovel.html for details
+## ----------------------------------------------------------------------------
+
+## Shovel plugin config example is defined in additional.config file
+
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Stomp Adapter
+##
+## See http://www.rabbitmq.com/stomp.html for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# STOMP section
+# =======================================
+
+## Network Configuration - the format is generally the same as for the broker
+##
+# stomp.listeners.tcp.default = 61613
+
+## Same for ssl listeners
+##
+# stomp.listeners.ssl.default = 61614
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+# stomp.num_acceptors.tcp = 10
+# stomp.num_acceptors.ssl = 1
+
+## Additional SSL options
+
+## Extract a name from the client's certificate when using SSL.
+##
+# stomp.ssl_cert_login = true
+
+## 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!
+##
+# stomp.default_user = guest
+# stomp.default_pass = guest
+
+## 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.
+##
+# stomp.implicit_connect = true
+
+## ----------------------------------------------------------------------------
+## RabbitMQ MQTT Adapter
+##
+## See https://github.com/rabbitmq/rabbitmq-mqtt/blob/stable/README.md
+## for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# MQTT section
+# =======================================
+
+## 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!
+##
+# mqtt.default_user = guest
+# mqtt.default_pass = guest
+
+## 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.
+##
+# mqtt.allow_anonymous = true
+
+## If you have multiple chosts, specify the one to which the
+## adapter connects.
+##
+# mqtt.vhost = /
+
+## Specify the exchange to which messages from MQTT clients are published.
+##
+# mqtt.exchange = amq.topic
+
+## Specify TTL (time to live) to control the lifetime of non-clean sessions.
+##
+# mqtt.subscription_ttl = 1800000
+
+## Set the prefetch count (governing the maximum number of unacknowledged
+## messages that will be delivered).
+##
+# mqtt.prefetch = 10
+
+## TCP/SSL Configuration (as per the broker configuration).
+##
+# mqtt.listeners.tcp.default = 1883
+
+## Same for ssl listener
+##
+# mqtt.listeners.ssl.default = 1884
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+# mqtt.num_acceptors.tcp = 10
+# mqtt.num_acceptors.ssl = 1
+
+## TCP/Socket options (as per the broker configuration).
+##
+# mqtt.tcp_listen_options.backlog = 128
+# mqtt.tcp_listen_options.nodelay = true
+
+## ----------------------------------------------------------------------------
+## RabbitMQ AMQP 1.0 Support
+##
+## See https://github.com/rabbitmq/rabbitmq-amqp1.0/blob/stable/README.md
+## for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# AMQP_1 section
+# =======================================
+
+
+## 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!
+##
+# amqp1_0.default_user = guest
+
+## Enable protocol strict mode. See the README for more information.
+##
+# amqp1_0.protocol_strict_mode = false
+
+## Lager controls logging.
+## See https://github.com/basho/lager for more documentation
+##
+## Log direcrory, taken from the RABBITMQ_LOG_BASE env variable by default.
+##
+# log.dir = /var/log/rabbitmq
+
+## Logging to console (can be true or false)
+##
+# log.console = false
+
+## Loglevel to log to console
+##
+# log.console.level = info
+
+## Logging to file. Can be false or filename.
+## Default:
+# log.file = rabbit.log
+
+## To turn off:
+# log.file = false
+
+## Loglevel to log to file
+##
+# log.file.level = info
+
+## File rotation config. No rotation by defualt.
+## DO NOT SET rotation date to ''. Leave unset if require "" value
+# log.file.rotation.date = $D0
+# log.file.rotation.size = 0
+
+
+## QA: Config for syslog logging
+# log.syslog = false
+# log.syslog.identity = rabbitmq
+# log.syslog.level = info
+# log.syslog.facility = daemon
+
+
+## ----------------------------------------------------------------------------
+## RabbitMQ LDAP Plugin
+##
+## See http://www.rabbitmq.com/ldap.html for details.
+##
+## ----------------------------------------------------------------------------
+
+# =======================================
+# LDAP section
+# =======================================
+
+##
+## Connecting to the LDAP server(s)
+## ================================
+##
+
+## Specify servers to bind to. You *must* set this in order for the plugin
+## to work properly.
+##
+# ldap.servers.1 = your-server-name-goes-here
+
+## You can define multiple servers
+# ldap.servers.2 = your-other-server
+
+## Connect to the LDAP server using SSL
+##
+# ldap.use_ssl = false
+
+## Specify the LDAP port to connect to
+##
+# ldap.port = 389
+
+## LDAP connection timeout, in milliseconds or 'infinity'
+##
+# ldap.timeout = infinity
+
+## Or number
+# ldap.timeout = 500
+
+## 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.
+##
+# ldap.log = false
+
+## Also can be true or network
+# ldap.log = true
+# ldap.log = network
+
+##
+## Authentication
+## ==============
+##
+
+## Pattern to convert the username given through AMQP to a DN before
+## binding
+##
+# ldap.user_dn_pattern = cn=${username},ou=People,dc=example,dc=com
+
+## 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.
+##
+# ldap.dn_lookup_attribute = userPrincipalName
+# ldap.dn_lookup_base = DC=gopivotal,DC=com
+
+## 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'.
+##
+# ldap.other_bind = as_user
+
+## Or can be more complex:
+# ldap.other_bind.user_dn = User
+# ldap.other_bind.password = Password
+
+## If user_dn and password defined - other options is ignored.
+
+# -----------------------------
+# Too complex section of LDAP
+# -----------------------------
+
+##
+## 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.
+
+## Following configuration should be defined in additional.config file
+## DO NOT UNCOMMENT THIS LINES!
+
+## 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/docs/rabbitmqctl.1.xml b/docs/rabbitmqctl.1.xml
index 885243c657cd..ddacc7e8c216 100644
--- a/docs/rabbitmqctl.1.xml
+++ b/docs/rabbitmqctl.1.xml
@@ -535,7 +535,7 @@
- sync_queue queue
+ sync_queue -p vhost queue
@@ -564,7 +564,7 @@
- cancel_sync_queue queue
+ cancel_sync_queue -p vhost queue
@@ -584,7 +584,7 @@
- purge_queue queue
+ purge_queue -p vhost queue
@@ -803,11 +803,11 @@
- add_vhost vhostpath
+ add_vhost vhost
- vhostpath
+ vhost
The name of the virtual host entry to create.
@@ -824,11 +824,11 @@
- delete_vhost vhostpath
+ delete_vhost vhost
- vhostpath
+ vhost
The name of the virtual host entry to delete.
@@ -885,11 +885,11 @@
- set_permissions -p vhostpath user conf write read
+ set_permissions -p vhost user conf write read
- vhostpath
+ vhost
The name of the virtual host to which to grant the user access, defaulting to /.
@@ -925,11 +925,11 @@
- clear_permissions -p vhostpath username
+ clear_permissions -p vhost username
- vhostpath
+ vhost
The name of the virtual host to which to deny the user access, defaulting to /.
@@ -951,11 +951,11 @@
- list_permissions -p vhostpath
+ list_permissions -p vhost
- vhostpath
+ vhost
The name of the virtual host for which to list the users that have been granted access to it, and their permissions. Defaults to /.
@@ -1015,7 +1015,7 @@
- set_parameter -p vhostpath component_name name value
+ set_parameter -p vhost component_name name value
Sets a parameter.
@@ -1051,7 +1051,7 @@
- clear_parameter -p vhostpath component_name key
+ clear_parameter -p vhost component_name key
Clears a parameter.
@@ -1079,7 +1079,7 @@
- list_parameters -p vhostpath
+ list_parameters -p vhost
Lists all parameters for a virtual host.
@@ -1104,7 +1104,7 @@
- set_policy -p vhostpath --priority priority --apply-to apply-to name pattern definition
+ set_policy -p vhost --priority priority --apply-to apply-to name pattern definition
Sets a policy.
@@ -1151,7 +1151,7 @@
- clear_policy -p vhostpath name
+ clear_policy -p vhost name
Clears a policy.
@@ -1172,7 +1172,7 @@
- list_policies -p vhostpath
+ list_policies -p vhost
Lists all policies for a virtual host.
@@ -1254,7 +1254,7 @@
- list_queues -p vhostpath queueinfoitem ...
+ list_queues -p vhost queueinfoitem ...
Returns queue details. Queue details of the / virtual host
@@ -1430,7 +1430,7 @@
- list_exchanges -p vhostpath exchangeinfoitem ...
+ list_exchanges -p vhost exchangeinfoitem ...
Returns exchange details. Exchange details of the / virtual host
@@ -1493,7 +1493,7 @@
- list_bindings -p vhostpath bindinginfoitem ...
+ list_bindings -p vhost bindinginfoitem ...
Returns binding details. By default the bindings for
@@ -1835,7 +1835,7 @@
- list_consumers -p vhostpath
+ list_consumers -p vhost
List consumers, i.e. subscriptions to a queue's message
@@ -1872,6 +1872,21 @@
+
+ node_health_check
+
+
+ Health check of the RabbitMQ node. Verifies the rabbit application is
+ running, list_queues and list_channels return, and alarms are not set.
+
+ For example:
+ rabbitmqctl node_health_check -n rabbit@stringer
+
+ This command performs a health check on the RabbitMQ node.
+
+
+
+
environment
diff --git a/scripts/set_rabbitmq_policy.sh b/docs/set_rabbitmq_policy.sh.example
similarity index 99%
rename from scripts/set_rabbitmq_policy.sh
rename to docs/set_rabbitmq_policy.sh.example
index a88b0c417a4d..f46e901ad56b 100644
--- a/scripts/set_rabbitmq_policy.sh
+++ b/docs/set_rabbitmq_policy.sh.example
@@ -2,4 +2,3 @@
# cluster start up. It is a convenient place to set your cluster
# policy here, for example:
# ${OCF_RESKEY_ctl} set_policy ha-all "." '{"ha-mode":"all", "ha-sync-mode":"automatic"}' --apply-to all --priority 0
-
diff --git a/include/rabbit_cli.hrl b/include/rabbit_cli.hrl
index a23ea3bbc67c..ad8ac37b323f 100644
--- a/include/rabbit_cli.hrl
+++ b/include/rabbit_cli.hrl
@@ -46,8 +46,6 @@
-define(OFFLINE_DEF, {?OFFLINE_OPT, flag}).
-define(ONLINE_DEF, {?ONLINE_OPT, flag}).
--define(RPC_TIMEOUT, infinity).
-
%% Subset of standartized exit codes from sysexits.h, see
%% https://github.com/rabbitmq/rabbitmq-server/issues/396 for discussion.
-define(EX_OK , 0).
diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec
index 7cf31774007f..b6715d430a6d 100644
--- a/packaging/RPMS/Fedora/rabbitmq-server.spec
+++ b/packaging/RPMS/Fedora/rabbitmq-server.spec
@@ -11,7 +11,7 @@ Source2: rabbitmq-server.logrotate
URL: http://www.rabbitmq.com/
BuildArch: noarch
BuildRequires: erlang >= R16B-03, python-simplejson, xmlto, libxslt, gzip, sed, zip, rsync
-Requires: erlang >= R16B-03, logrotate
+Requires: erlang >= R16B-03, logrotate, socat
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%{_arch}-root
Summary: The RabbitMQ server
Requires(post): %%REQUIRES%%
@@ -26,7 +26,6 @@ RabbitMQ is an open source multi-protocol messaging broker.
%define _rabbit_server_ocf scripts/rabbitmq-server.ocf
%define _plugins_state_dir %{_localstatedir}/lib/rabbitmq/plugins
%define _rabbit_server_ha_ocf scripts/rabbitmq-server-ha.ocf
-%define _set_rabbitmq_policy_sh scripts/set_rabbitmq_policy.sh
%define _maindir %{buildroot}%{_rabbit_erllibdir}
@@ -51,7 +50,6 @@ mkdir -p %{buildroot}%{_localstatedir}/log/rabbitmq
install -p -D -m 0755 %{S:1} %{buildroot}%{_initrddir}/rabbitmq-server
install -p -D -m 0755 %{_rabbit_server_ocf} %{buildroot}%{_exec_prefix}/lib/ocf/resource.d/rabbitmq/rabbitmq-server
install -p -D -m 0755 %{_rabbit_server_ha_ocf} %{buildroot}%{_exec_prefix}/lib/ocf/resource.d/rabbitmq/rabbitmq-server-ha
-install -p -D -m 0644 %{_set_rabbitmq_policy_sh} %{buildroot}%{_exec_prefix}/lib/ocf/resource.d/rabbitmq/set_rabbitmq_policy.sh.example
install -p -D -m 0644 %{S:2} %{buildroot}%{_sysconfdir}/logrotate.d/rabbitmq-server
mkdir -p %{buildroot}%{_sysconfdir}/rabbitmq
@@ -95,6 +93,8 @@ fi
/sbin/chkconfig --add %{name}
if [ -f %{_sysconfdir}/rabbitmq/rabbitmq.conf ] && [ ! -f %{_sysconfdir}/rabbitmq/rabbitmq-env.conf ]; then
mv %{_sysconfdir}/rabbitmq/rabbitmq.conf %{_sysconfdir}/rabbitmq/rabbitmq-env.conf
+else
+ touch %{_sysconfdir}/rabbitmq/rabbitmq-env.conf
fi
chmod -R o-rwx,g-w %{_localstatedir}/lib/rabbitmq/mnesia
@@ -125,11 +125,15 @@ done
%doc LICENSE*
%doc README
%doc docs/rabbitmq.config.example
+%doc docs/set_rabbitmq_policy.sh.example
%clean
rm -rf %{buildroot}
%changelog
+* Tue Mar 1 2016 michael@rabbitmq.com 3.6.1-1
+- New Upstream Release
+
* Tue Dec 22 2015 michael@rabbitmq.com 3.6.0-1
- New Upstream Release
diff --git a/packaging/debs/Debian/debian/changelog b/packaging/debs/Debian/debian/changelog
index 372afa8258d1..adf8ce5aa546 100644
--- a/packaging/debs/Debian/debian/changelog
+++ b/packaging/debs/Debian/debian/changelog
@@ -1,3 +1,9 @@
+rabbitmq-server (3.6.1-1) unstable; urgency=low
+
+ * New Upstream Release
+
+ -- Michael Klishin Tue, 01 Mar 2016 13:19:57 +0000
+
rabbitmq-server (3.6.0-1) unstable; urgency=low
* New Upstream Release
diff --git a/packaging/debs/Debian/debian/control b/packaging/debs/Debian/debian/control
index 56acaa948ec5..9cf494ab8774 100644
--- a/packaging/debs/Debian/debian/control
+++ b/packaging/debs/Debian/debian/control
@@ -18,7 +18,7 @@ Standards-Version: 3.9.4
Package: rabbitmq-server
Architecture: all
-Depends: erlang-nox (>= 1:16.b.3) | esl-erlang, adduser, logrotate, ${misc:Depends}
+Depends: erlang-nox (>= 1:16.b.3) | esl-erlang, adduser, logrotate, socat, ${misc:Depends}
Description: Multi-protocol messaging broker
RabbitMQ is an open source multi-protocol messaging broker.
Homepage: http://www.rabbitmq.com/
diff --git a/packaging/debs/Debian/debian/postinst b/packaging/debs/Debian/debian/postinst
index c83881e6bad4..2439612c428d 100644
--- a/packaging/debs/Debian/debian/postinst
+++ b/packaging/debs/Debian/debian/postinst
@@ -40,6 +40,8 @@ case "$1" in
if [ -f /etc/rabbitmq/rabbitmq.conf ] && \
[ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then
mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf
+ else
+ touch /etc/rabbitmq/rabbitmq-env.conf
fi
;;
diff --git a/packaging/debs/Debian/debian/rabbitmq-server.docs b/packaging/debs/Debian/debian/rabbitmq-server.docs
index 40d4f2dc8120..fbe9f95a054a 100644
--- a/packaging/debs/Debian/debian/rabbitmq-server.docs
+++ b/packaging/debs/Debian/debian/rabbitmq-server.docs
@@ -1 +1,2 @@
docs/rabbitmq.config.example
+docs/set_rabbitmq_policy.sh.example
diff --git a/packaging/debs/Debian/debian/rules b/packaging/debs/Debian/debian/rules
index 669e30c177ec..053df181150f 100755
--- a/packaging/debs/Debian/debian/rules
+++ b/packaging/debs/Debian/debian/rules
@@ -49,8 +49,6 @@ override_dh_auto_install:
$(DEB_DESTDIR)$(PREFIX)/lib/ocf/resource.d/rabbitmq/rabbitmq-server
install -p -D -m 0755 scripts/rabbitmq-server-ha.ocf \
$(DEB_DESTDIR)$(PREFIX)/lib/ocf/resource.d/rabbitmq/rabbitmq-server-ha
- install -p -D -m 0644 scripts/set_rabbitmq_policy.sh \
- $(DEB_DESTDIR)$(PREFIX)/lib/ocf/resource.d/rabbitmq/set_rabbitmq_policy.sh.example
rm $(DEB_DESTDIR)$(RMQ_ERLAPP_DIR)/LICENSE* \
$(DEB_DESTDIR)$(RMQ_ERLAPP_DIR)/INSTALL
diff --git a/packaging/windows-exe/rabbitmq_nsi.in b/packaging/windows-exe/rabbitmq_nsi.in
index 3c868b91e7e9..ae1585c37292 100644
--- a/packaging/windows-exe/rabbitmq_nsi.in
+++ b/packaging/windows-exe/rabbitmq_nsi.in
@@ -10,6 +10,8 @@
!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!define uninstall "Software\Microsoft\Windows\CurrentVersion\Uninstall\RabbitMQ"
+!define MUI_FINISHPAGE_NOAUTOCLOSE
+!define MUI_UNFINISHPAGE_NOAUTOCLOSE
;--------------------------------
; Third-party functions
@@ -135,6 +137,20 @@ Section "RabbitMQ Server (required)" Rabbit
; Set output path to the user's data directory
SetOutPath $APPDATA\RabbitMQ
+ IfFileExists advanced.config 0 +2
+ Goto config_written
+ IfFileExists rabbitmq.config 0 +3
+ Rename rabbitmq.config advanced.config
+ Goto config_written
+ ClearErrors
+ FileOpen $0 advanced.config w
+ IfErrors config_written
+ FileWrite $0 "[]."
+ FileClose $0
+ config_written:
+
+
+
; ...And put the example config file there
File "rabbitmq_server-%%VERSION%%\etc\rabbitmq.config.example"
diff --git a/priv/schema/.gitignore b/priv/schema/.gitignore
new file mode 100644
index 000000000000..68e5b59a44b2
--- /dev/null
+++ b/priv/schema/.gitignore
@@ -0,0 +1,4 @@
+# plugin schemas are extracted
+# into this directory: this is a Cuttlefish
+# requirement. So we ignore them.
+rabbitmq_*.schema
diff --git a/priv/schema/rabbitmq.schema b/priv/schema/rabbitmq.schema
new file mode 100644
index 000000000000..19040da409d3
--- /dev/null
+++ b/priv/schema/rabbitmq.schema
@@ -0,0 +1,961 @@
+% ==============================
+% 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", 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}]}.
+
+%% ==========================================================================
+
+%%
+%% 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
+ 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}.
diff --git a/rabbitmq-components.mk b/rabbitmq-components.mk
index eed26fdac880..b200585b30f4 100644
--- a/rabbitmq-components.mk
+++ b/rabbitmq-components.mk
@@ -66,6 +66,8 @@ dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref)
dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master
+dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master
+dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master
dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master
dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master
dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master
@@ -117,6 +119,8 @@ RABBITMQ_COMPONENTS = amqp_client \
rabbitmq_top \
rabbitmq_tracing \
rabbitmq_web_dispatch \
+ rabbitmq_web_mqtt \
+ rabbitmq_web_mqtt_examples \
rabbitmq_web_stomp \
rabbitmq_web_stomp_examples \
rabbitmq_website
diff --git a/rabbitmq.conf.d/ldap.conf b/rabbitmq.conf.d/ldap.conf
new file mode 100644
index 000000000000..2f51cbb409a7
--- /dev/null
+++ b/rabbitmq.conf.d/ldap.conf
@@ -0,0 +1,138 @@
+# ## ----------------------------------------------------------------------------
+# ## RabbitMQ LDAP Plugin
+# ##
+# ## See http://www.rabbitmq.com/ldap.html for details.
+# ##
+# ## ----------------------------------------------------------------------------
+
+
+# =======================================
+# LDAP section
+# =======================================
+
+# Should be defined in additional.conf maybe?
+
+# {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"]},
+
+ldap.servers.myserver = your-server-name-goes-here
+
+# ## Connect to the LDAP server using SSL
+# ##
+# ## {use_ssl, false},
+
+ldap.use_ssl = false
+
+# ## Specify the LDAP port to connect to
+# ##
+# ## {port, 389},
+
+ldap.port = 389
+
+# ## LDAP connection timeout, in milliseconds or 'infinity'
+# ##
+# ## {timeout, infinity},
+
+ldap.timeout = infinity
+
+# Or number
+# ldap.timeout = 500
+
+# ## 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},
+
+ldap.log = false
+
+# Also can be true or network
+# ldap.log = true
+# ldap.log = 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"},
+
+ldap.user_dn_pattern = cn=${username},ou=People,dc=example,dc=com
+
+# ## 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"},
+
+ldap.dn_lookup_attribute = userPrincipalName
+ldap.dn_lookup_base = DC=gopivotal,DC=com
+
+# ## 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},
+
+ldap.other_bind = as_user
+
+# Or can be more complex:
+# ldap.other_bind.user_dn = User
+# ldap.other_bind.password = Password
+# If user_dn and password defined - other options is ignored.
+
+# -----------------------------
+# Too complex section of LDAP
+# -----------------------------
+
+# ##
+# ## 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/rabbitmq.conf.d/rabbitmq.conf b/rabbitmq.conf.d/rabbitmq.conf
new file mode 100644
index 000000000000..e702ec08b424
--- /dev/null
+++ b/rabbitmq.conf.d/rabbitmq.conf
@@ -0,0 +1,726 @@
+# ======================================
+# RabbbitMQ broker section
+# ======================================
+
+## Network Connectivity
+## ====================
+##
+## By default, RabbitMQ will listen on all interfaces, using
+## the standard (reserved) AMQP port.
+##
+listener.tcp.default = 5672
+
+
+## To listen on a specific interface, provide an IP address with port.
+## For example, to listen only on localhost for both IPv4 and IPv6:
+##
+# IPv4
+# listener.tcp.local = 127.0.0.1:5672
+# IPv6
+# listener.tcp.local_v6 = ::1:5672
+
+## You can define multiple listeners using listener names
+# listener.tcp.other_port = 5673
+# listener.tcp.other_ip = 10.10.10.10:5672
+
+
+## SSL listeners are configured in the same fashion as TCP listeners,
+## including the option to control the choice of interface.
+##
+# listener.ssl.default = 5671
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+num_acceptors.tcp = 10
+num_acceptors.ssl = 1
+
+
+## Maximum time for AMQP 0-8/0-9/0-9-1 handshake (after socket connection
+## and SSL handshake), in milliseconds.
+##
+handshake_timeout = 10000
+
+## 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
+
+##
+## Security / AAA
+## ==============
+##
+
+## The default "guest" user is only permitted to access the server
+## via a loopback interface (e.g. localhost).
+## {loopback_users, [<<"guest">>]},
+##
+loopback_user.guest = true
+
+## Uncomment the following line if you want to allow access to the
+## guest user from anywhere on the network.
+# loopback_user.guest = false
+
+## Configuring SSL.
+## See http://www.rabbitmq.com/ssl.html for full documentation.
+##
+ssl_option.verify = verify_peer
+ssl_option.fail_if_no_peer_cert = false
+# ssl_option.cacertfile = /path/to/rabbitmq.crt
+# ssl_option.certfile = /path/to/rabbitmq.crt
+# ssl_option.keyfile = /path/to/rabbitmq.key
+
+## 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_mechanism.plain = PLAIN
+auth_mechanism.amqplain = AMQPLAIN
+
+## Select an authentication database to use. RabbitMQ comes bundled
+## with a built-in auth-database, based on mnesia.
+##
+auth_backends.1 = internal
+
+auth_backends.2.authn = ldap
+auth_backends.2.authz = internal
+
+auth_backends.3.authz = rabbit_auth_backend_uaa
+
+## Configurations supporting the rabbitmq_auth_mechanism_ssl and
+## rabbitmq_auth_backend_ldap plugins.
+##
+## NB: These options require that the relevant plugin is enabled.
+## See http://www.rabbitmq.com/plugins.html for further details.
+
+
+## The RabbitMQ-auth-mechanism-ssl plugin makes it possible to
+## authenticate a user based on the client's SSL certificate.
+##
+## To use auth-mechanism-ssl, add to or replace the auth_mechanisms
+## with EXTERNAL value.
+##
+#auth_mechanism.external = EXTERNAL
+
+## The rabbitmq_auth_backend_ldap plugin allows the broker to
+## perform authentication and authorisation by deferring to an
+## external LDAP server.
+##
+## For more information about configuring the LDAP backend, see
+## http://www.rabbitmq.com/ldap.html.
+##
+## Enable the LDAP auth backend by adding to or replacing the
+## auth_backends entry:
+##
+# auth_backends.2 = rabbit_auth_backend_ldap
+
+## Add another backend
+# auth_backend.3 = rabbit_auth_backend_http
+
+
+## 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
+
+## SSL handshake timeout, in milliseconds.
+##
+# ssl_handshake_timeout = 5000
+
+
+## Password hashing implementation. Will only affect newly
+## created users. To recalculate hash for an existing user
+## it's necessary to update her password.
+##
+## To use SHA-512, set to rabbit_password_hashing_sha512.
+##
+password_hashing_module = rabbit_password_hashing_sha256
+
+## 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.
+##
+# password_hashing_module = rabbit_password_hashing_md5
+
+##
+## 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.configure = .*
+default_permissions.read = .*
+default_permissions.write = .*
+
+## 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 = true
+
+## Define other tags like this:
+# default_user_tags.management = true
+# default_user_tags.custom_tag = true
+
+##
+## Additional network and protocol related configuration
+## =====================================================
+##
+
+## Set the default AMQP heartbeat delay (in seconds).
+##
+heartbeat = 600
+
+## Set the max permissible size of an AMQP frame (in bytes).
+##
+frame_max = 131072
+
+## Set the max frame size the server will accept before connection
+## tuning occurs
+##
+initial_frame_max = 4096
+
+## Set the max permissible number of channels per connection.
+## 0 means "no limit".
+##
+channel_max = 128
+
+## Customising Socket Options.
+##
+## See (http://www.erlang.org/doc/man/inet.html#setopts-2) for
+## further documentation.
+##
+
+tcp_listen_option.backlog = 128
+tcp_listen_option.nodelay = true
+tcp_listen_option.exit_on_close = false
+
+##
+## Resource Limits & Flow Control
+## ==============================
+##
+## See http://www.rabbitmq.com/memory.html for full details.
+
+## Memory-based Flow Control threshold.
+##
+vm_memory_high_watermark.relative = 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+).
+## Absolute watermark will be ignored if relative is defined!
+##
+# vm_memory_high_watermark.absolute = 2GB
+##
+## Supported units suffixes:
+##
+## kb, KB: kibibytes (2^10 bytes)
+## mb, MB: mebibytes (2^20)
+## gb, GB: gibibytes (2^30)
+
+
+
+## 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
+
+## Interval (in milliseconds) at which we perform the check of the memory
+## levels against the watermarks.
+##
+memory_monitor_interval = 2500
+
+## 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.
+##
+## Absolute watermark will be ignored if relative is defined!
+disk_free_limit.absolute = 50000
+
+## Or you can set it using memory units (same as in vm_memory_high_watermark)
+## with RabbitMQ 3.6.0+.
+# disk_free_limit.absolute = 500KB
+# disk_free_limit.absolute = 50mb
+# disk_free_limit.absolute = 5GB
+
+## 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.relative = 2.0
+
+##
+## Clustering
+## =====================
+##
+cluster_partition_handling = ignore
+
+## pause_if_all_down strategy require additional configuration
+# cluster_partition_handling = pause_if_all_down
+
+## Recover strategy. Can be either 'autoheal' or 'ignore'
+# cluster_partition_handling.pause_if_all_down.recover = ignore
+
+## Node names to check
+# cluster_partition_handling.pause_if_all_down.node.rabbit = rabbit@localhost
+# cluster_partition_handling.pause_if_all_down.node.hare = hare@localhost
+
+## 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
+
+## 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.disc.1 = rabbit@my.host.com
+
+## You can define multiple nodes
+# cluster_nodes.disc.2 = hare@my.host.com
+
+## There can be also ram nodes.
+## Ram nodes should not be defined together with disk nodes
+# cluster_nodes.ram.1 = rabbit@my.host.com
+
+## 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
+
+##
+## Statistics Collection
+## =====================
+##
+
+## Set (internal) statistics collection granularity.
+##
+## Can be none, coarse or fine
+collect_statistics = none
+
+# collect_statistics = coarse
+
+## Statistics collection interval (in milliseconds). Increasing
+## this will reduce the load on management database.
+##
+collect_statistics_interval = 5000
+
+##
+## Misc/Advanced Options
+## =====================
+##
+## NB: Change these only if you understand what you are doing!
+##
+
+## Explicitly enable/disable hipe compilation.
+##
+hipe_compile = false
+
+## Timeout used when waiting for Mnesia tables in a cluster to
+## become available.
+##
+mnesia_table_loading_timeout = 30000
+
+## 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
+
+## You can also set this size in memory units
+##
+queue_index_embed_msgs_below = 4kb
+
+## ----------------------------------------------------------------------------
+## Advanced Erlang Networking/Clustering Options.
+##
+## See http://www.rabbitmq.com/clustering.html for details
+## ----------------------------------------------------------------------------
+
+# ======================================
+# Kernel section
+# ======================================
+
+# kernel.net_ticktime = 60
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Management Plugin
+##
+## See http://www.rabbitmq.com/management.html for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# Management section
+# =======================================
+
+## Pre-Load schema definitions from the following JSON file. See
+## http://www.rabbitmq.com/management.html#load-definitions
+##
+# management.load_definitions = /path/to/schema.json
+
+## Log all requests to the management HTTP API to a file.
+##
+# management.http_log_dir = /path/to/access.log
+
+## 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.
+##
+
+# QA: Maybe use IP type like in tcp_listener?
+management.listener.port = 12345
+management.listener.ip = 127.0.0.1
+# management.listener.ssl = true
+
+# management.listener.ssl_opts.cacertfile = /path/to/cacert.pem
+# management.listener.ssl_opts.certfile = /path/to/cert.pem
+# management.listener.ssl_opts.keyfile = /path/to/key.pem
+
+## One of 'basic', 'detailed' or 'none'. See
+## http://www.rabbitmq.com/management.html#fine-stats for more details.
+management.rates_mode = basic
+
+## 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.
+## Your can use 'minute', 'hour' and '24hours' keys or integer key (in seconds)
+management.sample_retention_policies.global.minute = 5
+management.sample_retention_policies.global.hour = 60
+management.sample_retention_policies.global.day = 1200
+
+management.sample_retention_policies.basic.minute = 5
+management.sample_retention_policies.basic.hour = 60
+
+management.sample_retention_policies.detailed.10 = 5
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Shovel Plugin
+##
+## See http://www.rabbitmq.com/shovel.html for details
+## ----------------------------------------------------------------------------
+
+## Shovel plugin config example is defined in additional.config file
+
+
+## ----------------------------------------------------------------------------
+## RabbitMQ Stomp Adapter
+##
+## See http://www.rabbitmq.com/stomp.html for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# STOMP section
+# =======================================
+
+## Network Configuration - the format is generally the same as for the broker
+##
+stomp.listener.tcp.default = 61613
+
+## Same for ssl listeners
+##
+# stomp.listener.ssl.default = 61614
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+stomp.num_acceptors.tcp = 10
+stomp.num_acceptors.ssl = 1
+
+## Additional SSL options
+
+## Extract a name from the client's certificate when using SSL.
+##
+stomp.ssl_cert_login = true
+
+## 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!
+##
+# stomp.default_user = guest
+# stomp.default_pass = guest
+
+## 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.
+##
+# stomp.implicit_connect = true
+
+## ----------------------------------------------------------------------------
+## RabbitMQ MQTT Adapter
+##
+## See https://github.com/rabbitmq/rabbitmq-mqtt/blob/stable/README.md
+## for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# MQTT section
+# =======================================
+
+## 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!
+##
+# mqtt.default_user = guest
+# mqtt.default_pass = guest
+
+## 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.
+##
+# mqtt.allow_anonymous = true
+
+## If you have multiple chosts, specify the one to which the
+## adapter connects.
+##
+mqtt.vhost = /
+
+## Specify the exchange to which messages from MQTT clients are published.
+##
+mqtt.exchange = amq.topic
+
+## Specify TTL (time to live) to control the lifetime of non-clean sessions.
+##
+# mqtt.subscription_ttl = 1800000
+
+## Set the prefetch count (governing the maximum number of unacknowledged
+## messages that will be delivered).
+##
+mqtt.prefetch = 10
+
+## TCP/SSL Configuration (as per the broker configuration).
+##
+mqtt.listener.tcp.default = 1883
+
+## Same for ssl listener
+##
+# mqtt.listener.ssl.default = 1884
+
+## Number of Erlang processes that will accept connections for the TCP
+## and SSL listeners.
+##
+mqtt.num_acceptors.tcp = 10
+mqtt.num_acceptors.ssl = 1
+
+## TCP/Socket options (as per the broker configuration).
+##
+# mqtt.tcp_listen_option.backlog = 128
+# mqtt.tcp_listen_option.nodelay = true
+
+## ----------------------------------------------------------------------------
+## RabbitMQ AMQP 1.0 Support
+##
+## See https://github.com/rabbitmq/rabbitmq-amqp1.0/blob/stable/README.md
+## for details
+## ----------------------------------------------------------------------------
+
+# =======================================
+# AMQP_1 section
+# =======================================
+
+
+## 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!
+##
+amqp1_0.default_user = guest
+
+## Enable protocol strict mode. See the README for more information.
+##
+amqp1_0.protocol_strict_mode = false
+
+## Lager controls logging.
+## See https://github.com/basho/lager for more documentation
+##
+## Log direcrory, taken from the RABBITMQ_LOG_BASE env variable by default.
+##
+# log.dir = /var/log/rabbitmq
+
+## Logging to console (can be true or false)
+##
+# log.console = false
+
+## Loglevel to log to console
+##
+# log.console.level = info
+
+## Logging to file. Can be false or filename.
+## Default:
+# log.file = rabbit.log
+
+## To turn off:
+# log.file = false
+
+## Loglevel to log to file
+##
+# log.file.level = info
+
+## File rotation config. No rotation by defualt.
+## DO NOT SET rotation date to ''. Leave unset if require "" value
+# log.file.rotation.date = $D0
+# log.file.rotation.size = 0
+
+
+## QA: Config for syslog logging
+# log.syslog = false
+# log.syslog.identity = rabbitmq
+# log.syslog.level = info
+# log.syslog.facility = daemon
+
+
+## ----------------------------------------------------------------------------
+## RabbitMQ LDAP Plugin
+##
+## See http://www.rabbitmq.com/ldap.html for details.
+##
+## ----------------------------------------------------------------------------
+
+# =======================================
+# LDAP section
+# =======================================
+
+##
+## Connecting to the LDAP server(s)
+## ================================
+##
+
+## Specify servers to bind to. You *must* set this in order for the plugin
+## to work properly.
+##
+# ldap.servers.1 = your-server-name-goes-here
+
+## You can define multiple servers
+# ldap.servers.2 = your-other-server
+
+## Connect to the LDAP server using SSL
+##
+# ldap.use_ssl = false
+
+## Specify the LDAP port to connect to
+##
+# ldap.port = 389
+
+## LDAP connection timeout, in milliseconds or 'infinity'
+##
+# ldap.timeout = infinity
+
+## Or number
+# ldap.timeout = 500
+
+## 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.
+##
+# ldap.log = false
+
+## Also can be true or network
+# ldap.log = true
+# ldap.log = network
+
+##
+## Authentication
+## ==============
+##
+
+## Pattern to convert the username given through AMQP to a DN before
+## binding
+##
+# ldap.user_dn_pattern = cn=${username},ou=People,dc=example,dc=com
+
+## 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.
+##
+# ldap.dn_lookup_attribute = userPrincipalName
+# ldap.dn_lookup_base = DC=gopivotal,DC=com
+
+## 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'.
+##
+# ldap.other_bind = as_user
+
+## Or can be more complex:
+# ldap.other_bind.user_dn = User
+# ldap.other_bind.password = Password
+
+## If user_dn and password defined - other options is ignored.
+
+# -----------------------------
+# Too complex section of LDAP
+# -----------------------------
+
+##
+## 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.
+
+## Following configuration should be defined in additional.config file
+## DO NOT UNCOMMENT THIS LINES!
+
+## 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/scripts/cuttlefish b/scripts/cuttlefish
new file mode 100755
index 000000000000..6c1e4bbb8993
Binary files /dev/null and b/scripts/cuttlefish differ
diff --git a/scripts/rabbitmq-defaults b/scripts/rabbitmq-defaults
index c5d87822a24c..bccd0d7435b4 100644
--- a/scripts/rabbitmq-defaults
+++ b/scripts/rabbitmq-defaults
@@ -38,6 +38,9 @@ CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq
LOG_BASE=${SYS_PREFIX}/var/log/rabbitmq
MNESIA_BASE=${SYS_PREFIX}/var/lib/rabbitmq/mnesia
ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins
+GENERATED_CONFIG_DIR=${SYS_PREFIX}/var/lib/rabbitmq/config
+ADVANCED_CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/advanced
+SCHEMA_DIR=${RABBITMQ_HOME}/priv/schema
PLUGINS_DIR="${RABBITMQ_HOME}/plugins"
IO_THREAD_POOL_SIZE=64
diff --git a/scripts/rabbitmq-defaults.bat b/scripts/rabbitmq-defaults.bat
index 27edd0d11eab..5612af967ad2 100644
--- a/scripts/rabbitmq-defaults.bat
+++ b/scripts/rabbitmq-defaults.bat
@@ -41,6 +41,9 @@ set CONFIG_FILE=!RABBITMQ_BASE!\rabbitmq
set LOG_BASE=!RABBITMQ_BASE!\log
set MNESIA_BASE=!RABBITMQ_BASE!\db
set ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
+set GENERATED_CONFIG_DIR=!RABBITMQ_BASE!\config
+set ADVANCED_CONFIG_FILE=!RABBITMQ_BASE!\advanced
+set SCHEMA_DIR=!RABBITMQ_HOME!\priv\schema
REM PLUGINS_DIR="${RABBITMQ_HOME}/plugins"
for /f "delims=" %%F in ("!TDP0!..\plugins") do set PLUGINS_DIR=%%~dpsF%%~nF%%~xF
diff --git a/scripts/rabbitmq-env b/scripts/rabbitmq-env
index 872e5492dec7..8ceb8c94f29a 100644
--- a/scripts/rabbitmq-env
+++ b/scripts/rabbitmq-env
@@ -103,15 +103,11 @@ fi
##--- Set environment vars RABBITMQ_ to defaults if not set
-SED_OPT="-E"
-if [ $(uname -s) = "Linux" ]; then
- SED_OPT="-r"
-fi
-
rmq_normalize_path() {
local path=$1
- echo "$path" | sed $SED_OPT -e 's,//+,/,g' -e 's,(.)/$,\1,'
+ # Remove redundant slashes and strip a trailing slash
+ echo "$path" | sed -e 's#/\{2,\}#/#g' -e 's#/$##'
}
rmq_normalize_path_var() {
@@ -188,6 +184,9 @@ DEFAULT_NODE_PORT=5672
[ "x" = "x$RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS" ] && RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=${SERVER_ADDITIONAL_ERL_ARGS}
[ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${MNESIA_DIR}
[ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}
+[ "x" = "x$RABBITMQ_GENERATED_CONFIG_DIR" ] && RABBITMQ_GENERATED_CONFIG_DIR=${GENERATED_CONFIG_DIR}
+[ "x" = "x$RABBITMQ_ADVANCED_CONFIG_FILE" ] && RABBITMQ_ADVANCED_CONFIG_FILE=${ADVANCED_CONFIG_FILE}
+[ "x" = "x$RABBITMQ_SCHEMA_DIR" ] && RABBITMQ_SCHEMA_DIR=${SCHEMA_DIR}
rmq_normalize_path_var \
RABBITMQ_CONFIG_FILE \
@@ -262,7 +261,8 @@ if [ "${RABBITMQ_DEV_ENV}" ]; then
RABBITMQ_ENABLED_PLUGINS_FILE="${enabled_plugins_file}"
fi
fi
-
+
+
if [ -d "${RABBITMQ_PLUGINS_DIR}" ]; then
# RabbitMQ was started with "make run-broker" from its own
# source tree. Take rabbit_common from the plugins directory.
diff --git a/scripts/rabbitmq-env.bat b/scripts/rabbitmq-env.bat
index 981a2feddc86..430395accf1c 100644
--- a/scripts/rabbitmq-env.bat
+++ b/scripts/rabbitmq-env.bat
@@ -77,6 +77,8 @@ if "!RABBITMQ_NODENAME!"=="" (
if "!NODENAME!"=="" (
REM We use Erlang to query the local hostname because
REM !COMPUTERNAME! and Erlang may return different results.
+ REM Start erl with -sname to make sure epmd is started.
+ call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -sname rabbit-prelaunch-epmd -eval "init:stop()." >nul 2>&1
for /f "delims=" %%F in ('call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -eval "net_kernel:start([list_to_atom(""rabbit-gethostname-"" ++ os:getpid()), %NAMETYPE%]), [_, H] = string:tokens(atom_to_list(node()), ""@""), io:format(""~s~n"", [H]), init:stop()."') do @set HOSTNAME=%%F
set RABBITMQ_NODENAME=rabbit@!HOSTNAME!
set HOSTNAME=
@@ -156,6 +158,31 @@ if "!RABBITMQ_CONFIG_FILE!"=="" (
)
)
+if "!RABBITMQ_GENERATED_CONFIG_DIR!"=="" (
+ if "!GENERATED_CONFIG_DIR!"=="" (
+ set RABBITMQ_GENERATED_CONFIG_DIR=!RABBITMQ_BASE!\config
+ ) else (
+ set RABBITMQ_GENERATED_CONFIG_DIR=!GENERATED_CONFIG_DIR!
+ )
+)
+
+if "!RABBITMQ_ADVANCED_CONFIG_FILE!"=="" (
+ if "!ADVANCED_CONFIG_FILE!"=="" (
+ set RABBITMQ_ADVANCED_CONFIG_FILE=!RABBITMQ_BASE!\advanced
+ ) else (
+ set RABBITMQ_ADVANCED_CONFIG_FILE=!GENERATED_CONFIG_DIR!
+ )
+)
+
+if "!RABBITMQ_SCHEMA_DIR!" == "" (
+ if "!SCHEMA_DIR!"=="" (
+ set RABBITMQ_SCHEMA_DIR=!RABBITMQ_HOME!\priv\schema
+ ) else (
+ set RABBITMQ_SCHEMA_DIR=!SCHEMA_DIR!
+ )
+)
+
+
REM [ "x" = "x$RABBITMQ_LOG_BASE" ] && RABBITMQ_LOG_BASE=${LOG_BASE}
if "!RABBITMQ_LOG_BASE!"=="" (
if "!LOG_BASE!"=="" (
diff --git a/scripts/rabbitmq-script-wrapper b/scripts/rabbitmq-script-wrapper
index ed4c276e53cf..9623f0170930 100644
--- a/scripts/rabbitmq-script-wrapper
+++ b/scripts/rabbitmq-script-wrapper
@@ -15,14 +15,9 @@
## Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved.
##
-SED_OPT="-E"
-if [ $(uname -s) = "Linux" ]; then
- SED_OPT="-r"
-fi
-
for arg in "$@" ; do
# Wrap each arg in single quotes and wrap single quotes in double quotes, so that they're passed through cleanly.
- arg=`printf %s "$arg" | sed $SED_OPT -e "s/'/'\"'\"'/g"`
+ arg=`printf %s "$arg" | sed -e "s#'#'\"'\"'#g"`
CMDLINE="${CMDLINE} '${arg}'"
done
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server
index 6397d1cdbd42..0e3f06baf981 100755
--- a/scripts/rabbitmq-server
+++ b/scripts/rabbitmq-server
@@ -47,7 +47,7 @@ case "$(uname -s)" in
exit $EX_CANTCREAT
fi
if ! echo $$ > ${RABBITMQ_PID_FILE}; then
- # Bettern diagnostics - otherwise the only report in logs is about failed 'echo'
+ # Better diagnostics - otherwise the only report in logs is about failed 'echo'
# command, but without any other details: neither what script has failed nor what
# file output was redirected to.
echo "Failed to write pid file: ${RABBITMQ_PID_FILE}"
@@ -58,8 +58,13 @@ esac
RABBITMQ_EBIN_ROOT="${RABBITMQ_HOME}/ebin"
+[ "$NOTIFY_SOCKET" ] && RUNNING_UNDER_SYSTEMD=true
+
set +e
+# NOTIFY_SOCKET is needed here to prevent epmd from impersonating the
+# success of our startup sequence to systemd.
+NOTIFY_SOCKET= \
RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \
RABBITMQ_DIST_PORT=$RABBITMQ_DIST_PORT \
${ERL_DIR}erl -pa "$RABBITMQ_EBIN_ROOT" \
@@ -68,8 +73,11 @@ RABBITMQ_DIST_PORT=$RABBITMQ_DIST_PORT \
-hidden \
-s rabbit_prelaunch \
${RABBITMQ_NAME_TYPE} rabbitmqprelaunch$$ \
+ -conf_advanced "${RABBITMQ_ADVANCED_CONFIG_FILE}" \
+ -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \
+ -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \
-extra "${RABBITMQ_NODENAME}"
-
+
PRELAUNCH_RESULT=$?
if [ ${PRELAUNCH_RESULT} = 2 ] ; then
# dist port is mentioned in config, so do not set it
@@ -81,10 +89,25 @@ else
exit ${PRELAUNCH_RESULT}
fi
+if [ ! -f "${RABBITMQ_SCHEMA_DIR}/rabbitmq.schema" ]; then
+ cp "${RABBITMQ_HOME}/priv/schema/rabbitmq.schema" "${RABBITMQ_SCHEMA_DIR}"
+fi
+
set -e
-RABBITMQ_CONFIG_ARG=
-[ -f "${RABBITMQ_CONFIG_FILE}.config" ] && RABBITMQ_CONFIG_ARG="-config ${RABBITMQ_CONFIG_FILE}"
+if [ -f "${RABBITMQ_CONFIG_FILE}.config" ]; then
+ RABBITMQ_CONFIG_ARG="-config ${RABBITMQ_CONFIG_FILE}"
+elif [ -f "${RABBITMQ_CONFIG_FILE}.conf" ]; then
+ RABBITMQ_CONFIG_ARG="-conf ${RABBITMQ_CONFIG_FILE} \
+ -conf_dir ${RABBITMQ_GENERATED_CONFIG_DIR} \
+ -conf_script_dir `dirname $0` \
+ -conf_schema_dir ${RABBITMQ_SCHEMA_DIR}"
+ if [ -f "${RABBITMQ_ADVANCED_CONFIG_FILE}.config" ]; then
+ RABBITMQ_CONFIG_ARG="${RABBITMQ_CONFIG_ARG} \
+ -conf_advanced ${RABBITMQ_ADVANCED_CONFIG_FILE} \
+ -config ${RABBITMQ_ADVANCED_CONFIG_FILE}"
+ fi
+fi
RABBITMQ_LISTEN_ARG=
[ "x" != "x$RABBITMQ_NODE_PORT" ] && [ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_LISTEN_ARG="-rabbit tcp_listeners [{\""${RABBITMQ_NODE_IP_ADDRESS}"\","${RABBITMQ_NODE_PORT}"}]"
@@ -106,6 +129,7 @@ fi
set -f
start_rabbitmq_server() {
+ check_start_params &&
RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \
exec ${ERL_DIR}erl \
-pa ${RABBITMQ_EBIN_ROOT} \
@@ -144,7 +168,39 @@ stop_rabbitmq_server() {
fi
}
-if [ 'x' = "x$RABBITMQ_ALLOW_INPUT" -a -z "$detached" ]; then
+check_start_params() {
+ check_not_empty RABBITMQ_BOOT_MODULE
+ check_not_empty RABBITMQ_NAME_TYPE
+ check_not_empty RABBITMQ_NODENAME
+ check_not_empty SASL_BOOT_FILE
+ check_not_empty RABBITMQ_IO_THREAD_POOL_SIZE
+}
+
+check_not_empty() {
+ local name="${1:?}"
+ local value
+ eval value=\$$name
+ if [ -z "$value" ]; then
+ echo "Error: ENV variable should be defined: $1.
+ Please check rabbitmq-env, rabbitmq-defaults, and $CONF_ENV_FILE script files"
+ exit 78
+ fi
+}
+
+if [ "$RABBITMQ_ALLOW_INPUT" -o "$RUNNING_UNDER_SYSTEMD" -o "$detached" ]; then
+ # Run erlang VM directly, completely replacing current shell
+ # process - so the pid file written in the code above will be
+ # valid (unless detached, which is also handled in the code
+ # above).
+ #
+ # And also this is the correct mode to run the broker under
+ # systemd - there is no need in a proxy process that converts
+ # signals to graceful shutdown command, the unit file should already
+ # contain instructions for graceful shutdown. Also by removing
+ # this additional process we could simply use value returned by
+ # `os:getpid/0` for a systemd ready notification.
+ start_rabbitmq_server "$@"
+else
# When RabbitMQ runs in the foreground but the Erlang shell is
# disabled, we setup signal handlers to stop RabbitMQ properly. This
# is at least useful in the case of Docker.
@@ -153,7 +209,7 @@ if [ 'x' = "x$RABBITMQ_ALLOW_INPUT" -a -z "$detached" ]; then
RABBITMQ_SERVER_START_ARGS="${RABBITMQ_SERVER_START_ARGS} +B i"
# Signal handlers. They all stop RabbitMQ properly (using
- # rabbitmqctl stop). Depending on the signal, this script will exwit
+ # rabbitmqctl stop). Depending on the signal, this script will exit
# with a non-zero error code:
# SIGHUP SIGTERM SIGTSTP
# They are considered a normal process termination, so the script
@@ -169,6 +225,4 @@ if [ 'x' = "x$RABBITMQ_ALLOW_INPUT" -a -z "$detached" ]; then
# Block until RabbitMQ exits or a signal is caught.
# Waits for last command (which is start_rabbitmq_server)
wait $!
-else
- start_rabbitmq_server "$@"
fi
diff --git a/scripts/rabbitmq-server-ha.ocf b/scripts/rabbitmq-server-ha.ocf
index 5505c105811a..ae7991833baa 100755
--- a/scripts/rabbitmq-server-ha.ocf
+++ b/scripts/rabbitmq-server-ha.ocf
@@ -13,8 +13,8 @@
#
# See usage() function below for more details ...
#
-# Note that the script uses set_rabbitmq_policy.sh script located in the
-# same directory to setup RabbitMQ policies.
+# Note that the script uses an external file to setup RabbitMQ policies
+# so make sure to create it from an example shipped with the package.
#
#######################################################################
# Initialization:
@@ -45,7 +45,8 @@ OCF_RESKEY_erlang_cookie_default=false
OCF_RESKEY_erlang_cookie_file_default="/var/lib/rabbitmq/.erlang.cookie"
OCF_RESKEY_use_fqdn_default=false
OCF_RESKEY_fqdn_prefix_default=""
-OCF_RESKEY_max_rabbitmqctl_timeouts_default=1
+OCF_RESKEY_max_rabbitmqctl_timeouts_default=3
+OCF_RESKEY_policy_file_default="/usr/local/sbin/set_rabbitmq_policy"
: ${HA_LOGTAG="lrmd"}
: ${HA_LOGFACILITY="daemon"}
@@ -66,6 +67,7 @@ OCF_RESKEY_max_rabbitmqctl_timeouts_default=1
: ${OCF_RESKEY_use_fqdn=${OCF_RESKEY_use_fqdn_default}}
: ${OCF_RESKEY_fqdn_prefix=${OCF_RESKEY_fqdn_prefix_default}}
: ${OCF_RESKEY_max_rabbitmqctl_timeouts=${OCF_RESKEY_max_rabbitmqctl_timeouts_default}}
+: ${OCF_RESKEY_policy_file=${OCF_RESKEY_policy_file_default}}
#######################################################################
@@ -288,6 +290,14 @@ If too many timeouts happen in a raw, the monitor call will return with error.
+
+
+A path to the shell script to setup RabbitMQ policies
+
+A policy file path
+
+
+
$EXTENDED_OCF_PARAMS
@@ -613,7 +623,7 @@ rmq_setup_env() {
fi
done
- export LL="${OCF_RESOURCE_INSTANCE}:"
+ export LL="${OCF_RESOURCE_INSTANCE}[$$]:"
update_cookie
}
@@ -752,6 +762,31 @@ get_alive_pacemaker_nodes_but()
fi
}
+# Get current master. If a parameter is provided,
+# do not check node with that name
+get_master_name_but()
+{
+ local node
+ for node in $(get_alive_pacemaker_nodes_but "$@")
+ do
+ ocf_log info "${LH} looking if $node is master"
+
+ if is_master $node; then
+ ocf_log info "${LH} master is $node"
+ echo $node
+ break
+ fi
+ done
+}
+
+# Returns 0 if we are clustered with provideded node
+is_clustered_with()
+{
+ get_running_nodes | grep -q $(rabbit_node_name $1);
+ return $?
+}
+
+
check_need_join_to() {
local join_to
local node
@@ -929,9 +964,10 @@ unjoin_nodes_from_cluster() {
local tries=0
until [ $tries -eq 5 ]; do
tries=$((tries+1))
- if get_running_nodes | grep -q $(rabbit_node_name $nodename)
- then
+ if is_clustered_with $nodename; then
ocf_log info "${LH} the ${nodename} is alive and cannot be kicked from the cluster yet"
+ else
+ break
fi
sleep 10
done
@@ -1260,6 +1296,7 @@ start_rmq_server_app() {
get_status() {
local what="${1:-kernel}"
local rc=$OCF_NOT_RUNNING
+ local LH="${LL} get_status():"
local body
local beam_running
@@ -1270,11 +1307,11 @@ get_status() {
beam_running=$?
# report not running only if the which_applications() reported an error AND the beam is not running
if [ $rc -ne 0 -a $beam_running -ne 0 ] ; then
- ocf_log info "get_status() failed with code ${rc}. Command output: ${body}"
+ ocf_log info "${LH} failed with code ${rc}. Command output: ${body}"
return $OCF_NOT_RUNNING
# return a generic error, if there were errors and beam is found running
elif [ $rc -ne 0 ] ; then
- ocf_log info "get_status() found the beam process running but failed with code ${rc}. Command output: ${body}"
+ ocf_log info "${LH} found the beam process running but failed with code ${rc}. Command output: ${body}"
return $OCF_ERR_GENERIC
fi
@@ -1284,7 +1321,7 @@ get_status() {
echo "$body" | grep "\{${what}," 2>&1 > /dev/null && rc=$OCF_SUCCESS
if [ $rc -ne $OCF_SUCCESS ] ; then
- ocf_log info "get_status(): app ${what} was not found in command output: ${body}"
+ ocf_log info "${LH} app ${what} was not found in command output: ${body}"
fi
fi
@@ -1371,7 +1408,6 @@ get_monitor() {
local name
local node
local nodelist
- local rc_check=$OCF_SUCCESS
local max
local our_uptime
local node_uptime
@@ -1408,58 +1444,47 @@ get_monitor() {
if [ $rabbit_running -eq $OCF_SUCCESS ]
then
- ocf_log info "${LH} rabbit app is running. checking if we are the part of healthy cluster"
+ ocf_log info "${LH} rabbit app is running. checking if we are the part of healthy cluster"
+
+ if [ $rc -eq $OCF_RUNNING_MASTER ] ; then
+ # The master is always running inside of its cluster
+ ocf_log info "${LH} rabbit app is running and is master of cluster"
+
+ else
+ local master_name=$(get_master_name_but $THIS_PCMK_NODE)
+
+ if [ -z "$master_name" ]; then
+ ocf_log info "${LH} no master is elected currently. Skipping cluster health check."
+
+ elif is_clustered_with $master_name; then
+ ocf_log info "${LH} rabbit app is running and is member of healthy cluster"
- if [ $rc -eq $OCF_RUNNING_MASTER ] ; then
- # The master is always running inside of its cluster
- ocf_log info "${LH} rabbit app is running and is master of cluster"
- rc_check=$OCF_SUCCESS
else
- rc_check=$OCF_ERR_GENERIC
- nodelist=$(get_alive_pacemaker_nodes_but)
- for node in $nodelist
- do
- ocf_log info "${LH} rabbit app is running. looking for master on $node"
- is_master $node
- status_master=$?
- ocf_log info "${LH} fetched master attribute for $node. attr value is ${status_master}"
- if [ $status_master -eq 0 ] ; then
- ocf_log info "${LH} rabbit app is running. master is $node"
- if get_running_nodes | grep -q $(rabbit_node_name $node)
- then
- ocf_log info "${LH} rabbit app is running and is member of healthy cluster"
- rc_check=$OCF_SUCCESS
- break
- fi
- fi
- done
- [ $rc_check -eq $OCF_ERR_GENERIC ] && ocf_log err "${LH} rabbit node is running out of the cluster"
+ # Rabbit is running but is not connected to master
+ # Failing to avoid split brain
+ ocf_log err "${LH} rabbit node is running out of the cluster"
+ rc=$OCF_ERR_GENERIC
fi
+ fi
else
- if [ "$OCF_CHECK_LEVEL" -gt 20 ]; then
+ if [ "$OCF_CHECK_LEVEL" -gt 20 ]; then
ocf_log info "${LH} rabbit app is not running. checking if there is a master"
# Do not refetch the master status as we know it already
if [ $rc -eq $OCF_RUNNING_MASTER ]; then
ocf_log err "${LH} we are the master and rabbit app is not running. this is a failure"
exit $OCF_FAILED_MASTER
fi
- nodelist=$(get_alive_pacemaker_nodes_but $THIS_PCMK_NODE)
- rc_check=$OCF_SUCCESS
- for node in $nodelist
- do
- is_master $node
- status_master=$?
- ocf_log info "${LH} fetched master attribute for $node. attr value is ${status_master}"
- if [ $status_master -eq 0 ] ; then
- rc_check=$OCF_ERR_GENERIC
- ocf_log info "${LH} rabbit app is not running. master is $node. exiting to be restarted by pacemaker"
- break
- fi
- done
- fi
+
+ local master_name=$(get_master_name_but $THIS_PCMK_NODE)
+
+ if [ -n "$master_name" ]; then
+ ocf_log info "${LH} master exists and rabbit app is not running. Exiting to be restarted by pacemaker"
+ rc=$OCF_ERR_GENERIC
+ fi
+ fi
fi
- if [ $rc -eq $OCF_ERR_GENERIC -o $rc_check -eq $OCF_ERR_GENERIC ]; then
+ if [ $rc -eq $OCF_ERR_GENERIC ]; then
ocf_log err "${LH} get_status() returns generic error ${rc}"
ocf_log info "${LH} ensuring this slave does not get promoted."
master_score 0
@@ -1887,23 +1912,33 @@ action_notify() {
case "$OCF_RESKEY_CRM_meta_notify_operation" in
promote)
ocf_log info "${LH} post-promote begin."
+
+ rc=$OCF_SUCCESS
+
# Do nothing, if the list of nodes being promoted reported empty.
# Delegate recovery, if needed, to the "running out of the cluster" monitor's logic
if [ -z "${OCF_RESKEY_CRM_meta_notify_promote_uname}" ] ; then
- ocf_log warn "${LH} there are no nodes to join to reported on post-promote. Nothing to do."
- ocf_log info "${LH} post-promote end."
- return $OCF_SUCCESS
+ ocf_log warn "${LH} there are no nodes to join to reported on post-promote. Nothing to do."
+
+ elif my_host "${OCF_RESKEY_CRM_meta_notify_promote_uname}"; then
+ ocf_log info "${LH} ignoring post-promote of self"
+
+ elif is_clustered_with "${OCF_RESKEY_CRM_meta_notify_promote_uname}"; then
+ ocf_log info "${LH} we are already clustered with master - ${OCF_RESKEY_CRM_meta_notify_promote_uname}. Nothing to do."
+
+ else
+ # Note, this should fail when the mnesia is inconsistent.
+ # For example, when the "old" master processing the promition of the new one.
+ # Later this ex-master node will rejoin the cluster at post-start.
+ jjj_join "${OCF_RESKEY_CRM_meta_notify_promote_uname}"
+ rc=$?
+ if [ $rc -eq $OCF_ERR_GENERIC ] ; then
+ ocf_log err "${LH} Failed to join the cluster on post-promote. The resource will be restarted."
+ fi
fi
- # Note, this should fail when the mnesia is inconsistent.
- # For example, when the "old" master processing the promition of the new one.
- # Later this ex-master node will rejoin the cluster at post-start.
- jjj_join "${OCF_RESKEY_CRM_meta_notify_promote_uname}"
- rc=$?
+
ocf_log info "${LH} post-promote end."
- if [ $rc -eq $OCF_ERR_GENERIC ] ; then
- ocf_log err "${LH} Failed to join the cluster on post-promote. The resource will be restarted."
- return $OCF_ERR_GENERIC
- fi
+ return $rc
;;
start)
ocf_log info "${LH} post-start begin."
@@ -2073,8 +2108,7 @@ action_promote() {
exit $OCF_FAILED_MASTER
fi
- local set_policy_path="$(dirname $0)/set_rabbitmq_policy.sh"
- [ -f $set_policy_path ] && . $set_policy_path
+ [ -f "${OCF_RESKEY_policy_file}" ] && . "${OCF_RESKEY_policy_file}"
# create timestamp file
nowtime="$(now)"
diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat
index 84908f380f3e..2a38e77a82e9 100644
--- a/scripts/rabbitmq-server.bat
+++ b/scripts/rabbitmq-server.bat
@@ -21,6 +21,7 @@ rem Preserve values that might contain exclamation marks before
rem enabling delayed expansion
set TDP0=%~dp0
set STAR=%*
+set CONF_SCRIPT_DIR="%~dp0"
setlocal enabledelayedexpansion
REM Get default settings with user overrides for (RABBITMQ_)
@@ -41,11 +42,16 @@ if not exist "!ERLANG_HOME!\bin\erl.exe" (
set RABBITMQ_EBIN_ROOT=!RABBITMQ_HOME!\ebin
+set RABBITMQ_CONFIG_FILE="!RABBITMQ_CONFIG_FILE!"
+
"!ERLANG_HOME!\bin\erl.exe" ^
-pa "!RABBITMQ_EBIN_ROOT!" ^
-noinput -hidden ^
-s rabbit_prelaunch ^
!RABBITMQ_NAME_TYPE! rabbitmqprelaunch!RANDOM!!TIME:~9! ^
+ -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
+ -rabbit enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
+ -rabbit plugins_dir "!$RABBITMQ_PLUGINS_DIR!" ^
-extra "!RABBITMQ_NODENAME!"
if ERRORLEVEL 2 (
@@ -56,13 +62,25 @@ if ERRORLEVEL 2 (
set RABBITMQ_DIST_ARG=-kernel inet_dist_listen_min !RABBITMQ_DIST_PORT! -kernel inet_dist_listen_max !RABBITMQ_DIST_PORT!
)
+if not exist "!RABBITMQ_SCHEMA_DIR!\rabbitmq.schema" (
+ copy "!RABBITMQ_HOME!\priv\schema\rabbitmq.schema" "!RABBITMQ_SCHEMA_DIR!\rabbitmq.schema"
+)
+
set RABBITMQ_EBIN_PATH="-pa !RABBITMQ_EBIN_ROOT!"
if exist "!RABBITMQ_CONFIG_FILE!.config" (
set RABBITMQ_CONFIG_ARG=-config "!RABBITMQ_CONFIG_FILE!"
-) else (
- set RABBITMQ_CONFIG_ARG=
-)
+) else if exist "!RABBITMQ_CONFIG_FILE!.conf" (
+ set RABBITMQ_CONFIG_ARG=-conf "!RABBITMQ_CONFIG_FILE!" ^
+ -conf_dir !RABBITMQ_GENERATED_CONFIG_DIR! ^
+ -conf_script_dir !CONF_SCRIPT_DIR:\=/! ^
+ -conf_schema_dir !RABBITMQ_SCHEMA_DIR!
+ if exist "!RABBITMQ_ADVANCED_CONFIG_FILE!.config" (
+ set RABBITMQ_CONFIG_ARG=!RABBITMQ_CONFIG_ARG! ^
+ -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
+ -config "!RABBITMQ_ADVANCED_CONFIG_FILE!"
+ )
+)
set RABBITMQ_LISTEN_ARG=
if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
@@ -91,7 +109,18 @@ if "!RABBITMQ_NODE_ONLY!"=="" (
)
if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" (
- set RABBITMQ_IO_THREAD_POOL_ARG=30
+ set RABBITMQ_IO_THREAD_POOL_SIZE=64
+)
+
+
+set ENV_OK=true
+CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE!
+CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE!
+CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME!
+
+
+if "!ENV_OK!"=="false" (
+ EXIT /b 78
)
"!ERLANG_HOME!\bin\erl.exe" ^
@@ -122,5 +151,16 @@ if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" (
!RABBITMQ_DIST_ARG! ^
!STAR!
+EXIT /B 0
+
+:check_not_empty
+if "%~2"=="" (
+ ECHO "Error: ENV variable should be defined: %1. Please check rabbitmq-env and rabbitmq-defaults, and !RABBITMQ_CONF_ENV_FILE! script files. Check also your Environment Variables settings"
+ set ENV_OK=false
+ EXIT /B 78
+ )
+EXIT /B 0
+
endlocal
endlocal
+
diff --git a/scripts/rabbitmq-service.bat b/scripts/rabbitmq-service.bat
index 404d167d0388..7e80e78398dc 100644
--- a/scripts/rabbitmq-service.bat
+++ b/scripts/rabbitmq-service.bat
@@ -21,6 +21,7 @@ rem Preserve values that might contain exclamation marks before
rem enabling delayed expansion
set TN0=%~n0
set TDP0=%~dp0
+set CONF_SCRIPT_DIR="%~dp0"
set P1=%1
setlocal enabledelayedexpansion
@@ -104,6 +105,16 @@ if not exist "!RABBITMQ_BASE!" (
echo Creating base directory !RABBITMQ_BASE! & md "!RABBITMQ_BASE!"
)
+set ENV_OK=true
+CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE!
+CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE!
+CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME!
+
+
+if "!ENV_OK!"=="false" (
+ EXIT /b 78
+)
+
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" list !RABBITMQ_SERVICENAME! 2>NUL 1>NUL
if errorlevel 1 (
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" add !RABBITMQ_SERVICENAME! -internalservicename !RABBITMQ_SERVICENAME!
@@ -113,10 +124,16 @@ if errorlevel 1 (
set RABBITMQ_EBIN_ROOT=!RABBITMQ_HOME!\ebin
+set RABBITMQ_CONFIG_FILE="!RABBITMQ_CONFIG_FILE!"
+
+
"!ERLANG_HOME!\bin\erl.exe" ^
-pa "!RABBITMQ_EBIN_ROOT!" ^
-noinput -hidden ^
-s rabbit_prelaunch ^
+ -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
+ -rabbit enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
+ -rabbit plugins_dir "!$RABBITMQ_PLUGINS_DIR!" ^
!RABBITMQ_NAME_TYPE! rabbitmqprelaunch!RANDOM!!TIME:~9!
if ERRORLEVEL 3 (
@@ -131,10 +148,29 @@ if ERRORLEVEL 3 (
set RABBITMQ_DIST_ARG=-kernel inet_dist_listen_min !RABBITMQ_DIST_PORT! -kernel inet_dist_listen_max !RABBITMQ_DIST_PORT!
)
+if not exist "!RABBITMQ_SCHEMA_DIR!\rabbitmq.schema" (
+ copy "!RABBITMQ_HOME!\priv\schema\rabbitmq.schema" "!RABBITMQ_SCHEMA_DIR!\rabbitmq.schema"
+)
+ REM Try to create advanced config file, if it doesn't exist
+ REM It still can fail to be created, but at least not for default install
+if not exist "!RABBITMQ_ADVANCED_CONFIG_FILE!.config" (
+ echo []. > !RABBITMQ_ADVANCED_CONFIG_FILE!.config
+)
+
if exist "!RABBITMQ_CONFIG_FILE!.config" (
set RABBITMQ_CONFIG_ARG=-config "!RABBITMQ_CONFIG_FILE!"
) else (
- set RABBITMQ_CONFIG_ARG=
+ rem Always specify generated config arguments, we cannot
+ rem assume .conf file is available
+ set RABBITMQ_CONFIG_ARG=-conf "!RABBITMQ_CONFIG_FILE!" ^
+ -conf_dir !RABBITMQ_GENERATED_CONFIG_DIR! ^
+ -conf_script_dir !CONF_SCRIPT_DIR:\=/! ^
+ -conf_schema_dir !RABBITMQ_SCHEMA_DIR!
+ if exist "!RABBITMQ_ADVANCED_CONFIG_FILE!.config" (
+ set RABBITMQ_CONFIG_ARG=!RABBITMQ_CONFIG_ARG! ^
+ -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
+ -config "!RABBITMQ_ADVANCED_CONFIG_FILE!"
+ )
)
set RABBITMQ_LISTEN_ARG=
@@ -156,7 +192,11 @@ if "!RABBITMQ_NODE_ONLY!"=="" (
)
if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" (
- set RABBITMQ_IO_THREAD_POOL_SIZE=30
+ set RABBITMQ_IO_THREAD_POOL_SIZE=64
+)
+
+if "!RABBITMQ_SERVICE_RESTART!"=="" (
+ set RABBITMQ_SERVICE_RESTART=restart
)
set ERLANG_SERVICE_ARGUMENTS= ^
@@ -187,10 +227,15 @@ set ERLANG_SERVICE_ARGUMENTS= ^
!RABBITMQ_DIST_ARG! ^
!STARVAR!
+echo "!ERLANG_SERVICE_ARGUMENTS!" > "!RABBITMQ_CONFIG_FILE!.txt"
+
set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:\=\\!
set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"!
+
+
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" set !RABBITMQ_SERVICENAME! ^
+-onfail !RABBITMQ_SERVICE_RESTART! ^
-machine "!ERLANG_SERVICE_MANAGER_PATH!\erl.exe" ^
-env ERL_CRASH_DUMP="!RABBITMQ_BASE:\=/!/erl_crash.dump" ^
-env ERL_LIBS="!ERL_LIBS!" ^
@@ -212,5 +257,15 @@ goto END
:END
+EXIT /B 0
+
+:check_not_empty
+if "%~2"=="" (
+ ECHO "Error: ENV variable should be defined: %1. Please check rabbitmq-env, rabbitmq-default, and !RABBITMQ_CONF_ENV_FILE! script files. Check also your Environment Variables settings"
+ set ENV_OK=false
+ EXIT /B 78
+ )
+EXIT /B 0
+
endlocal
endlocal
diff --git a/scripts/rabbitmqctl b/scripts/rabbitmqctl
index 3705b9a97924..2336c3d46613 100755
--- a/scripts/rabbitmqctl
+++ b/scripts/rabbitmqctl
@@ -30,7 +30,7 @@ fi
RABBITMQ_USE_LONGNAME=${RABBITMQ_USE_LONGNAME} \
exec ${ERL_DIR}erl \
-pa "${RABBITMQ_HOME}/ebin" \
- -noinput \
+ -noinput +B \
-hidden \
${RABBITMQ_CTL_ERL_ARGS} \
-boot "${CLEAN_BOOT_FILE}" \
diff --git a/scripts/travis_test_ocf_ra.sh b/scripts/travis_test_ocf_ra.sh
new file mode 100644
index 000000000000..e8f9a7419494
--- /dev/null
+++ b/scripts/travis_test_ocf_ra.sh
@@ -0,0 +1,30 @@
+#!/bin/sh -eux
+# Prepare and run a smoke test against the RabbitMQ OCF RA only if
+# the scripts/rabbitmq-server-ha.ocf has changes
+if ! git diff HEAD~ --name-only | grep -q scripts/rabbitmq-server-ha.ocf
+then
+ exit 0
+fi
+
+export VAGRANT_VERSION=1.8.1
+export DOCKER_IMAGE=bogdando/rabbitmq-cluster-ocf-wily
+export UPLOAD_METHOD=none
+export DOCKER_MOUNTS="$(pwd)/scripts/rabbitmq-server-ha.ocf:/tmp/rabbitmq-server-ha"
+
+# Install vagrant and requirements
+sudo apt-get install -qq git wget
+wget --no-verbose https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/vagrant_${VAGRANT_VERSION}_x86_64.deb
+sudo dpkg -i --force-all ./vagrant_${VAGRANT_VERSION}_x86_64.deb
+vagrant plugin install vagrant-triggers
+
+# Update docker and prepare images
+sudo apt-get update
+sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install --only-upgrade docker-engine
+sudo service docker restart
+docker pull $DOCKER_IMAGE
+
+# Prepare and run a smoke test for a rabbitmq cluster by the OCF RA
+git clone https://github.com/bogdando/rabbitmq-cluster-ocf-vagrant.git
+cd ./rabbitmq-cluster-ocf-vagrant
+vagrant up --provider docker
+docker exec -it n1 /bin/bash /vagrant/vagrant_script/test_rabbitcluster.sh rabbit@n1 rabbit@n2
diff --git a/src/rabbit.app.src b/src/rabbit.app.src
index f347b24585d0..83e7237c806d 100644
--- a/src/rabbit.app.src
+++ b/src/rabbit.app.src
@@ -97,5 +97,8 @@
{msg_store_credit_disc_bound, {2000, 500}},
{msg_store_io_batch_size, 2048},
%% see rabbitmq-server#143
- {credit_flow_default_credit, {200, 50}}
+ {credit_flow_default_credit, {200, 50}},
+ %% see rabbitmq-server#248
+ %% and rabbitmq-server#667
+ {channel_operation_timeout, 15000}
]}]}.
diff --git a/src/rabbit.erl b/src/rabbit.erl
index def466701a32..7816cd53aa98 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -272,6 +272,7 @@ start() ->
boot() ->
start_it(fun() ->
+ ensure_config(),
ok = ensure_application_loaded(),
HipeResult = rabbit_hipe:maybe_hipe_compile(),
ok = start_logger(),
@@ -285,20 +286,138 @@ boot() ->
broker_start()
end).
+ensure_config() ->
+ case rabbit_config:prepare_and_use_config() of
+ {error, Reason} ->
+ {Format, Arg} = case Reason of
+ {generation_error, Error} -> {"~s", [Error]};
+ Other -> {"~p", [Other]}
+ end,
+ log_boot_error_and_exit(generate_config_file,
+ "~nConfig file generation failed "++Format,
+ Arg);
+ ok -> ok
+ end.
+
+
broker_start() ->
Plugins = rabbit_plugins:setup(),
ToBeLoaded = Plugins ++ ?APPS,
start_apps(ToBeLoaded),
- case os:type() of
- {win32, _} -> ok;
- _ ->
- %% Only for systemd unit with Type=notify. Errors are intentionally
- %% ignored: either you have working systemd-notify(1) or you don't
- %% care about systemd at all.
- os:cmd("systemd-notify --ready")
- end,
+ maybe_sd_notify(),
ok = log_broker_started(rabbit_plugins:active()).
+%% Try to send systemd ready notification if it makes sense in the
+%% current environment. standard_error is used intentionally in all
+%% logging statements, so all this messages will end in systemd
+%% journal.
+maybe_sd_notify() ->
+ case sd_notify_ready() of
+ false ->
+ io:format(standard_error, "systemd READY notification failed, beware of timeouts~n", []);
+ _ ->
+ ok
+ end.
+
+sd_notify_ready() ->
+ case {os:type(), os:getenv("NOTIFY_SOCKET")} of
+ {{win32, _}, _} ->
+ true;
+ {_, [_|_]} -> %% Non-empty NOTIFY_SOCKET, give it a try
+ sd_notify_legacy() orelse sd_notify_socat();
+ _ ->
+ true
+ end.
+
+sd_notify_data() ->
+ "READY=1\nSTATUS=Initialized\nMAINPID=" ++ os:getpid() ++ "\n".
+
+sd_notify_legacy() ->
+ case code:load_file(sd_notify) of
+ {module, sd_notify} ->
+ SDNotify = sd_notify,
+ SDNotify:sd_notify(0, sd_notify_data()),
+ true;
+ {error, _} ->
+ false
+ end.
+
+%% socat(1) is the most portable way the sd_notify could be
+%% implemented in erlang, without introducing some NIF. Currently the
+%% following issues prevent us from implementing it in a more
+%% reasonable way:
+%% - systemd-notify(1) is unstable for non-root users
+%% - erlang doesn't support unix domain sockets.
+%%
+%% Some details on how we ended with such a solution:
+%% https://github.com/rabbitmq/rabbitmq-server/issues/664
+sd_notify_socat() ->
+ case sd_current_unit() of
+ {ok, Unit} ->
+ io:format(standard_error, "systemd unit for activation check: \"~s\"~n", [Unit]),
+ sd_notify_socat(Unit);
+ _ ->
+ false
+ end.
+
+socat_socket_arg("@" ++ AbstractUnixSocket) ->
+ "abstract-sendto:" ++ AbstractUnixSocket;
+socat_socket_arg(UnixSocket) ->
+ "unix-sendto:" ++ UnixSocket.
+
+sd_open_port() ->
+ open_port(
+ {spawn_executable, os:find_executable("socat")},
+ [{args, [socat_socket_arg(os:getenv("NOTIFY_SOCKET")), "STDIO"]},
+ use_stdio, out]).
+
+sd_notify_socat(Unit) ->
+ case sd_open_port() of
+ {'EXIT', Exit} ->
+ io:format(standard_error, "Failed to start socat ~p~n", [Exit]),
+ false;
+ Port ->
+ Port ! {self(), {command, sd_notify_data()}},
+ Result = sd_wait_activation(Port, Unit),
+ port_close(Port),
+ Result
+ end.
+
+sd_current_unit() ->
+ case catch re:run(os:cmd("systemctl status " ++ os:getpid()), "([-.@0-9a-zA-Z]+)", [unicode, {capture, all_but_first, list}]) of
+ {'EXIT', _} ->
+ error;
+ {match, [Unit]} ->
+ {ok, Unit};
+ _ ->
+ error
+ end.
+
+sd_wait_activation(Port, Unit) ->
+ case os:find_executable("systemctl") of
+ false ->
+ io:format(standard_error, "'systemctl' unavailable, falling back to sleep~n", []),
+ timer:sleep(5000),
+ true;
+ _ ->
+ sd_wait_activation(Port, Unit, 10)
+ end.
+
+sd_wait_activation(_, _, 0) ->
+ io:format(standard_error, "Service still in 'activating' state, bailing out~n", []),
+ false;
+sd_wait_activation(Port, Unit, AttemptsLeft) ->
+ case os:cmd("systemctl show --property=ActiveState " ++ Unit) of
+ "ActiveState=activating\n" ->
+ timer:sleep(1000),
+ sd_wait_activation(Port, Unit, AttemptsLeft - 1);
+ "ActiveState=" ++ _ ->
+ true;
+ _ = Err->
+ io:format(standard_error, "Unexpected status from systemd ~p~n", [Err]),
+ false
+ end.
+
start_it(StartFun) ->
Marker = spawn_link(fun() -> receive stop -> ok end end),
case catch register(rabbit_boot, Marker) of
@@ -335,6 +454,10 @@ stop_and_halt() ->
stop()
after
rabbit_log:info("Halting Erlang VM~n", []),
+ %% Also duplicate this information to stderr, so console where
+ %% foreground broker was running (or systemd journal) will
+ %% contain information about graceful termination.
+ io:format(standard_error, "Gracefully halting Erlang VM~n", []),
init:stop()
end,
ok.
@@ -643,7 +766,8 @@ print_banner() ->
"~n ###### ##"
"~n ########## Logs: ~s" ++
LogFmt ++
- "~n~n Starting broker...",
+ "~n~n Starting broker..."
+ "~n",
[Product, Version, ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE] ++
LogLocations).
@@ -678,11 +802,16 @@ log_banner() ->
rabbit_log:info("~n~s", [Banner]).
warn_if_kernel_config_dubious() ->
- case erlang:system_info(kernel_poll) of
- true -> ok;
- false -> rabbit_log:warning(
- "Kernel poll (epoll, kqueue, etc) is disabled. Throughput "
- "and CPU utilization may worsen.~n")
+ case os:type() of
+ {win32, _} ->
+ ok;
+ _ ->
+ case erlang:system_info(kernel_poll) of
+ true -> ok;
+ false -> rabbit_log:warning(
+ "Kernel poll (epoll, kqueue, etc) is disabled. Throughput "
+ "and CPU utilization may worsen.~n")
+ end
end,
AsyncThreads = erlang:system_info(thread_pool_size),
case AsyncThreads < ?ASYNC_THREADS_WARNING_THRESHOLD of
@@ -788,32 +917,7 @@ home_dir() ->
end.
config_files() ->
- Abs = fun (F) ->
- filename:absname(filename:rootname(F, ".config") ++ ".config")
- end,
- case init:get_argument(config) of
- {ok, Files} -> [Abs(File) || [File] <- Files];
- error -> case config_setting() of
- none -> [];
- File -> [Abs(File) ++ " (not found)"]
- end
- end.
-
-%% This is a pain. We want to know where the config file is. But we
-%% can't specify it on the command line if it is missing or the VM
-%% will fail to start, so we need to find it by some mechanism other
-%% than init:get_arguments/0. We can look at the environment variable
-%% which is responsible for setting it... but that doesn't work for a
-%% Windows service since the variable can change and the service not
-%% be reinstalled, so in that case we add a magic application env.
-config_setting() ->
- case application:get_env(rabbit, windows_service_config) of
- {ok, File1} -> File1;
- undefined -> case os:getenv("RABBITMQ_CONFIG_FILE") of
- false -> none;
- File2 -> File2
- end
- end.
+ rabbit_config:config_files().
%% We don't want this in fhc since it references rabbit stuff. And we can't put
%% this in the bootstep directly.
diff --git a/src/rabbit_amqqueue_process.erl b/src/rabbit_amqqueue_process.erl
index f79304632e64..6d3bf892b085 100644
--- a/src/rabbit_amqqueue_process.erl
+++ b/src/rabbit_amqqueue_process.erl
@@ -1367,7 +1367,7 @@ handle_pre_hibernate(State = #q{backing_queue = BQ,
format_message_queue(Opt, MQ) -> rabbit_misc:format_message_queue(Opt, MQ).
-log_delete_exclusive({ConPid, ConRef}, State) ->
+log_delete_exclusive({ConPid, _ConRef}, State) ->
log_delete_exclusive(ConPid, State);
log_delete_exclusive(ConPid, #q{ q = #amqqueue{ name = Resource } }) ->
#resource{ name = QName, virtual_host = VHost } = Resource,
diff --git a/src/rabbit_auth_backend_dummy.erl b/src/rabbit_auth_backend_dummy.erl
deleted file mode 100644
index 0077b4c99372..000000000000
--- a/src/rabbit_auth_backend_dummy.erl
+++ /dev/null
@@ -1,48 +0,0 @@
-%% 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_auth_backend_dummy).
--include("rabbit.hrl").
-
--behaviour(rabbit_authn_backend).
--behaviour(rabbit_authz_backend).
-
--export([user/0]).
--export([user_login_authentication/2, user_login_authorization/1,
- check_vhost_access/3, check_resource_access/3]).
-
--ifdef(use_specs).
-
--spec(user/0 :: () -> rabbit_types:user()).
-
--endif.
-
-%% A user to be used by the direct client when permission checks are
-%% not needed. This user can do anything AMQPish.
-user() -> #user{username = <<"none">>,
- tags = [],
- authz_backends = [{?MODULE, none}]}.
-
-%% Implementation of rabbit_auth_backend
-
-user_login_authentication(_, _) ->
- {refused, "cannot log in conventionally as dummy user", []}.
-
-user_login_authorization(_) ->
- {refused, "cannot log in conventionally as dummy user", []}.
-
-check_vhost_access(#auth_user{}, _VHostPath, _Sock) -> true.
-check_resource_access(#auth_user{}, #resource{}, _Permission) -> true.
diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl
deleted file mode 100644
index d7705d8e7b70..000000000000
--- a/src/rabbit_auth_backend_internal.erl
+++ /dev/null
@@ -1,400 +0,0 @@
-%% 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_auth_backend_internal).
--include("rabbit.hrl").
-
--behaviour(rabbit_authn_backend).
--behaviour(rabbit_authz_backend).
-
--export([user_login_authentication/2, user_login_authorization/1,
- check_vhost_access/3, check_resource_access/3]).
-
--export([add_user/2, delete_user/1, lookup_user/1,
- change_password/2, clear_password/1,
- hash_password/2, change_password_hash/2, change_password_hash/3,
- set_tags/2, set_permissions/5, clear_permissions/2]).
--export([user_info_keys/0, perms_info_keys/0,
- user_perms_info_keys/0, vhost_perms_info_keys/0,
- user_vhost_perms_info_keys/0,
- list_users/0, list_users/2, list_permissions/0,
- list_user_permissions/1, list_user_permissions/3,
- list_vhost_permissions/1, list_vhost_permissions/3,
- list_user_vhost_permissions/2]).
-
-%% for testing
--export([hashing_module_for_user/1]).
-
-%%----------------------------------------------------------------------------
-
--ifdef(use_specs).
-
--type(regexp() :: binary()).
-
--spec(add_user/2 :: (rabbit_types:username(), rabbit_types:password()) -> 'ok').
--spec(delete_user/1 :: (rabbit_types:username()) -> 'ok').
--spec(lookup_user/1 :: (rabbit_types:username())
- -> rabbit_types:ok(rabbit_types:internal_user())
- | rabbit_types:error('not_found')).
--spec(change_password/2 :: (rabbit_types:username(), rabbit_types:password())
- -> 'ok').
--spec(clear_password/1 :: (rabbit_types:username()) -> 'ok').
--spec(hash_password/2 :: (module(), rabbit_types:password())
- -> rabbit_types:password_hash()).
--spec(change_password_hash/2 :: (rabbit_types:username(),
- rabbit_types:password_hash()) -> 'ok').
--spec(set_tags/2 :: (rabbit_types:username(), [atom()]) -> 'ok').
--spec(set_permissions/5 ::(rabbit_types:username(), rabbit_types:vhost(),
- regexp(), regexp(), regexp()) -> 'ok').
--spec(clear_permissions/2 :: (rabbit_types:username(), rabbit_types:vhost())
- -> 'ok').
--spec(user_info_keys/0 :: () -> rabbit_types:info_keys()).
--spec(perms_info_keys/0 :: () -> rabbit_types:info_keys()).
--spec(user_perms_info_keys/0 :: () -> rabbit_types:info_keys()).
--spec(vhost_perms_info_keys/0 :: () -> rabbit_types:info_keys()).
--spec(user_vhost_perms_info_keys/0 :: () -> rabbit_types:info_keys()).
--spec(list_users/0 :: () -> [rabbit_types:infos()]).
--spec(list_users/2 :: (reference(), pid()) -> 'ok').
--spec(list_permissions/0 :: () -> [rabbit_types:infos()]).
--spec(list_user_permissions/1 ::
- (rabbit_types:username()) -> [rabbit_types:infos()]).
--spec(list_user_permissions/3 ::
- (rabbit_types:username(), reference(), pid()) -> 'ok').
--spec(list_vhost_permissions/1 ::
- (rabbit_types:vhost()) -> [rabbit_types:infos()]).
--spec(list_vhost_permissions/3 ::
- (rabbit_types:vhost(), reference(), pid()) -> 'ok').
--spec(list_user_vhost_permissions/2 ::
- (rabbit_types:username(), rabbit_types:vhost())
- -> [rabbit_types:infos()]).
-
--endif.
-
-%%----------------------------------------------------------------------------
-%% Implementation of rabbit_auth_backend
-
-%% Returns a password hashing module for the user record provided. If
-%% there is no information in the record, we consider it to be legacy
-%% (inserted by a version older than 3.6.0) and fall back to MD5, the
-%% now obsolete hashing function.
-hashing_module_for_user(#internal_user{
- hashing_algorithm = ModOrUndefined}) ->
- rabbit_password:hashing_mod(ModOrUndefined).
-
-user_login_authentication(Username, []) ->
- internal_check_user_login(Username, fun(_) -> true end);
-user_login_authentication(Username, [{password, Cleartext}]) ->
- internal_check_user_login(
- Username,
- fun (#internal_user{password_hash = <>} = U) ->
- Hash =:= rabbit_password:salted_hash(
- hashing_module_for_user(U), Salt, Cleartext);
- (#internal_user{}) ->
- false
- end);
-user_login_authentication(Username, AuthProps) ->
- exit({unknown_auth_props, Username, AuthProps}).
-
-user_login_authorization(Username) ->
- case user_login_authentication(Username, []) of
- {ok, #auth_user{impl = Impl, tags = Tags}} -> {ok, Impl, Tags};
- Else -> Else
- end.
-
-internal_check_user_login(Username, Fun) ->
- Refused = {refused, "user '~s' - invalid credentials", [Username]},
- case lookup_user(Username) of
- {ok, User = #internal_user{tags = Tags}} ->
- case Fun(User) of
- true -> {ok, #auth_user{username = Username,
- tags = Tags,
- impl = none}};
- _ -> Refused
- end;
- {error, not_found} ->
- Refused
- end.
-
-check_vhost_access(#auth_user{username = Username}, VHostPath, _Sock) ->
- case mnesia:dirty_read({rabbit_user_permission,
- #user_vhost{username = Username,
- virtual_host = VHostPath}}) of
- [] -> false;
- [_R] -> true
- end.
-
-check_resource_access(#auth_user{username = Username},
- #resource{virtual_host = VHostPath, name = Name},
- Permission) ->
- case mnesia:dirty_read({rabbit_user_permission,
- #user_vhost{username = Username,
- virtual_host = VHostPath}}) of
- [] ->
- false;
- [#user_permission{permission = P}] ->
- PermRegexp = case element(permission_index(Permission), P) of
- %% <<"^$">> breaks Emacs' erlang mode
- <<"">> -> <<$^, $$>>;
- RE -> RE
- end,
- case re:run(Name, PermRegexp, [{capture, none}]) of
- match -> true;
- nomatch -> false
- end
- end.
-
-permission_index(configure) -> #permission.configure;
-permission_index(write) -> #permission.write;
-permission_index(read) -> #permission.read.
-
-%%----------------------------------------------------------------------------
-%% Manipulation of the user database
-
-add_user(Username, Password) ->
- rabbit_log:info("Creating user '~s'~n", [Username]),
- %% hash_password will pick the hashing function configured for us
- %% but we also need to store a hint as part of the record, so we
- %% retrieve it here one more time
- HashingMod = rabbit_password:hashing_mod(),
- User = #internal_user{username = Username,
- password_hash = hash_password(HashingMod, Password),
- tags = [],
- hashing_algorithm = HashingMod},
- R = rabbit_misc:execute_mnesia_transaction(
- fun () ->
- case mnesia:wread({rabbit_user, Username}) of
- [] ->
- ok = mnesia:write(rabbit_user, User, write);
- _ ->
- mnesia:abort({user_already_exists, Username})
- end
- end),
- rabbit_event:notify(user_created, [{name, Username}]),
- R.
-
-delete_user(Username) ->
- rabbit_log:info("Deleting user '~s'~n", [Username]),
- R = rabbit_misc:execute_mnesia_transaction(
- rabbit_misc:with_user(
- Username,
- fun () ->
- ok = mnesia:delete({rabbit_user, Username}),
- [ok = mnesia:delete_object(
- rabbit_user_permission, R, write) ||
- R <- mnesia:match_object(
- rabbit_user_permission,
- #user_permission{user_vhost = #user_vhost{
- username = Username,
- virtual_host = '_'},
- permission = '_'},
- write)],
- ok
- end)),
- rabbit_event:notify(user_deleted, [{name, Username}]),
- R.
-
-lookup_user(Username) ->
- rabbit_misc:dirty_read({rabbit_user, Username}).
-
-change_password(Username, Password) ->
- rabbit_log:info("Changing password for '~s'~n", [Username]),
- HashingAlgorithm = rabbit_password:hashing_mod(),
- R = change_password_hash(Username,
- hash_password(rabbit_password:hashing_mod(),
- Password),
- HashingAlgorithm),
- rabbit_event:notify(user_password_changed, [{name, Username}]),
- R.
-
-clear_password(Username) ->
- rabbit_log:info("Clearing password for '~s'~n", [Username]),
- R = change_password_hash(Username, <<"">>),
- rabbit_event:notify(user_password_cleared, [{name, Username}]),
- R.
-
-hash_password(HashingMod, Cleartext) ->
- rabbit_password:hash(HashingMod, Cleartext).
-
-change_password_hash(Username, PasswordHash) ->
- change_password_hash(Username, PasswordHash, rabbit_password:hashing_mod()).
-
-
-change_password_hash(Username, PasswordHash, HashingAlgorithm) ->
- update_user(Username, fun(User) ->
- User#internal_user{
- password_hash = PasswordHash,
- hashing_algorithm = HashingAlgorithm }
- end).
-
-set_tags(Username, Tags) ->
- rabbit_log:info("Setting user tags for user '~s' to ~p~n",
- [Username, Tags]),
- R = update_user(Username, fun(User) ->
- User#internal_user{tags = Tags}
- end),
- rabbit_event:notify(user_tags_set, [{name, Username}, {tags, Tags}]),
- R.
-
-set_permissions(Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm) ->
- rabbit_log:info("Setting permissions for "
- "'~s' in '~s' to '~s', '~s', '~s'~n",
- [Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm]),
- lists:map(
- fun (RegexpBin) ->
- Regexp = binary_to_list(RegexpBin),
- case re:compile(Regexp) of
- {ok, _} -> ok;
- {error, Reason} -> throw({error, {invalid_regexp,
- Regexp, Reason}})
- end
- end, [ConfigurePerm, WritePerm, ReadPerm]),
- R = rabbit_misc:execute_mnesia_transaction(
- rabbit_misc:with_user_and_vhost(
- Username, VHostPath,
- fun () -> ok = mnesia:write(
- rabbit_user_permission,
- #user_permission{user_vhost = #user_vhost{
- username = Username,
- virtual_host = VHostPath},
- permission = #permission{
- configure = ConfigurePerm,
- write = WritePerm,
- read = ReadPerm}},
- write)
- end)),
- rabbit_event:notify(permission_created, [{user, Username},
- {vhost, VHostPath},
- {configure, ConfigurePerm},
- {write, WritePerm},
- {read, ReadPerm}]),
- R.
-
-clear_permissions(Username, VHostPath) ->
- R = rabbit_misc:execute_mnesia_transaction(
- rabbit_misc:with_user_and_vhost(
- Username, VHostPath,
- fun () ->
- ok = mnesia:delete({rabbit_user_permission,
- #user_vhost{username = Username,
- virtual_host = VHostPath}})
- end)),
- rabbit_event:notify(permission_deleted, [{user, Username},
- {vhost, VHostPath}]),
- R.
-
-
-update_user(Username, Fun) ->
- rabbit_misc:execute_mnesia_transaction(
- rabbit_misc:with_user(
- Username,
- fun () ->
- {ok, User} = lookup_user(Username),
- ok = mnesia:write(rabbit_user, Fun(User), write)
- end)).
-
-%%----------------------------------------------------------------------------
-%% Listing
-
--define(PERMS_INFO_KEYS, [configure, write, read]).
--define(USER_INFO_KEYS, [user, tags]).
-
-user_info_keys() -> ?USER_INFO_KEYS.
-
-perms_info_keys() -> [user, vhost | ?PERMS_INFO_KEYS].
-vhost_perms_info_keys() -> [user | ?PERMS_INFO_KEYS].
-user_perms_info_keys() -> [vhost | ?PERMS_INFO_KEYS].
-user_vhost_perms_info_keys() -> ?PERMS_INFO_KEYS.
-
-list_users() ->
- [extract_internal_user_params(U) ||
- U <- mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})].
-
-list_users(Ref, AggregatorPid) ->
- rabbit_control_misc:emitting_map(
- AggregatorPid, Ref,
- fun(U) -> extract_internal_user_params(U) end,
- mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})).
-
-list_permissions() ->
- list_permissions(perms_info_keys(), match_user_vhost('_', '_')).
-
-list_permissions(Keys, QueryThunk) ->
- [extract_user_permission_params(Keys, U) ||
- %% TODO: use dirty ops instead
- U <- rabbit_misc:execute_mnesia_transaction(QueryThunk)].
-
-list_permissions(Keys, QueryThunk, Ref, AggregatorPid) ->
- rabbit_control_misc:emitting_map(
- AggregatorPid, Ref, fun(U) -> extract_user_permission_params(Keys, U) end,
- %% TODO: use dirty ops instead
- rabbit_misc:execute_mnesia_transaction(QueryThunk)).
-
-filter_props(Keys, Props) -> [T || T = {K, _} <- Props, lists:member(K, Keys)].
-
-list_user_permissions(Username) ->
- list_permissions(
- user_perms_info_keys(),
- rabbit_misc:with_user(Username, match_user_vhost(Username, '_'))).
-
-list_user_permissions(Username, Ref, AggregatorPid) ->
- list_permissions(
- user_perms_info_keys(),
- rabbit_misc:with_user(Username, match_user_vhost(Username, '_')),
- Ref, AggregatorPid).
-
-list_vhost_permissions(VHostPath) ->
- list_permissions(
- vhost_perms_info_keys(),
- rabbit_vhost:with(VHostPath, match_user_vhost('_', VHostPath))).
-
-list_vhost_permissions(VHostPath, Ref, AggregatorPid) ->
- list_permissions(
- vhost_perms_info_keys(),
- rabbit_vhost:with(VHostPath, match_user_vhost('_', VHostPath)),
- Ref, AggregatorPid).
-
-list_user_vhost_permissions(Username, VHostPath) ->
- list_permissions(
- user_vhost_perms_info_keys(),
- rabbit_misc:with_user_and_vhost(
- Username, VHostPath, match_user_vhost(Username, VHostPath))).
-
-extract_user_permission_params(Keys, #user_permission{
- user_vhost =
- #user_vhost{username = Username,
- virtual_host = VHostPath},
- permission = #permission{
- configure = ConfigurePerm,
- write = WritePerm,
- read = ReadPerm}}) ->
- filter_props(Keys, [{user, Username},
- {vhost, VHostPath},
- {configure, ConfigurePerm},
- {write, WritePerm},
- {read, ReadPerm}]).
-
-extract_internal_user_params(#internal_user{username = Username, tags = Tags}) ->
- [{user, Username}, {tags, Tags}].
-
-match_user_vhost(Username, VHostPath) ->
- fun () -> mnesia:match_object(
- rabbit_user_permission,
- #user_permission{user_vhost = #user_vhost{
- username = Username,
- virtual_host = VHostPath},
- permission = '_'},
- read)
- end.
diff --git a/src/rabbit_cli.erl b/src/rabbit_cli.erl
index 4aad3c091656..415150495631 100644
--- a/src/rabbit_cli.erl
+++ b/src/rabbit_cli.erl
@@ -18,17 +18,19 @@
-include("rabbit_cli.hrl").
-export([main/3, start_distribution/0, start_distribution/1,
- parse_arguments/4, rpc_call/4, rpc_call/5, rpc_call/7]).
+ parse_arguments/4, filter_opts/2,
+ rpc_call/4, rpc_call/5, rpc_call/7]).
%%----------------------------------------------------------------------------
-ifdef(use_specs).
+-type(option_name() :: string()).
+-type(option_value() :: string() | node() | boolean()).
-type(optdef() :: flag | {option, string()}).
--type(parse_result() :: {'ok', {atom(), [{string(), string()}], [string()]}} |
+-type(parse_result() :: {'ok', {atom(), [{option_name(), option_value()}], [string()]}} |
'no_command').
-
-spec(main/3 :: (fun (([string()], string()) -> parse_result()),
fun ((atom(), atom(), [any()], [any()]) -> any()),
atom()) -> no_return()).
@@ -38,6 +40,9 @@
-spec(parse_arguments/4 ::
([{atom(), [{string(), optdef()}]} | atom()],
[{string(), optdef()}], string(), [string()]) -> parse_result()).
+
+-spec(filter_opts/2 :: ([{option_name(), option_value()}], [option_name()]) -> [boolean()]).
+
-spec(rpc_call/4 :: (node(), atom(), atom(), [any()]) -> any()).
-spec(rpc_call/5 :: (node(), atom(), atom(), [any()], number()) -> any()).
-spec(rpc_call/7 :: (node(), atom(), atom(), [any()], reference(), pid(),
@@ -117,7 +122,10 @@ main(ParseFun, DoFun, UsageMod) ->
_ ->
print_error("unable to connect to node ~w: ~w", [Node, Reason]),
print_badrpc_diagnostics([Node]),
- rabbit_misc:quit(?EX_UNAVAILABLE)
+ case Command of
+ stop -> rabbit_misc:quit(?EX_OK);
+ _ -> rabbit_misc:quit(?EX_UNAVAILABLE)
+ end
end;
{badrpc_multi, Reason, Nodes} ->
print_error("unable to connect to nodes ~p: ~w", [Nodes, Reason]),
@@ -241,6 +249,22 @@ process_opts(Defs, C, [A | As], Found, KVs, Outs) ->
{none, _, _} -> no_command
end.
+%% When we have a set of flags that are used for filtering, we want by
+%% default to include every such option in our output. But if a user
+%% explicitly specified any such flag, we want to include only items
+%% which he has requested.
+filter_opts(CurrentOptionValues, AllOptionNames) ->
+ Explicit = lists:map(fun(OptName) ->
+ proplists:get_bool(OptName, CurrentOptionValues)
+ end,
+ AllOptionNames),
+ case lists:member(true, Explicit) of
+ true ->
+ Explicit;
+ false ->
+ lists:duplicate(length(AllOptionNames), true)
+ end.
+
%%----------------------------------------------------------------------------
fmt_stderr(Format, Args) -> rabbit_misc:format_stderr(Format ++ "~n", Args).
@@ -255,14 +279,10 @@ print_badrpc_diagnostics(Nodes) ->
%% a timeout unless we set our ticktime to be the same. So let's do
%% that.
rpc_call(Node, Mod, Fun, Args) ->
- rpc_call(Node, Mod, Fun, Args, ?RPC_TIMEOUT).
+ rabbit_misc:rpc_call(Node, Mod, Fun, Args).
rpc_call(Node, Mod, Fun, Args, Timeout) ->
- case rpc:call(Node, net_kernel, get_net_ticktime, [], Timeout) of
- {badrpc, _} = E -> E;
- Time -> net_kernel:set_net_ticktime(Time, 0),
- rpc:call(Node, Mod, Fun, Args, Timeout)
- end.
+ rabbit_misc:rpc_call(Node, Mod, Fun, Args, Timeout).
rpc_call(Node, Mod, Fun, Args, Ref, Pid, Timeout) ->
- rpc_call(Node, Mod, Fun, Args++[Ref, Pid], Timeout).
+ rabbit_misc:rpc_call(Node, Mod, Fun, Args, Ref, Pid, Timeout).
diff --git a/src/rabbit_config.erl b/src/rabbit_config.erl
new file mode 100644
index 000000000000..67e7523ec0e3
--- /dev/null
+++ b/src/rabbit_config.erl
@@ -0,0 +1,179 @@
+-module(rabbit_config).
+
+-export([
+ generate_config_file/5,
+ prepare_and_use_config/0,
+ prepare_config/1,
+ update_app_config/1,
+ schema_dir/0,
+ config_files/0,
+ get_advanced_config/0
+ ]).
+
+prepare_and_use_config() ->
+ case legacy_erlang_term_config_used() of
+ true ->
+ %% Use .config file
+ ok;
+ false ->
+ case prepare_config(get_confs()) of
+ ok ->
+ %% No .conf to generate from
+ ok;
+ {ok, GeneratedConfigFile} ->
+ %% Generated config file
+ update_app_config(GeneratedConfigFile);
+ {error, Err} ->
+ {error, Err}
+ end
+ end.
+
+%% we support both the classic Erlang term
+%% config file (rabbitmq.config) as well as rabbitmq.conf
+legacy_erlang_term_config_used() ->
+ case init:get_argument(config) of
+ error -> false;
+ {ok, [Config | _]} ->
+ ConfigFile = Config ++ ".config",
+ rabbit_file:is_file(ConfigFile)
+ andalso
+ get_advanced_config() == none
+ end.
+
+get_confs() ->
+ case init:get_argument(conf) of
+ {ok, Configs} -> Configs;
+ _ -> []
+ end.
+
+prepare_config(Configs) ->
+ case {init:get_argument(conf_dir), init:get_argument(conf_script_dir)} of
+ {{ok, ConfDir}, {ok, ScriptDir}} ->
+ ConfFiles = [Config ++ ".conf" || [Config] <- Configs,
+ rabbit_file:is_file(Config ++
+ ".conf")],
+ case ConfFiles of
+ [] -> ok;
+ _ ->
+ case generate_config_file(ConfFiles, ConfDir, ScriptDir) of
+ {ok, GeneratedConfigFile} ->
+ {ok, GeneratedConfigFile};
+ {error, Reason} ->
+ {error, Reason}
+ end
+ end;
+ _ -> ok
+ end.
+
+update_app_config(ConfigFile) ->
+ ok = application_controller:change_application_data([], [ConfigFile]).
+
+generate_config_file(ConfFiles, ConfDir, ScriptDir) ->
+ generate_config_file(ConfFiles, ConfDir, ScriptDir,
+ schema_dir(), get_advanced_config()).
+
+
+generate_config_file(ConfFiles, ConfDir, ScriptDir, SchemaDir, Advanced) ->
+ prepare_plugin_schemas(SchemaDir),
+ % SchemaFile = filename:join([ScriptDir, "rabbitmq.schema"]),
+ Cuttlefish = filename:join([ScriptDir, "cuttlefish"]),
+ GeneratedDir = filename:join([ConfDir, "generated"]),
+
+ AdvancedConfigArg = case check_advanced_config(Advanced) of
+ {ok, FileName} -> [" -a ", FileName];
+ none -> []
+ end,
+ rabbit_file:recursive_delete([GeneratedDir]),
+ Command = lists:concat(["escript ", "\"", Cuttlefish, "\"",
+ " -f rabbitmq -s ", "\"", SchemaDir, "\"",
+ " -e ", "\"", ConfDir, "\"",
+ [[" -c ", ConfFile] || ConfFile <- ConfFiles],
+ AdvancedConfigArg]),
+ Result = rabbit_misc:os_cmd(Command),
+ case string:str(Result, " -config ") of
+ 0 -> {error, {generation_error, Result}};
+ _ ->
+ [OutFile] = rabbit_file:wildcard("rabbitmq.*.config", GeneratedDir),
+ ResultFile = filename:join([GeneratedDir, "rabbitmq.config"]),
+ rabbit_file:rename(filename:join([GeneratedDir, OutFile]),
+ ResultFile),
+ {ok, ResultFile}
+ end.
+
+schema_dir() ->
+ case init:get_argument(conf_schema_dir) of
+ {ok, SchemaDir} -> SchemaDir;
+ _ ->
+ case code:priv_dir(rabbit) of
+ {error, bad_name} -> filename:join([".", "priv", "schema"]);
+ PrivDir -> filename:join([PrivDir, "schema"])
+ end
+ end.
+
+check_advanced_config(none) -> none;
+check_advanced_config(ConfigName) ->
+ case rabbit_file:is_file(ConfigName) of
+ true -> {ok, ConfigName};
+ false -> none
+ end.
+
+get_advanced_config() ->
+ case init:get_argument(conf_advanced) of
+ %% There can be only one advanced.config
+ {ok, [FileName | _]} ->
+ ConfigName = FileName ++ ".config",
+ case rabbit_file:is_file(ConfigName) of
+ true -> ConfigName;
+ false -> none
+ end;
+ _ -> none
+ end.
+
+
+prepare_plugin_schemas(SchemaDir) ->
+ case rabbit_file:is_dir(SchemaDir) of
+ true -> rabbit_plugins:extract_schemas(SchemaDir);
+ false -> ok
+ end.
+
+
+config_files() ->
+ Abs = fun (F, Ex) -> filename:absname(filename:rootname(F, Ex) ++ Ex) end,
+ case legacy_erlang_term_config_used() of
+ true ->
+ case init:get_argument(config) of
+ {ok, Files} -> [Abs(File, ".config") || [File] <- Files];
+ error -> case config_setting() of
+ none -> [];
+ File -> [Abs(File, ".config")
+ ++
+ " (not found)"]
+ end
+ end;
+ false ->
+ ConfFiles = [Abs(File, ".conf") || File <- get_confs()],
+ AdvancedFiles = case get_advanced_config() of
+ none -> [];
+ FileName -> [Abs(FileName, ".config")]
+ end,
+ AdvancedFiles ++ ConfFiles
+
+ end.
+
+
+%% This is a pain. We want to know where the config file is. But we
+%% can't specify it on the command line if it is missing or the VM
+%% will fail to start, so we need to find it by some mechanism other
+%% than init:get_arguments/0. We can look at the environment variable
+%% which is responsible for setting it... but that doesn't work for a
+%% Windows service since the variable can change and the service not
+%% be reinstalled, so in that case we add a magic application env.
+config_setting() ->
+ case application:get_env(rabbit, windows_service_config) of
+ {ok, File1} -> File1;
+ undefined -> case os:getenv("RABBITMQ_CONFIG_FILE") of
+ false -> none;
+ File2 -> File2
+ end
+ end.
+
diff --git a/src/rabbit_control_main.erl b/src/rabbit_control_main.erl
index 793af7025961..693a6dc6fa3d 100644
--- a/src/rabbit_control_main.erl
+++ b/src/rabbit_control_main.erl
@@ -17,12 +17,13 @@
-module(rabbit_control_main).
-include("rabbit.hrl").
-include("rabbit_cli.hrl").
+-include("rabbit_misc.hrl").
-export([start/0, stop/0, parse_arguments/2, action/5, action/6,
sync_queue/1, cancel_sync_queue/1, become/1,
purge_queue/1]).
--import(rabbit_cli, [rpc_call/4, rpc_call/5, rpc_call/7]).
+-import(rabbit_misc, [rpc_call/4, rpc_call/5, rpc_call/7]).
-define(EXTERNAL_CHECK_INTERVAL, 1000).
@@ -75,7 +76,7 @@
{set_vhost_limits, [?VHOST_DEF]},
{clear_vhost_limits, [?VHOST_DEF]},
- {list_queues, [?VHOST_DEF]},
+ {list_queues, [?VHOST_DEF, ?OFFLINE_DEF, ?ONLINE_DEF]},
{list_exchanges, [?VHOST_DEF]},
{list_bindings, [?VHOST_DEF]},
{list_connections, [?VHOST_DEF]},
@@ -86,6 +87,7 @@
report,
set_cluster_name,
eval,
+ node_health_check,
close_connection,
{trace_on, [?VHOST_DEF]},
@@ -114,7 +116,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]).
+ environment, eval, force_boot, help, node_health_check]).
-define(COMMANDS_WITH_TIMEOUT,
[list_user_permissions, list_policies, list_queues, list_exchanges,
@@ -559,6 +561,17 @@ action(eval, Node, [Expr], _Opts, _Inform) ->
action(help, _Node, _Args, _Opts, _Inform) ->
io:format("~s", [rabbit_ctl_usage:usage()]);
+action(node_health_check, Node, _Args, _Opts, Inform) ->
+ Inform("Checking health of node ~p", [Node]),
+ try
+ rabbit_health_check:node(Node),
+ io:format("Health check passed~n")
+ catch
+ {node_is_ko, ErrorMsg, ErrorCode} ->
+ io:format("Heath check failed:~n~s~n", [ErrorMsg]),
+ halt(ErrorCode)
+ end;
+
action(Command, Node, Args, Opts, Inform) ->
%% For backward compatibility, run commands accepting a timeout with
%% the default timeout.
@@ -582,7 +595,8 @@ action(list_permissions, Node, [], Opts, Inform, Timeout) ->
VHost = proplists:get_value(?VHOST_OPT, Opts),
Inform("Listing permissions in vhost \"~s\"", [VHost]),
call(Node, {rabbit_auth_backend_internal, list_vhost_permissions, [VHost]},
- rabbit_auth_backend_internal:vhost_perms_info_keys(), true, Timeout);
+ rabbit_auth_backend_internal:vhost_perms_info_keys(), true, Timeout,
+ true);
action(list_parameters, Node, [], Opts, Inform, Timeout) ->
VHostArg = list_to_binary(proplists:get_value(?VHOST_OPT, Opts)),
@@ -607,13 +621,15 @@ action(list_user_permissions, _Node, _Args = [], _Opts, _Inform, _Timeout) ->
action(list_user_permissions, Node, Args = [_Username], _Opts, Inform, Timeout) ->
Inform("Listing permissions for user ~p", Args),
call(Node, {rabbit_auth_backend_internal, list_user_permissions, Args},
- rabbit_auth_backend_internal:user_perms_info_keys(), true, Timeout);
+ rabbit_auth_backend_internal:user_perms_info_keys(), true, Timeout,
+ true);
action(list_queues, Node, Args, Opts, Inform, Timeout) ->
+ [Online, Offline] = rabbit_cli:filter_opts(Opts, [?ONLINE_OPT, ?OFFLINE_OPT]),
Inform("Listing queues", []),
VHostArg = list_to_binary(proplists:get_value(?VHOST_OPT, Opts)),
ArgAtoms = default_if_empty(Args, [name, messages]),
- call(Node, {rabbit_amqqueue, info_all, [VHostArg, ArgAtoms]},
+ call(Node, {rabbit_amqqueue, info_all, [VHostArg, ArgAtoms, Online, Offline]},
ArgAtoms, Timeout);
action(list_exchanges, Node, Args, Opts, Inform, Timeout) ->
@@ -750,20 +766,33 @@ default_if_empty(List, Default) when is_list(List) ->
true -> [list_to_atom(X) || X <- List]
end.
-display_info_message(Result, InfoItemKeys) ->
+display_info_message_row(IsEscaped, Result, InfoItemKeys) ->
display_row([format_info_item(
case proplists:lookup(X, Result) of
none when is_list(Result), length(Result) > 0 ->
exit({error, {bad_info_key, X}});
none -> Result;
{X, Value} -> Value
- end) || X <- InfoItemKeys]).
+ end, IsEscaped) || X <- InfoItemKeys]).
+
+display_info_message(IsEscaped) ->
+ fun ([], _) ->
+ ok;
+ ([FirstResult|_] = List, InfoItemKeys) when is_list(FirstResult) ->
+ lists:foreach(fun(Result) ->
+ display_info_message_row(IsEscaped, Result, InfoItemKeys)
+ end,
+ List),
+ ok;
+ (Result, InfoItemKeys) ->
+ display_info_message_row(IsEscaped, Result, InfoItemKeys)
+ end.
display_info_list(Results, InfoItemKeys) when is_list(Results) ->
lists:foreach(
fun (Result) -> display_row(
- [format_info_item(proplists:get_value(X, Result)) ||
- X <- InfoItemKeys])
+ [format_info_item(proplists:get_value(X, Result), true)
+ || X <- InfoItemKeys])
end, lists:sort(Results)),
ok;
display_info_list(Other, _) ->
@@ -776,32 +805,33 @@ display_row(Row) ->
-define(IS_U8(X), (X >= 0 andalso X =< 255)).
-define(IS_U16(X), (X >= 0 andalso X =< 65535)).
-format_info_item(#resource{name = Name}) ->
- escape(Name);
-format_info_item({N1, N2, N3, N4} = Value) when
+format_info_item(#resource{name = Name}, IsEscaped) ->
+ escape(Name, IsEscaped);
+format_info_item({N1, N2, N3, N4} = Value, _IsEscaped) when
?IS_U8(N1), ?IS_U8(N2), ?IS_U8(N3), ?IS_U8(N4) ->
rabbit_misc:ntoa(Value);
-format_info_item({K1, K2, K3, K4, K5, K6, K7, K8} = Value) when
+format_info_item({K1, K2, K3, K4, K5, K6, K7, K8} = Value, _IsEscaped) when
?IS_U16(K1), ?IS_U16(K2), ?IS_U16(K3), ?IS_U16(K4),
?IS_U16(K5), ?IS_U16(K6), ?IS_U16(K7), ?IS_U16(K8) ->
rabbit_misc:ntoa(Value);
-format_info_item(Value) when is_pid(Value) ->
+format_info_item(Value, _IsEscaped) when is_pid(Value) ->
rabbit_misc:pid_to_string(Value);
-format_info_item(Value) when is_binary(Value) ->
- escape(Value);
-format_info_item(Value) when is_atom(Value) ->
- escape(atom_to_list(Value));
+format_info_item(Value, IsEscaped) when is_binary(Value) ->
+ escape(Value, IsEscaped);
+format_info_item(Value, IsEscaped) when is_atom(Value) ->
+ escape(atom_to_list(Value), IsEscaped);
format_info_item([{TableEntryKey, TableEntryType, _TableEntryValue} | _] =
- Value) when is_binary(TableEntryKey) andalso
- is_atom(TableEntryType) ->
- io_lib:format("~1000000000000p", [prettify_amqp_table(Value)]);
-format_info_item([T | _] = Value)
+ Value, IsEscaped) when is_binary(TableEntryKey) andalso
+ is_atom(TableEntryType) ->
+ io_lib:format("~1000000000000p", [prettify_amqp_table(Value, IsEscaped)]);
+format_info_item([T | _] = Value, IsEscaped)
when is_tuple(T) orelse is_pid(T) orelse is_binary(T) orelse is_atom(T) orelse
is_list(T) ->
"[" ++
lists:nthtail(2, lists:append(
- [", " ++ format_info_item(E) || E <- Value])) ++ "]";
-format_info_item(Value) ->
+ [", " ++ format_info_item(E, IsEscaped)
+ || E <- Value])) ++ "]";
+format_info_item(Value, _IsEscaped) ->
io_lib:format("~w", [Value]).
display_call_result(Node, MFA) ->
@@ -832,9 +862,12 @@ call(Node, {Mod, Fun, Args}) ->
rpc_call(Node, Mod, Fun, lists:map(fun list_to_binary_utf8/1, Args)).
call(Node, {Mod, Fun, Args}, InfoKeys, Timeout) ->
- call(Node, {Mod, Fun, Args}, InfoKeys, false, Timeout).
+ call(Node, {Mod, Fun, Args}, InfoKeys, false, Timeout, false).
call(Node, {Mod, Fun, Args}, InfoKeys, ToBinUtf8, Timeout) ->
+ call(Node, {Mod, Fun, Args}, InfoKeys, ToBinUtf8, Timeout, false).
+
+call(Node, {Mod, Fun, Args}, InfoKeys, ToBinUtf8, Timeout, IsEscaped) ->
Args0 = case ToBinUtf8 of
true -> lists:map(fun list_to_binary_utf8/1, Args);
false -> Args
@@ -854,7 +887,7 @@ call(Node, {Mod, Fun, Args}, InfoKeys, ToBinUtf8, Timeout) ->
end
end),
rabbit_control_misc:wait_for_info_messages(
- Pid, Ref, InfoKeys, fun display_info_message/2, Timeout).
+ Pid, Ref, InfoKeys, display_info_message(IsEscaped), Timeout).
list_to_binary_utf8(L) ->
B = list_to_binary(L),
@@ -867,9 +900,14 @@ list_to_binary_utf8(L) ->
%% characters. We don't escape characters above 127, since they may
%% form part of UTF-8 strings.
-escape(Atom) when is_atom(Atom) -> escape(atom_to_list(Atom));
-escape(Bin) when is_binary(Bin) -> escape(binary_to_list(Bin));
-escape(L) when is_list(L) -> escape_char(lists:reverse(L), []).
+escape(Atom, IsEscaped) when is_atom(Atom) ->
+ escape(atom_to_list(Atom), IsEscaped);
+escape(Bin, IsEscaped) when is_binary(Bin) ->
+ escape(binary_to_list(Bin), IsEscaped);
+escape(L, false) when is_list(L) ->
+ escape_char(lists:reverse(L), []);
+escape(L, true) when is_list(L) ->
+ L.
escape_char([$\\ | T], Acc) ->
escape_char(T, [$\\, $\\ | Acc]);
@@ -881,14 +919,18 @@ escape_char([X | T], Acc) ->
escape_char([], Acc) ->
Acc.
-prettify_amqp_table(Table) ->
- [{escape(K), prettify_typed_amqp_value(T, V)} || {K, T, V} <- Table].
-
-prettify_typed_amqp_value(longstr, Value) -> escape(Value);
-prettify_typed_amqp_value(table, Value) -> prettify_amqp_table(Value);
-prettify_typed_amqp_value(array, Value) -> [prettify_typed_amqp_value(T, V) ||
- {T, V} <- Value];
-prettify_typed_amqp_value(_Type, Value) -> Value.
+prettify_amqp_table(Table, IsEscaped) ->
+ [{escape(K, IsEscaped), prettify_typed_amqp_value(T, V, IsEscaped)}
+ || {K, T, V} <- Table].
+
+prettify_typed_amqp_value(longstr, Value, IsEscaped) ->
+ escape(Value, IsEscaped);
+prettify_typed_amqp_value(table, Value, IsEscaped) ->
+ prettify_amqp_table(Value, IsEscaped);
+prettify_typed_amqp_value(array, Value, IsEscaped) ->
+ [prettify_typed_amqp_value(T, V, IsEscaped) || {T, V} <- Value];
+prettify_typed_amqp_value(_Type, Value, _IsEscaped) ->
+ Value.
split_list([]) -> [];
split_list([_]) -> exit(even_list_needed);
diff --git a/src/rabbit_hipe.erl b/src/rabbit_hipe.erl
index 0302d82839e6..05b5f3719d1d 100644
--- a/src/rabbit_hipe.erl
+++ b/src/rabbit_hipe.erl
@@ -44,7 +44,8 @@ hipe_compile() ->
%% happens when RabbitMQ is stopped (just the
%% application, not the entire node) and started
%% again.
- already_hipe_compiled(HM)],
+ already_hipe_compiled(HM)
+ andalso (not compiled_with_version_support(HM))],
case HipeModules of
[] -> {ok, already_compiled};
_ -> do_hipe_compile(HipeModules)
@@ -59,6 +60,10 @@ already_hipe_compiled(Mod) ->
code:is_module_native(Mod) =:= false
end.
+compiled_with_version_support(Mod) ->
+ proplists:get_value(erlang_version_support, Mod:module_info(attributes))
+ =/= undefined.
+
do_hipe_compile(HipeModules) ->
Count = length(HipeModules),
io:format("~nHiPE compiling: |~s|~n |",
diff --git a/src/rabbit_mirror_queue_master.erl b/src/rabbit_mirror_queue_master.erl
index 057a4fad3116..e447e9de820a 100644
--- a/src/rabbit_mirror_queue_master.erl
+++ b/src/rabbit_mirror_queue_master.erl
@@ -43,7 +43,8 @@
backing_queue_state,
seen_status,
confirmed,
- known_senders
+ known_senders,
+ wait_timeout
}).
-ifdef(use_specs).
@@ -130,7 +131,8 @@ init_with_existing_bq(Q = #amqqueue{name = QName}, BQ, BQS) ->
backing_queue_state = BQS,
seen_status = dict:new(),
confirmed = [],
- known_senders = sets:new() }.
+ known_senders = sets:new(),
+ wait_timeout = rabbit_misc:get_env(rabbit, slave_wait_timeout, 15000) }.
stop_mirroring(State = #state { coordinator = CPid,
backing_queue = BQ,
@@ -203,7 +205,7 @@ delete_and_terminate(Reason, State = #state { backing_queue = BQ,
stop_all_slaves(Reason, State),
State#state{backing_queue_state = BQ:delete_and_terminate(Reason, BQS)}.
-stop_all_slaves(Reason, #state{name = QName, gm = GM}) ->
+stop_all_slaves(Reason, #state{name = QName, gm = GM, wait_timeout = WT}) ->
{ok, #amqqueue{slave_pids = SPids}} = rabbit_amqqueue:lookup(QName),
PidsMRefs = [{Pid, erlang:monitor(process, Pid)} || Pid <- [GM | SPids]],
ok = gm:broadcast(GM, {delete_and_terminate, Reason}),
@@ -215,7 +217,7 @@ stop_all_slaves(Reason, #state{name = QName, gm = GM}) ->
[receive
{'DOWN', MRef, process, _Pid, _Info} ->
ok
- after 15000 ->
+ after WT ->
rabbit_mirror_queue_misc:log_warning(
QName, "Missing 'DOWN' message from ~p in node ~p~n",
[Pid, node(Pid)]),
diff --git a/src/rabbit_plugins.erl b/src/rabbit_plugins.erl
index c7f5d501bf23..2f084ed28a4c 100644
--- a/src/rabbit_plugins.erl
+++ b/src/rabbit_plugins.erl
@@ -16,9 +16,11 @@
-module(rabbit_plugins).
-include("rabbit.hrl").
+-include_lib("stdlib/include/zip.hrl").
-export([setup/0, active/0, read_enabled/1, list/1, list/2, dependencies/3]).
-export([ensure/1]).
+-export([extract_schemas/1]).
%%----------------------------------------------------------------------------
@@ -46,6 +48,7 @@ ensure(FileJustChanged0) ->
FileJustChanged ->
Enabled = read_enabled(OurFile),
Wanted = prepare_plugins(Enabled),
+ rabbit_config:prepare_and_use_config(),
Current = active(),
Start = Wanted -- Current,
Stop = Current -- Wanted,
@@ -79,6 +82,50 @@ setup() ->
Enabled = read_enabled(EnabledFile),
prepare_plugins(Enabled).
+extract_schemas(SchemaDir) ->
+ application:load(rabbit),
+ {ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file),
+ Enabled = read_enabled(EnabledFile),
+
+ {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir),
+
+ AllPlugins = list(PluginsDistDir),
+ Wanted = dependencies(false, Enabled, AllPlugins),
+ WantedPlugins = lookup_plugins(Wanted, AllPlugins),
+ [ extract_schema(Plugin, SchemaDir) || Plugin <- WantedPlugins ],
+ application:unload(rabbit),
+ ok.
+
+extract_schema(#plugin{type = ez, location = Location}, SchemaDir) ->
+ {ok, Files} = zip:extract(Location,
+ [memory, {file_filter,
+ fun(#zip_file{name = Name}) ->
+ string:str(Name, "priv/schema") > 0
+ end}]),
+ lists:foreach(
+ fun({FileName, Content}) ->
+ ok = file:write_file(filename:join([SchemaDir,
+ filename:basename(FileName)]),
+ Content)
+ end,
+ Files),
+ ok;
+extract_schema(#plugin{type = dir, location = Location}, SchemaDir) ->
+ PluginSchema = filename:join([Location,
+ "priv",
+ "schema"]),
+ case rabbit_file:is_dir(PluginSchema) of
+ false -> ok;
+ true ->
+ PluginSchemaFiles =
+ [ filename:join(PluginSchema, FileName)
+ || FileName <- rabbit_file:wildcard(".*\\.schema",
+ PluginSchema) ],
+ [ file:copy(SchemaFile, SchemaDir)
+ || SchemaFile <- PluginSchemaFiles ]
+ end.
+
+
%% @doc Lists the plugins which are currently running.
active() ->
{ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir),
diff --git a/src/rabbit_plugins_main.erl b/src/rabbit_plugins_main.erl
index 4aeed4826c17..e248989a7a90 100644
--- a/src/rabbit_plugins_main.erl
+++ b/src/rabbit_plugins_main.erl
@@ -173,7 +173,7 @@ format_plugins(Node, Pattern, Opts, #cli{all = All,
EnabledImplicitly = Implicit -- Enabled,
{StatusMsg, Running} =
- case rabbit_cli:rpc_call(Node, rabbit_plugins, active, []) of
+ case rabbit_misc:rpc_call(Node, rabbit_plugins, active, []) of
{badrpc, _} -> {"[failed to contact ~s - status not shown]", []};
Active -> {"* = running on ~s", Active}
end,
@@ -279,7 +279,7 @@ sync(Node, ForceOnline, #cli{file = File}) ->
rpc_call(Node, Online, Mod, Fun, Args) ->
io:format("~nApplying plugin configuration to ~s...", [Node]),
- case rabbit_cli:rpc_call(Node, Mod, Fun, Args) of
+ case rabbit_misc:rpc_call(Node, Mod, Fun, Args) of
{ok, [], []} ->
io:format(" nothing to do.~n", []);
{ok, Start, []} ->
diff --git a/src/rabbit_prelaunch.erl b/src/rabbit_prelaunch.erl
index 5ecdd75acc42..3f83a153eaae 100644
--- a/src/rabbit_prelaunch.erl
+++ b/src/rabbit_prelaunch.erl
@@ -83,7 +83,7 @@ dist_port_set_check() ->
false ->
ok;
File ->
- case file:consult(File ++ ".config") of
+ case get_config(File) of
{ok, [Config]} ->
Kernel = pget(kernel, Config, []),
case {pget(inet_dist_listen_min, Kernel, none),
@@ -98,6 +98,16 @@ dist_port_set_check() ->
end
end.
+get_config(File) ->
+ case rabbit_file:is_file(File ++ ".config") of
+ true -> file:consult(File ++ ".config");
+ false ->
+ case rabbit_config:get_advanced_config() of
+ none -> {error, enoent};
+ FileName -> file:consult(FileName)
+ end
+ end.
+
dist_port_range_check() ->
case os:getenv("RABBITMQ_DIST_PORT") of
false -> ok;
diff --git a/src/rabbit_types.erl b/src/rabbit_types.erl
deleted file mode 100644
index c45c1f6d5d90..000000000000
--- a/src/rabbit_types.erl
+++ /dev/null
@@ -1,188 +0,0 @@
-%% 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_types).
-
--include("rabbit.hrl").
-
--ifdef(use_specs).
-
--export_type([maybe/1, info/0, infos/0, info_key/0, info_keys/0,
- message/0, msg_id/0, basic_message/0,
- delivery/0, content/0, decoded_content/0, undecoded_content/0,
- unencoded_content/0, encoded_content/0, message_properties/0,
- vhost/0, ctag/0, amqp_error/0, r/1, r2/2, r3/3, listener/0,
- binding/0, binding_source/0, binding_destination/0,
- amqqueue/0, exchange/0,
- connection/0, connection_name/0, tracked_connection/0,
- protocol/0, auth_user/0, user/0, internal_user/0,
- username/0, password/0, password_hash/0,
- ok/1, error/1, ok_or_error/1, ok_or_error2/2, ok_pid_or_error/0,
- channel_exit/0, connection_exit/0, mfargs/0, proc_name/0,
- proc_type_and_name/0, timestamp/0]).
-
--type(maybe(T) :: T | 'none').
--type(timestamp() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}).
--type(vhost() :: binary()).
--type(ctag() :: binary()).
-
-%% TODO: make this more precise by tying specific class_ids to
-%% specific properties
--type(undecoded_content() ::
- #content{class_id :: rabbit_framing:amqp_class_id(),
- properties :: 'none',
- properties_bin :: binary(),
- payload_fragments_rev :: [binary()]} |
- #content{class_id :: rabbit_framing:amqp_class_id(),
- properties :: rabbit_framing:amqp_property_record(),
- properties_bin :: 'none',
- payload_fragments_rev :: [binary()]}).
--type(unencoded_content() :: undecoded_content()).
--type(decoded_content() ::
- #content{class_id :: rabbit_framing:amqp_class_id(),
- properties :: rabbit_framing:amqp_property_record(),
- properties_bin :: maybe(binary()),
- payload_fragments_rev :: [binary()]}).
--type(encoded_content() ::
- #content{class_id :: rabbit_framing:amqp_class_id(),
- properties :: maybe(rabbit_framing:amqp_property_record()),
- properties_bin :: binary(),
- payload_fragments_rev :: [binary()]}).
--type(content() :: undecoded_content() | decoded_content()).
--type(msg_id() :: rabbit_guid:guid()).
--type(basic_message() ::
- #basic_message{exchange_name :: rabbit_exchange:name(),
- routing_keys :: [rabbit_router:routing_key()],
- content :: content(),
- id :: msg_id(),
- is_persistent :: boolean()}).
--type(message() :: basic_message()).
--type(delivery() ::
- #delivery{mandatory :: boolean(),
- sender :: pid(),
- message :: message()}).
--type(message_properties() ::
- #message_properties{expiry :: pos_integer() | 'undefined',
- needs_confirming :: boolean()}).
-
--type(info_key() :: atom()).
--type(info_keys() :: [info_key()]).
-
--type(info() :: {info_key(), any()}).
--type(infos() :: [info()]).
-
--type(amqp_error() ::
- #amqp_error{name :: rabbit_framing:amqp_exception(),
- explanation :: string(),
- method :: rabbit_framing:amqp_method_name()}).
-
--type(r(Kind) ::
- r2(vhost(), Kind)).
--type(r2(VirtualHost, Kind) ::
- r3(VirtualHost, Kind, rabbit_misc:resource_name())).
--type(r3(VirtualHost, Kind, Name) ::
- #resource{virtual_host :: VirtualHost,
- kind :: Kind,
- name :: Name}).
-
--type(listener() ::
- #listener{node :: node(),
- protocol :: atom(),
- host :: rabbit_networking:hostname(),
- port :: rabbit_networking:ip_port()}).
-
--type(binding_source() :: rabbit_exchange:name()).
--type(binding_destination() :: rabbit_amqqueue:name() | rabbit_exchange:name()).
-
--type(binding() ::
- #binding{source :: rabbit_exchange:name(),
- destination :: binding_destination(),
- key :: rabbit_binding:key(),
- args :: rabbit_framing:amqp_table()}).
-
--type(amqqueue() ::
- #amqqueue{name :: rabbit_amqqueue:name(),
- durable :: boolean(),
- auto_delete :: boolean(),
- exclusive_owner :: rabbit_types:maybe(pid()),
- arguments :: rabbit_framing:amqp_table(),
- pid :: rabbit_types:maybe(pid()),
- slave_pids :: [pid()]}).
-
--type(exchange() ::
- #exchange{name :: rabbit_exchange:name(),
- type :: rabbit_exchange:type(),
- durable :: boolean(),
- auto_delete :: boolean(),
- arguments :: rabbit_framing:amqp_table()}).
-
--type(connection_name() :: binary()).
-
-%% used e.g. by rabbit_networking
--type(connection() :: pid()).
-
-%% used e.g. by rabbit_connection_tracking
--type(tracked_connection() ::
- #tracked_connection{id :: {node(), connection_name()},
- node :: node(),
- vhost :: vhost(),
- name :: connection_name(),
- pid :: pid(),
- protocol :: protocol_name(),
- peer_host :: rabbit_networking:hostname(),
- peer_port :: rabbit_networking:ip_port(),
- username :: username(),
- connected_at :: integer()}).
-
-%% old AMQP 0-9-1-centric type, avoid when possible
--type(protocol() :: rabbit_framing:protocol()).
-
--type(protocol_name() :: 'amqp0_8' | 'amqp0_9_1' | 'amqp1_0' | 'mqtt' | 'stomp' | any()).
-
--type(auth_user() ::
- #auth_user{username :: username(),
- tags :: [atom()],
- impl :: any()}).
-
--type(user() ::
- #user{username :: username(),
- tags :: [atom()],
- authz_backends :: [{atom(), any()}]}).
-
--type(internal_user() ::
- #internal_user{username :: username(),
- password_hash :: password_hash(),
- tags :: [atom()]}).
-
--type(username() :: binary()).
--type(password() :: binary()).
--type(password_hash() :: binary()).
-
--type(ok(A) :: {'ok', A}).
--type(error(A) :: {'error', A}).
--type(ok_or_error(A) :: 'ok' | error(A)).
--type(ok_or_error2(A, B) :: ok(A) | error(B)).
--type(ok_pid_or_error() :: ok_or_error2(pid(), any())).
-
--type(channel_exit() :: no_return()).
--type(connection_exit() :: no_return()).
-
--type(mfargs() :: {atom(), atom(), [any()]}).
-
--type(proc_name() :: term()).
--type(proc_type_and_name() :: {atom(), proc_name()}).
-
--endif. % use_specs