devstack/lib/rpc_backend
Mehdi Abaakouk 7cf7a8f88f rpc: Allow to configure the rabbitmq heartbeat
For testing we can need to disable or change the rate of the heartbeat
Currently we have to set the value manually in each componments or
to write multiple [[post-config|$<APP>_CONF]] section in local.conf.

This change will allow to configure all componments at once with only two
lines.

Also, we don't set default values to continue to use oslo.messaging
defaults.

Change-Id: Ieaca60ca1cd6d7455b66ce490a9b023df431e9c3
2015-04-09 15:56:44 +02:00

397 lines
14 KiB
Bash

#!/bin/bash
#
# lib/rpc_backend
# Interface for interactig with different RPC backends
# Dependencies:
#
# - ``functions`` file
# - ``RABBIT_{HOST|PASSWORD|USERID}`` must be defined when RabbitMQ is used
# - ``RPC_MESSAGING_PROTOCOL`` option for configuring the messaging protocol
# ``stack.sh`` calls the entry points in this order:
#
# - check_rpc_backend
# - install_rpc_backend
# - restart_rpc_backend
# - iniset_rpc_backend
# Save trace setting
XTRACE=$(set +o | grep xtrace)
set +o xtrace
RPC_MESSAGING_PROTOCOL=${RPC_MESSAGING_PROTOCOL:-0.9}
# TODO(sdague): RPC backend selection is super wonky because we treat
# messaging server as a service, which it really isn't for multi host
QPID_HOST=${QPID_HOST:-}
# Functions
# ---------
# Make sure we only have one rpc backend enabled.
# Also check the specified rpc backend is available on your platform.
function check_rpc_backend {
local c svc
local rpc_needed=1
# We rely on the fact that filenames in lib/* match the service names
# that can be passed as arguments to is_service_enabled.
# We check for a call to iniset_rpc_backend in these files, meaning
# the service needs a backend.
rpc_candidates=$(grep -rl iniset_rpc_backend $TOP_DIR/lib/ | awk -F/ '{print $NF}')
for c in ${rpc_candidates}; do
if is_service_enabled $c; then
rpc_needed=0
break
fi
done
local rpc_backend_cnt=0
for svc in qpid zeromq rabbit; do
is_service_enabled $svc &&
(( rpc_backend_cnt++ )) || true
done
if [ "$rpc_backend_cnt" -gt 1 ]; then
echo "ERROR: only one rpc backend may be enabled,"
echo " set only one of 'rabbit', 'qpid', 'zeromq'"
echo " via ENABLED_SERVICES."
elif [ "$rpc_backend_cnt" == 0 ] && [ "$rpc_needed" == 0 ]; then
echo "ERROR: at least one rpc backend must be enabled,"
echo " set one of 'rabbit', 'qpid', 'zeromq'"
echo " via ENABLED_SERVICES."
fi
if is_service_enabled qpid && ! qpid_is_supported; then
die $LINENO "Qpid support is not available for this version of your distribution."
fi
}
# clean up after rpc backend - eradicate all traces so changing backends
# produces a clean switch
function cleanup_rpc_backend {
if is_service_enabled rabbit; then
# Obliterate rabbitmq-server
uninstall_package rabbitmq-server
# in case it's not actually running, /bin/true at the end
sudo killall epmd || sudo killall -9 epmd || /bin/true
if is_ubuntu; then
# And the Erlang runtime too
apt_get purge -y erlang*
fi
elif is_service_enabled qpid; then
if is_fedora; then
uninstall_package qpid-cpp-server
elif is_ubuntu; then
uninstall_package qpidd
else
exit_distro_not_supported "qpid installation"
fi
elif is_service_enabled zeromq; then
if is_fedora; then
uninstall_package zeromq python-zmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
uninstall_package redis python-redis
fi
elif is_ubuntu; then
uninstall_package libzmq1 python-zmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
uninstall_package redis-server python-redis
fi
elif is_suse; then
uninstall_package libzmq1 python-pyzmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
uninstall_package redis python-redis
fi
else
exit_distro_not_supported "zeromq installation"
fi
fi
# Remove the AMQP 1.0 messaging libraries
if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then
if is_fedora; then
uninstall_package qpid-proton-c-devel
uninstall_package python-qpid-proton
fi
# TODO(kgiusti) ubuntu cleanup
fi
}
# install rpc backend
function install_rpc_backend {
# Regardless of the broker used, if AMQP 1.0 is configured load
# the necessary messaging client libraries for oslo.messaging
if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then
if is_fedora; then
install_package qpid-proton-c-devel
install_package python-qpid-proton
elif is_ubuntu; then
# TODO(kgiusti) The QPID AMQP 1.0 protocol libraries
# are not yet in the ubuntu repos. Enable these installs
# once they are present:
#install_package libqpid-proton2-dev
#install_package python-qpid-proton
# Also add 'uninstall' directives in cleanup_rpc_backend()!
exit_distro_not_supported "QPID AMQP 1.0 Proton libraries"
else
exit_distro_not_supported "QPID AMQP 1.0 Proton libraries"
fi
# Install pyngus client API
# TODO(kgiusti) can remove once python qpid bindings are
# available on all supported platforms _and_ pyngus is added
# to the requirements.txt file in oslo.messaging
pip_install_gr pyngus
fi
if is_service_enabled rabbit; then
# Install rabbitmq-server
install_package rabbitmq-server
elif is_service_enabled qpid; then
if is_fedora; then
install_package qpid-cpp-server
elif is_ubuntu; then
install_package qpidd
else
exit_distro_not_supported "qpid installation"
fi
_configure_qpid
elif is_service_enabled zeromq; then
if is_fedora; then
install_package zeromq python-zmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
install_package redis python-redis
fi
elif is_ubuntu; then
install_package libzmq1 python-zmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
install_package redis-server python-redis
fi
elif is_suse; then
install_package libzmq1 python-pyzmq
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
install_package redis python-redis
fi
else
exit_distro_not_supported "zeromq installation"
fi
# Necessary directory for socket location.
sudo mkdir -p /var/run/openstack
sudo chown $STACK_USER /var/run/openstack
fi
# If using the QPID broker, install the QPID python client API
if is_service_enabled qpid || [ -n "$QPID_HOST" ]; then
install_package python-qpid
fi
}
# restart the rpc backend
function restart_rpc_backend {
if is_service_enabled rabbit; then
# Start rabbitmq-server
echo_summary "Starting RabbitMQ"
# NOTE(bnemec): Retry initial rabbitmq configuration to deal with
# the fact that sometimes it fails to start properly.
# Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1144100
local i
for i in `seq 10`; do
local rc=0
[[ $i -eq "10" ]] && die $LINENO "Failed to set rabbitmq password"
if is_fedora || is_suse; then
# service is not started by default
restart_service rabbitmq-server
fi
rabbit_setuser "$RABBIT_USERID" "$RABBIT_PASSWORD" || rc=$?
if [ $rc -ne 0 ]; then
continue
fi
# change the rabbit password since the default is "guest"
sudo rabbitmqctl change_password \
$RABBIT_USERID $RABBIT_PASSWORD || rc=$?
if [ $rc -ne 0 ]; then
continue;
fi
break
done
if is_service_enabled n-cell; then
# Add partitioned access for the child cell
if [ -z `sudo rabbitmqctl list_vhosts | grep child_cell` ]; then
sudo rabbitmqctl add_vhost child_cell
sudo rabbitmqctl set_permissions -p child_cell $RABBIT_USERID ".*" ".*" ".*"
fi
fi
elif is_service_enabled qpid; then
echo_summary "Starting qpid"
restart_service qpidd
fi
}
# builds transport url string
function get_transport_url {
if is_service_enabled qpid || [ -n "$QPID_HOST" ]; then
echo "qpid://$QPID_USERNAME:$QPID_PASSWORD@$QPID_HOST:5672/"
elif is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then
echo "rabbit://$RABBIT_USERID:$RABBIT_PASSWORD@$RABBIT_HOST:5672/"
fi
}
# iniset cofiguration
function iniset_rpc_backend {
local package=$1
local file=$2
local section=${3:-DEFAULT}
if is_service_enabled zeromq; then
iniset $file $section rpc_backend "zmq"
iniset $file $section rpc_zmq_host `hostname`
if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then
iniset $file $section rpc_zmq_matchmaker "redis"
MATCHMAKER_REDIS_HOST=${MATCHMAKER_REDIS_HOST:-127.0.0.1}
iniset $file matchmaker_redis host $MATCHMAKER_REDIS_HOST
else
die $LINENO "Other matchmaker drivers not supported"
fi
elif is_service_enabled qpid || [ -n "$QPID_HOST" ]; then
# For Qpid use the 'amqp' oslo.messaging transport when AMQP 1.0 is used
if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then
iniset $file $section rpc_backend "amqp"
else
iniset $file $section rpc_backend "qpid"
fi
iniset $file $section qpid_hostname ${QPID_HOST:-$SERVICE_HOST}
if [ -n "$QPID_USERNAME" ]; then
iniset $file $section qpid_username $QPID_USERNAME
iniset $file $section qpid_password $QPID_PASSWORD
fi
elif is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then
iniset $file $section rpc_backend "rabbit"
iniset $file oslo_messaging_rabbit rabbit_hosts $RABBIT_HOST
iniset $file oslo_messaging_rabbit rabbit_password $RABBIT_PASSWORD
iniset $file oslo_messaging_rabbit rabbit_userid $RABBIT_USERID
if [ -n "$RABBIT_HEARTBEAT_TIMEOUT_THRESHOLD" ]; then
iniset $file oslo_messaging_rabbit heartbeat_timeout_threshold $RABBIT_HEARTBEAT_TIMEOUT_THRESHOLD
fi
if [ -n "$RABBIT_HEARTBEAT_RATE" ]; then
iniset $file oslo_messaging_rabbit heartbeat_rate $RABBIT_HEARTBEAT_RATE
fi
fi
}
# Check if qpid can be used on the current distro.
# qpid_is_supported
function qpid_is_supported {
if [[ -z "$DISTRO" ]]; then
GetDistro
fi
# Qpid is not in openSUSE
( ! is_suse )
}
function rabbit_setuser {
local user="$1" pass="$2" found="" out=""
out=$(sudo rabbitmqctl list_users) ||
{ echo "failed to list users" 1>&2; return 1; }
found=$(echo "$out" | awk '$1 == user { print $1 }' "user=$user")
if [ "$found" = "$user" ]; then
sudo rabbitmqctl change_password "$user" "$pass" ||
{ echo "failed changing pass for '$user'" 1>&2; return 1; }
else
sudo rabbitmqctl add_user "$user" "$pass" ||
{ echo "failed changing pass for $user"; return 1; }
fi
sudo rabbitmqctl set_permissions "$user" ".*" ".*" ".*"
}
# Set up the various configuration files used by the qpidd broker
function _configure_qpid {
# the location of the configuration files have changed since qpidd 0.14
local qpid_conf_file
if [ -e /etc/qpid/qpidd.conf ]; then
qpid_conf_file=/etc/qpid/qpidd.conf
elif [ -e /etc/qpidd.conf ]; then
qpid_conf_file=/etc/qpidd.conf
else
exit_distro_not_supported "qpidd.conf file not found!"
fi
# force the ACL file to a known location
local qpid_acl_file=/etc/qpid/qpidd.acl
if [ ! -e $qpid_acl_file ]; then
sudo mkdir -p -m 755 `dirname $qpid_acl_file`
sudo touch $qpid_acl_file
sudo chmod o+r $qpid_acl_file
fi
sudo sed -i.bak '/^acl-file=/d' $qpid_conf_file
echo "acl-file=$qpid_acl_file" | sudo tee --append $qpid_conf_file
sudo sed -i '/^auth=/d' $qpid_conf_file
if [ -z "$QPID_USERNAME" ]; then
# no QPID user configured, so disable authentication
# and access control
echo "auth=no" | sudo tee --append $qpid_conf_file
cat <<EOF | sudo tee $qpid_acl_file
acl allow all all
EOF
else
# Configure qpidd to use PLAIN authentication, and add
# QPID_USERNAME to the ACL:
echo "auth=yes" | sudo tee --append $qpid_conf_file
if [ -z "$QPID_PASSWORD" ]; then
read_password QPID_PASSWORD "ENTER A PASSWORD FOR QPID USER $QPID_USERNAME"
fi
# Create ACL to allow $QPID_USERNAME full access
cat <<EOF | sudo tee $qpid_acl_file
group admin ${QPID_USERNAME}@QPID
acl allow admin all
acl deny all all
EOF
# Add user to SASL database
if is_ubuntu; then
install_package sasl2-bin
elif is_fedora; then
install_package cyrus-sasl-lib
install_package cyrus-sasl-plain
fi
local sasl_conf_file=/etc/sasl2/qpidd.conf
sudo sed -i.bak '/PLAIN/!s/mech_list: /mech_list: PLAIN /' $sasl_conf_file
local sasl_db=`sudo grep sasldb_path $sasl_conf_file | cut -f 2 -d ":" | tr -d [:blank:]`
if [ ! -e $sasl_db ]; then
sudo mkdir -p -m 755 `dirname $sasl_db`
fi
echo $QPID_PASSWORD | sudo saslpasswd2 -c -p -f $sasl_db -u QPID $QPID_USERNAME
sudo chmod o+r $sasl_db
fi
# If AMQP 1.0 is specified, ensure that the version of the
# broker can support AMQP 1.0 and configure the queue and
# topic address patterns used by oslo.messaging.
if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then
QPIDD=$(type -p qpidd)
if ! $QPIDD --help | grep -q "queue-patterns"; then
exit_distro_not_supported "qpidd with AMQP 1.0 support"
fi
if ! grep -q "queue-patterns=exclusive" $qpid_conf_file; then
cat <<EOF | sudo tee --append $qpid_conf_file
queue-patterns=exclusive
queue-patterns=unicast
topic-patterns=broadcast
EOF
fi
fi
}
# Restore xtrace
$XTRACE
# Tell emacs to use shell-script-mode
## Local variables:
## mode: shell-script
## End: