#!/bin/bash # # lib/rpc_backend # Interface for interactig with different rpc backend # rpc backend settings # 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 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 # NOTE(ewindisch): Redis is not strictly necessary # but there is a matchmaker driver that works # really well & out of the box for multi-node. 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 } # iniset cofiguration function iniset_rpc_backend { local package=$1 local file=$2 local section=$3 if is_service_enabled zeromq; then iniset $file $section rpc_backend "zmq" iniset $file $section rpc_zmq_matchmaker \ oslo_messaging._drivers.matchmaker_redis.MatchMakerRedis # Set MATCHMAKER_REDIS_HOST if running multi-node. MATCHMAKER_REDIS_HOST=${MATCHMAKER_REDIS_HOST:-127.0.0.1} iniset $file matchmaker_redis host $MATCHMAKER_REDIS_HOST 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 $section rabbit_hosts $RABBIT_HOST iniset $file $section rabbit_password $RABBIT_PASSWORD iniset $file $section rabbit_userid $RABBIT_USERID 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 <