e263c82e |
#!/bin/bash
# |
d98a5d0a |
# lib/apache
# Functions to control configuration and operation of apache web server
# Dependencies: |
6a5aa7c6 |
#
# - ``functions`` file |
d8864fea |
# - ``STACK_USER`` must be defined
# |
e578effb |
# lib/apache exports the following functions:
# |
6a5aa7c6 |
# - install_apache_wsgi |
a688bc65 |
# - apache_site_config_for |
6a5aa7c6 |
# - enable_apache_site
# - disable_apache_site
# - start_apache_server
# - stop_apache_server
# - restart_apache_server |
d98a5d0a |
# Save trace setting |
523f4880 |
_XTRACE_LIB_APACHE=$(set +o | grep xtrace) |
d98a5d0a |
set +o xtrace
# Allow overriding the default Apache user and group, default to
# current user and his default group. |
e578effb |
APACHE_USER=${APACHE_USER:-$STACK_USER} |
d98a5d0a |
APACHE_GROUP=${APACHE_GROUP:-$(id -gn $APACHE_USER)}
# Set up apache name and configuration directory |
cfb9f057 |
# Note that APACHE_CONF_DIR is really more accurately apache's vhost
# configuration dir but we can't just change this because public interfaces. |
d98a5d0a |
if is_ubuntu; then
APACHE_NAME=apache2 |
444a8d53 |
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/sites-available} |
cfb9f057 |
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf-enabled} |
d98a5d0a |
elif is_fedora; then
APACHE_NAME=httpd |
444a8d53 |
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/conf.d} |
cfb9f057 |
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d} |
d98a5d0a |
elif is_suse; then
APACHE_NAME=apache2 |
444a8d53 |
APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/vhosts.d} |
cfb9f057 |
APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d} |
d98a5d0a |
fi |
66ce5c25 |
APACHE_LOG_DIR="/var/log/${APACHE_NAME}" |
d98a5d0a |
# Functions
# --------- |
4b49e409 |
# 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 |
35649ae0 |
if is_ubuntu; then
# Skip mod_version as it is not a valid mod to enable
# on debuntu, instead it is built in.
if [[ "$mod" != "version" ]] && ! a2query -m $mod ; then
sudo a2enmod $mod
restart_apache_server
fi
elif is_suse; then
if ! a2enmod -q $mod ; then |
4b49e409 |
sudo a2enmod $mod
restart_apache_server
fi
elif is_fedora; then
# pass
true
else
exit_distro_not_supported "apache enable mod"
fi
}
|
604e598e |
# 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
|
2d903568 |
# This varies based on packaged/installed. If we've
# pip_installed, then the pip setup will only build a "python"
# module that will be either python2 or python3 depending on what
# it was built with. |
604e598e |
# |
2d903568 |
# For package installs, the distro ships both plugins and you need
# to select the right one ... it will not be autodetected. |
d7a82f41 |
UWSGI_PYTHON_PLUGIN=python3 |
604e598e |
|
2d903568 |
if is_ubuntu; then |
3480093b |
local pkg_list="uwsgi uwsgi-plugin-python3 libapache2-mod-proxy-uwsgi" |
8956006e |
if [[ "$DISTRO" == 'bionic' ]]; then |
3480093b |
pkg_list="${pkg_list} uwsgi-plugin-python"
fi
install_package ${pkg_list} |
c2c2b6b4 |
elif is_fedora; then |
2d903568 |
# Note httpd comes with mod_proxy_uwsgi and it is loaded by
# default; the mod_proxy_uwsgi package actually conflicts now.
# See:
# https://bugzilla.redhat.com/show_bug.cgi?id=1574335
#
# Thus there is nothing else to do after this install
install_package uwsgi \
uwsgi-plugin-python3 |
10c3ffd2 |
elif [[ $os_VENDOR =~ openSUSE ]]; then
install_package uwsgi \
uwsgi-python3 \
apache2-mod_uwsgi |
2d903568 |
else |
c2c2b6b4 |
# Compile uwsgi from source. |
2d903568 |
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
UWSGI_PYTHON_PLUGIN=python
fi |
604e598e |
|
35649ae0 |
if is_ubuntu || is_suse ; then |
604e598e |
# 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
}
|
d98a5d0a |
# install_apache_wsgi() - Install Apache server and wsgi module |
aee18c74 |
function install_apache_wsgi { |
d98a5d0a |
# Apache installation, because we mark it NOPRIME
if is_ubuntu; then
# Install apache2, which is NOPRIME'd |
afa8a00c |
install_package apache2 |
d7a82f41 |
if is_package_installed libapache2-mod-wsgi; then
uninstall_package libapache2-mod-wsgi |
afa8a00c |
fi |
d7a82f41 |
install_package libapache2-mod-wsgi-py3 |
d98a5d0a |
elif is_fedora; then
sudo rm -f /etc/httpd/conf.d/000-* |
1e265089 |
install_package httpd python3-mod_wsgi |
41e6e123 |
# For consistency with Ubuntu, switch to the worker mpm, as |
9fd38e79 |
# the default is event |
41e6e123 |
sudo sed -i '/mod_mpm_prefork.so/s/^/#/g' /etc/httpd/conf.modules.d/00-mpm.conf |
9fd38e79 |
sudo sed -i '/mod_mpm_event.so/s/^/#/g' /etc/httpd/conf.modules.d/00-mpm.conf |
41e6e123 |
sudo sed -i '/mod_mpm_worker.so/s/^#//g' /etc/httpd/conf.modules.d/00-mpm.conf |
d98a5d0a |
elif is_suse; then
install_package apache2 apache2-mod_wsgi
else |
4b49e409 |
exit_distro_not_supported "apache wsgi installation" |
d98a5d0a |
fi |
4b49e409 |
# WSGI isn't enabled by default, enable it
enable_apache_mod wsgi |
d074dc7f |
}
|
a688bc65 |
# apache_site_config_for() - The filename of the site's configuration file.
# This function uses the global variables APACHE_NAME and APACHE_CONF_DIR.
# |
8f8b274e |
# On Ubuntu 14.04+, the site configuration file must have a .conf suffix for a2ensite and a2dissite to |
a688bc65 |
# recognise it. a2ensite and a2dissite ignore the .conf suffix used as parameter. The default sites'
# files are 000-default.conf and default-ssl.conf.
# |
633a1290 |
# On Fedora and openSUSE, any file in /etc/httpd/conf.d/ whose name ends with .conf is enabled. |
a688bc65 |
#
# 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 |
8f8b274e |
# Ubuntu 14.04 - Apache 2.4
echo $APACHE_CONF_DIR/${site}.conf |
633a1290 |
elif is_fedora || is_suse; then |
a688bc65 |
# fedora conf.d is only imported if it ends with .conf so this is approx the same |
444a8d53 |
local enabled_site_file="$APACHE_CONF_DIR/${site}.conf" |
a688bc65 |
if [ -f $enabled_site_file ]; then
echo ${enabled_site_file}
else
echo ${enabled_site_file}.disabled
fi
fi
}
|
5470701e |
# enable_apache_site() - Enable a particular apache site |
aee18c74 |
function enable_apache_site { |
5470701e |
local site=$@ |
35649ae0 |
# Many of our sites use mod version. Just enable it.
enable_apache_mod version |
5470701e |
if is_ubuntu; then
sudo a2ensite ${site} |
633a1290 |
elif is_fedora || is_suse; then |
444a8d53 |
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 |
5470701e |
fi
}
# disable_apache_site() - Disable a particular apache site |
aee18c74 |
function disable_apache_site { |
5470701e |
local site=$@
if is_ubuntu; then |
2fcdaac5 |
sudo a2dissite ${site} || true |
633a1290 |
elif is_fedora || is_suse; then |
444a8d53 |
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 |
5470701e |
fi
}
|
d98a5d0a |
# start_apache_server() - Start running apache server |
aee18c74 |
function start_apache_server { |
d98a5d0a |
start_service $APACHE_NAME
}
# stop_apache_server() - Stop running apache server |
aee18c74 |
function stop_apache_server { |
d98a5d0a |
if [ -n "$APACHE_NAME" ]; then
stop_service $APACHE_NAME
else
exit_distro_not_supported "apache configuration"
fi
}
# restart_apache_server |
aee18c74 |
function restart_apache_server { |
2df0046f |
# 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. |
2b85cf0f |
restart_service $APACHE_NAME |
d98a5d0a |
}
|
2f8c88e0 |
function write_uwsgi_config {
local file=$1
local wsgi=$2
local url=$3
local http=$4
local name=""
name=$(basename $wsgi) |
aa26baac |
# 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' |
d0db62a4 |
# /var/run will be empty on ubuntu after reboot, so we can use systemd-temptiles
# to automatically create $socket_dir.
sudo mkdir -p /etc/tmpfiles.d/
echo "d $socket_dir 0755 $STACK_USER root" | sudo tee /etc/tmpfiles.d/uwsgi.conf
sudo systemd-tmpfiles --create /etc/tmpfiles.d/uwsgi.conf
|
aa26baac |
local socket="$socket_dir/${name}.socket" |
2f8c88e0 |
# always cleanup given that we are using iniset here
rm -rf $file
iniset "$file" uwsgi wsgi-file "$wsgi"
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 |
ef60f2b7 |
iniset "$file" uwsgi exit-on-reload false |
477a9628 |
# Set worker-reload-mercy so that worker will not exit till the time
# configured after graceful shutdown
iniset "$file" uwsgi worker-reload-mercy $WORKER_TIMEOUT |
2f8c88e0 |
iniset "$file" uwsgi enable-threads true |
2d903568 |
iniset "$file" uwsgi plugins http,${UWSGI_PYTHON_PLUGIN} |
2f8c88e0 |
# uwsgi recommends this to prevent thundering herd on accept.
iniset "$file" uwsgi thunder-lock true |
477a9628 |
# Set hook to trigger graceful shutdown on SIGTERM
iniset "$file" uwsgi hook-master-start "unix_signal:15 gracefully_kill_them_all" |
2f8c88e0 |
# 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
# 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) |
b90bb1a4 |
iniset "$file" uwsgi socket "$socket"
iniset "$file" uwsgi chmod-socket 666 |
1fa65363 |
echo "ProxyPass \"${url}\" \"unix:${socket}|uwsgi://uwsgi-uds-${name}/\" retry=0 " | sudo tee -a $apache_conf |
2f8c88e0 |
enable_apache_site $name |
f6a2d2cd |
restart_apache_server |
2f8c88e0 |
fi
}
|
1fa65363 |
# For services using chunked encoding, the only services known to use this
# currently are Glance and Swift, we need to use an http proxy instead of
# mod_proxy_uwsgi because the chunked encoding gets dropped. See:
# https://github.com/unbit/uwsgi/issues/1540 You can workaround this on python2
# but that involves having apache buffer the request before sending it to |
2f7df51c |
# uwsgi. |
1fa65363 |
function write_local_uwsgi_http_config {
local file=$1
local wsgi=$2
local url=$3
name=$(basename $wsgi)
# create a home for the sockets; note don't use /tmp -- apache has
# a private view of it on some platforms.
# always cleanup given that we are using iniset here
rm -rf $file
iniset "$file" uwsgi wsgi-file "$wsgi"
port=$(get_random_port) |
1560efe9 |
iniset "$file" uwsgi http-socket "127.0.0.1:$port" |
1fa65363 |
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 |
ef60f2b7 |
iniset "$file" uwsgi exit-on-reload false |
1fa65363 |
iniset "$file" uwsgi enable-threads true |
2d903568 |
iniset "$file" uwsgi plugins http,${UWSGI_PYTHON_PLUGIN} |
1fa65363 |
# uwsgi recommends this to prevent thundering herd on accept.
iniset "$file" uwsgi thunder-lock true |
477a9628 |
# Set hook to trigger graceful shutdown on SIGTERM
iniset "$file" uwsgi hook-master-start "unix_signal:15 gracefully_kill_them_all"
# Set worker-reload-mercy so that worker will not exit till the time
# configured after graceful shutdown
iniset "$file" uwsgi worker-reload-mercy $WORKER_TIMEOUT |
1fa65363 |
# 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
iniset "$file" uwsgi http-raw-body true
iniset "$file" uwsgi http-chunked-input true
iniset "$file" uwsgi http-auto-chunked true |
82d0610f |
iniset "$file" uwsgi http-keepalive false |
b79531a9 |
# Increase socket timeout for slow chunked uploads
iniset "$file" uwsgi socket-timeout 30 |
1fa65363 |
enable_apache_mod proxy
enable_apache_mod proxy_http
local apache_conf=""
apache_conf=$(apache_site_config_for $name)
echo "KeepAlive Off" | sudo tee $apache_conf |
a3488d5f |
echo "SetEnv proxy-sendchunked 1" | sudo tee -a $apache_conf |
1fa65363 |
echo "ProxyPass \"${url}\" \"http://127.0.0.1:$port\" retry=0 " | sudo tee -a $apache_conf
enable_apache_site $name
restart_apache_server
}
|
09eea0b2 |
# Write a straight-through proxy for a service that runs locally and just needs
# to be reachable via the main http proxy at $loc
function write_local_proxy_http_config {
local name=$1
local url=$2
local loc=$3
local apache_conf
apache_conf=$(apache_site_config_for $name)
enable_apache_mod proxy
enable_apache_mod proxy_http
echo "KeepAlive Off" | sudo tee $apache_conf
echo "SetEnv proxy-sendchunked 1" | sudo tee -a $apache_conf
echo "ProxyPass \"${loc}\" \"$url\" retry=0 " | sudo tee -a $apache_conf
enable_apache_site $name
restart_apache_server
}
|
2f8c88e0 |
function remove_uwsgi_config {
local file=$1
local wsgi=$2
local name=""
name=$(basename $wsgi)
rm -rf $file
disable_apache_site $name
}
|
d98a5d0a |
# Restore xtrace |
523f4880 |
$_XTRACE_LIB_APACHE |
d98a5d0a |
|
6a5aa7c6 |
# Tell emacs to use shell-script-mode
## Local variables:
## mode: shell-script
## End: |