devstack/lib/apache
Ian Wienand f6a2d2cd4e Always restart apache
As described in [1], it seems that mod_wsgi is not "graceful" reload
safe.  Upon re-init, it can end up in a segfault loop.

The "reload" (not *restart*) after setting up uwsgi was added with
I1d89be1f1b36f26eaf543b99bde6fdc5701474fe but not causing an issue
until uwsgi was enabled.

We do not notice in the gate, because the TLS setup ends up doing a
restart after this setup.  In the period between the
write_uwsgi_config and that restart, Apache is sitting in a segfault
loop, but we never noticed because we don't try talking to it.  Other
jobs that don't do any further apache configuration have started
failing, however.

Looking at the original comments around "reload_apache_server" I'm not
sure if it is still necessary.  [2] shows it is not used outside these
two calls.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1445540
[2] http://codesearch.openstack.org/?q=reload_apache_server&i=nope&files=&repos=

Closes-Bug: #1686210
Change-Id: I5234bae0595efdcd30305a32bf9c121072a3625e
2017-04-26 11:09:59 +10:00

286 lines
9.4 KiB
Bash

#!/bin/bash
#
# lib/apache
# Functions to control configuration and operation of apache web server
# Dependencies:
#
# - ``functions`` file
# - ``STACK_USER`` must be defined
#
# lib/apache exports the following functions:
#
# - install_apache_wsgi
# - apache_site_config_for
# - enable_apache_site
# - disable_apache_site
# - start_apache_server
# - stop_apache_server
# - restart_apache_server
# Save trace setting
_XTRACE_LIB_APACHE=$(set +o | grep xtrace)
set +o xtrace
# Allow overriding the default Apache user and group, default to
# current user and his default group.
APACHE_USER=${APACHE_USER:-$STACK_USER}
APACHE_GROUP=${APACHE_GROUP:-$(id -gn $APACHE_USER)}
# Set up apache name and configuration directory
# Note that APACHE_CONF_DIR is really more accurately apache's vhost
# configuration dir but we can't just change this because public interfaces.
if is_ubuntu; then
APACHE_NAME=apache2
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/sites-available}
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf-enabled}
elif is_fedora; then
APACHE_NAME=httpd
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/conf.d}
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d}
elif is_suse; then
APACHE_NAME=apache2
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/vhosts.d}
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d}
fi
APACHE_LOG_DIR="/var/log/${APACHE_NAME}"
# Functions
# ---------
# Enable apache mod and restart apache if it isn't already enabled.
function enable_apache_mod {
local mod=$1
# Apache installation, because we mark it NOPRIME
if is_ubuntu || is_suse ; then
if ! a2query -m $mod ; then
sudo a2enmod $mod
restart_apache_server
fi
elif is_fedora; then
# pass
true
else
exit_distro_not_supported "apache enable mod"
fi
}
# NOTE(sdague): Install uwsgi including apache module, we need to get
# to 2.0.6+ to get a working mod_proxy_uwsgi. We can probably build a
# check for that and do it differently for different platforms.
function install_apache_uwsgi {
local apxs="apxs2"
if is_fedora; then
apxs="apxs"
fi
# Ubuntu xenial is back level on uwsgi so the proxy doesn't
# actually work. Hence we have to build from source for now.
#
# Centos 7 actually has the module in epel, but there was a big
# push to disable epel by default. As such, compile from source
# there as well.
local dir
dir=$(mktemp -d)
pushd $dir
pip_install uwsgi
pip download uwsgi -c $REQUIREMENTS_DIR/upper-constraints.txt
local uwsgi
uwsgi=$(ls uwsgi*)
tar xvf $uwsgi
cd uwsgi*/apache2
sudo $apxs -i -c mod_proxy_uwsgi.c
popd
# delete the temp directory
sudo rm -rf $dir
if is_ubuntu; then
# we've got to enable proxy and proxy_uwsgi for this to work
sudo a2enmod proxy
sudo a2enmod proxy_uwsgi
elif is_fedora; then
# redhat is missing a nice way to turn on/off modules
echo "LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so" \
| sudo tee /etc/httpd/conf.modules.d/02-proxy-uwsgi.conf
fi
restart_apache_server
}
# install_apache_wsgi() - Install Apache server and wsgi module
function install_apache_wsgi {
# Apache installation, because we mark it NOPRIME
if is_ubuntu; then
# Install apache2, which is NOPRIME'd
install_package apache2
if python3_enabled; then
if is_package_installed libapache2-mod-wsgi; then
uninstall_package libapache2-mod-wsgi
fi
install_package libapache2-mod-wsgi-py3
else
install_package libapache2-mod-wsgi
fi
elif is_fedora; then
sudo rm -f /etc/httpd/conf.d/000-*
install_package httpd mod_wsgi
elif is_suse; then
install_package apache2 apache2-mod_wsgi
else
exit_distro_not_supported "apache wsgi installation"
fi
# WSGI isn't enabled by default, enable it
enable_apache_mod wsgi
}
# apache_site_config_for() - The filename of the site's configuration file.
# This function uses the global variables APACHE_NAME and APACHE_CONF_DIR.
#
# On Ubuntu 14.04+, the site configuration file must have a .conf suffix for a2ensite and a2dissite to
# recognise it. a2ensite and a2dissite ignore the .conf suffix used as parameter. The default sites'
# files are 000-default.conf and default-ssl.conf.
#
# On Fedora and openSUSE, any file in /etc/httpd/conf.d/ whose name ends with .conf is enabled.
#
# On RHEL and CentOS, things should hopefully work as in Fedora.
#
# The table below summarizes what should happen on each distribution:
# +----------------------+--------------------+--------------------------+--------------------------+
# | Distribution | File name | Site enabling command | Site disabling command |
# +----------------------+--------------------+--------------------------+--------------------------+
# | Ubuntu 14.04 | site.conf | a2ensite site | a2dissite site |
# | Fedora, RHEL, CentOS | site.conf.disabled | mv site.conf{.disabled,} | mv site.conf{,.disabled} |
# +----------------------+--------------------+--------------------------+--------------------------+
function apache_site_config_for {
local site=$@
if is_ubuntu; then
# Ubuntu 14.04 - Apache 2.4
echo $APACHE_CONF_DIR/${site}.conf
elif is_fedora || is_suse; then
# fedora conf.d is only imported if it ends with .conf so this is approx the same
local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
if [ -f $enabled_site_file ]; then
echo ${enabled_site_file}
else
echo ${enabled_site_file}.disabled
fi
fi
}
# enable_apache_site() - Enable a particular apache site
function enable_apache_site {
local site=$@
if is_ubuntu; then
sudo a2ensite ${site}
elif is_fedora || is_suse; then
local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
# Do nothing if site already enabled or no site config exists
if [[ -f ${enabled_site_file}.disabled ]] && [[ ! -f ${enabled_site_file} ]]; then
sudo mv ${enabled_site_file}.disabled ${enabled_site_file}
fi
fi
}
# disable_apache_site() - Disable a particular apache site
function disable_apache_site {
local site=$@
if is_ubuntu; then
sudo a2dissite ${site} || true
elif is_fedora || is_suse; then
local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
# Do nothing if no site config exists
if [[ -f ${enabled_site_file} ]]; then
sudo mv ${enabled_site_file} ${enabled_site_file}.disabled
fi
fi
}
# start_apache_server() - Start running apache server
function start_apache_server {
start_service $APACHE_NAME
}
# stop_apache_server() - Stop running apache server
function stop_apache_server {
if [ -n "$APACHE_NAME" ]; then
stop_service $APACHE_NAME
else
exit_distro_not_supported "apache configuration"
fi
}
# restart_apache_server
function restart_apache_server {
# Apache can be slow to stop, doing an explicit stop, sleep, start helps
# to mitigate issues where apache will claim a port it's listening on is
# still in use and fail to start.
restart_service $APACHE_NAME
}
function write_uwsgi_config {
local file=$1
local wsgi=$2
local url=$3
local http=$4
local name=""
name=$(basename $wsgi)
# create a home for the sockets; note don't use /tmp -- apache has
# a private view of it on some platforms.
local socket_dir='/var/run/uwsgi'
sudo install -d -o $STACK_USER -m 755 $socket_dir
local socket="$socket_dir/${name}.socket"
# always cleanup given that we are using iniset here
rm -rf $file
iniset "$file" uwsgi wsgi-file "$wsgi"
iniset "$file" uwsgi socket "$socket"
iniset "$file" uwsgi processes $API_WORKERS
# This is running standalone
iniset "$file" uwsgi master true
# Set die-on-term & exit-on-reload so that uwsgi shuts down
iniset "$file" uwsgi die-on-term true
iniset "$file" uwsgi exit-on-reload true
iniset "$file" uwsgi enable-threads true
iniset "$file" uwsgi plugins python
# uwsgi recommends this to prevent thundering herd on accept.
iniset "$file" uwsgi thunder-lock true
# Override the default size for headers from the 4k default.
iniset "$file" uwsgi buffer-size 65535
# Make sure the client doesn't try to re-use the connection.
iniset "$file" uwsgi add-header "Connection: close"
# This ensures that file descriptors aren't shared between processes.
iniset "$file" uwsgi lazy-apps true
iniset "$file" uwsgi chmod-socket 666
# If we said bind directly to http, then do that and don't start the apache proxy
if [[ -n "$http" ]]; then
iniset "$file" uwsgi http $http
else
local apache_conf=""
apache_conf=$(apache_site_config_for $name)
echo "ProxyPass \"${url}\" \"unix:${socket}|uwsgi://uwsgi-uds-${name}/\" retry=0 " | sudo tee $apache_conf
enable_apache_site $name
restart_apache_server
fi
}
function remove_uwsgi_config {
local file=$1
local wsgi=$2
local name=""
name=$(basename $wsgi)
rm -rf $file
disable_apache_site $name
}
# Restore xtrace
$_XTRACE_LIB_APACHE
# Tell emacs to use shell-script-mode
## Local variables:
## mode: shell-script
## End: