Auto-detect haproxy user_group
As a followup to Id99948aec64656a0532afc68e146f0610bff1378, adding auto detection to haproxy_amphora.user_group haproxy is capable[1] handling a list of configuration files. This patch leverages that capability by simply providing haproxy with an additional configuration file, which is baked in the amphora image via a diskimage-builder element. The above-mentioned element will specify the following values for user group: Ubuntu: 'nogroup' RHEL/CentOS/Fedora: 'haproxy' The amphora-agent will parse and remove any user_group configuration provided by Octavia controller worker. This is in order to maintain amphora-agent backward compatibility to old Octavia workers, who still provide user_group to the amphora-agent. Octavia Workers that include this patch will no longer provide user_group configuration to the amphora-agent. [1] https://cbonte.github.io/haproxy-dconv/1.7/management.html#3 Related-Bug #1548070 Change-Id: Ia8fede9d7da4709a48661d1fc595a16d04fcbfa9
This commit is contained in:
parent
4fd2647e21
commit
26a55415ab
|
@ -14,5 +14,5 @@ ln -s /bin/amphora-agent /usr/local/bin/amphora-agent || true
|
||||||
mkdir /etc/octavia
|
mkdir /etc/octavia
|
||||||
# we assume certs, etc will come in through the config drive
|
# we assume certs, etc will come in through the config drive
|
||||||
mkdir /etc/octavia/certs
|
mkdir /etc/octavia/certs
|
||||||
mkdir /var/lib/octavia
|
mkdir -p /var/lib/octavia
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
case $DISTRO_NAME in
|
||||||
|
ubuntu | debian )
|
||||||
|
HAPROXY_USER_GROUP=nogroup
|
||||||
|
;;
|
||||||
|
fedora | centos* | rhel* )
|
||||||
|
HAPROXY_USER_GROUP=haproxy
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
HAPROXY_USER_GROUP=nogroup
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat >> /var/lib/octavia/haproxy-default-user-group.conf <<EOF
|
||||||
|
global
|
||||||
|
group $HAPROXY_USER_GROUP
|
||||||
|
EOF
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
case $DISTRO_NAME in
|
||||||
|
ubuntu | debian )
|
||||||
|
HAPROXY_USER_GROUP=nogroup
|
||||||
|
;;
|
||||||
|
fedora | centos* | rhel* )
|
||||||
|
HAPROXY_USER_GROUP=haproxy
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
HAPROXY_USER_GROUP=nogroup
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat >> /var/lib/octavia/haproxy-default-user-group.conf <<EOF
|
||||||
|
global
|
||||||
|
group $HAPROXY_USER_GROUP
|
||||||
|
EOF
|
|
@ -119,7 +119,9 @@
|
||||||
# build_rate_limit = -1
|
# build_rate_limit = -1
|
||||||
# build_active_retries = 300
|
# build_active_retries = 300
|
||||||
# build_retry_interval = 5
|
# build_retry_interval = 5
|
||||||
# user_group = nogroup
|
|
||||||
|
# This setting is deprecated. It is now automatically discovered.
|
||||||
|
# user_group =
|
||||||
|
|
||||||
# Maximum number of entries that can fit in the stick table.
|
# Maximum number of entries that can fit in the stick table.
|
||||||
# The size supports "k", "m", "g" suffixes.
|
# The size supports "k", "m", "g" suffixes.
|
||||||
|
|
|
@ -49,6 +49,8 @@ class AgentJinjaTemplater(object):
|
||||||
'base_path': CONF.haproxy_amphora.base_path,
|
'base_path': CONF.haproxy_amphora.base_path,
|
||||||
'bind_host': CONF.haproxy_amphora.bind_host,
|
'bind_host': CONF.haproxy_amphora.bind_host,
|
||||||
'bind_port': CONF.haproxy_amphora.bind_port,
|
'bind_port': CONF.haproxy_amphora.bind_port,
|
||||||
|
# TODO(nmagnezi): user_group is Deprecated in Pike,
|
||||||
|
# should be Removed in R cycle.
|
||||||
'user_group': CONF.haproxy_amphora.user_group,
|
'user_group': CONF.haproxy_amphora.user_group,
|
||||||
'controller_list': CONF.health_manager.controller_ip_port_list,
|
'controller_list': CONF.health_manager.controller_ip_port_list,
|
||||||
'debug': CONF.debug,
|
'debug': CONF.debug,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -23,6 +24,7 @@ import subprocess
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import jinja2
|
import jinja2
|
||||||
|
from oslo_config import cfg
|
||||||
import six
|
import six
|
||||||
from werkzeug import exceptions
|
from werkzeug import exceptions
|
||||||
|
|
||||||
|
@ -36,6 +38,8 @@ from octavia.i18n import _LE
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
BUFFER = 100
|
BUFFER = 100
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
UPSTART_CONF = 'upstart.conf.j2'
|
UPSTART_CONF = 'upstart.conf.j2'
|
||||||
SYSVINIT_CONF = 'sysvinit.conf.j2'
|
SYSVINIT_CONF = 'sysvinit.conf.j2'
|
||||||
SYSTEMD_CONF = 'systemd.conf.j2'
|
SYSTEMD_CONF = 'systemd.conf.j2'
|
||||||
|
@ -107,15 +111,27 @@ class Listener(object):
|
||||||
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||||
# mode 00600
|
# mode 00600
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
with os.fdopen(os.open(name, flags, mode), 'wb') as file:
|
|
||||||
b = stream.read(BUFFER)
|
b = stream.read(BUFFER)
|
||||||
while (b):
|
s_io = io.StringIO()
|
||||||
file.write(b)
|
while b:
|
||||||
|
# Write haproxy configuration to StringIO
|
||||||
|
s_io.write(b.decode('utf8'))
|
||||||
b = stream.read(BUFFER)
|
b = stream.read(BUFFER)
|
||||||
|
|
||||||
|
# Since haproxy user_group is now auto-detected by the amphora agent,
|
||||||
|
# remove it from haproxy configuration in case it was provided
|
||||||
|
# by an older Octavia controller. This is needed in order to prevent
|
||||||
|
# a duplicate entry for 'group' in haproxy configuration, which will
|
||||||
|
# result an error when haproxy starts.
|
||||||
|
new_config = re.sub(r"\s+group\s.+", "", s_io.getvalue())
|
||||||
|
|
||||||
|
with os.fdopen(os.open(name, flags, mode), 'w') as file:
|
||||||
|
file.write(new_config)
|
||||||
|
|
||||||
# use haproxy to check the config
|
# use haproxy to check the config
|
||||||
cmd = "haproxy -c -L {peer} -f {config_file}".format(config_file=name,
|
cmd = "haproxy -c -L {peer} -f {config_file} -f {haproxy_ug}".format(
|
||||||
peer=peer_name)
|
config_file=name, peer=peer_name,
|
||||||
|
haproxy_ug=consts.HAPROXY_USER_GROUP_CFG)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||||
|
@ -172,6 +188,7 @@ class Listener(object):
|
||||||
haproxy_pid=util.pid_path(listener_id),
|
haproxy_pid=util.pid_path(listener_id),
|
||||||
haproxy_cmd=util.CONF.haproxy_amphora.haproxy_cmd,
|
haproxy_cmd=util.CONF.haproxy_amphora.haproxy_cmd,
|
||||||
haproxy_cfg=util.config_path(listener_id),
|
haproxy_cfg=util.config_path(listener_id),
|
||||||
|
haproxy_user_group_cfg=consts.HAPROXY_USER_GROUP_CFG,
|
||||||
respawn_count=util.CONF.haproxy_amphora.respawn_count,
|
respawn_count=util.CONF.haproxy_amphora.respawn_count,
|
||||||
respawn_interval=(util.CONF.haproxy_amphora.
|
respawn_interval=(util.CONF.haproxy_amphora.
|
||||||
respawn_interval),
|
respawn_interval),
|
||||||
|
|
|
@ -7,7 +7,7 @@ Wants=syslog.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
EnvironmentFile=-/etc/default/haproxy
|
EnvironmentFile=-/etc/default/haproxy
|
||||||
ExecStartPre=/usr/sbin/haproxy -f {{ haproxy_cfg }} -c -q
|
ExecStartPre=/usr/sbin/haproxy -f {{ haproxy_cfg }} -f {{ haproxy_user_group_cfg }} -c -q
|
||||||
# Re-add the namespace
|
# Re-add the namespace
|
||||||
ExecStartPre=-/sbin/ip netns add {{ amphora_nsname }}
|
ExecStartPre=-/sbin/ip netns add {{ amphora_nsname }}
|
||||||
# Load the system sysctl into the new namespace
|
# Load the system sysctl into the new namespace
|
||||||
|
@ -23,8 +23,8 @@ ExecStartPre=-/sbin/ip netns exec {{ amphora_nsname }} ifup -a
|
||||||
ExecStartPre=-/bin/awk '{system("/sbin/ip netns exec amphora-haproxy ifup " $2)}' /var/lib/octavia/plugged_interfaces
|
ExecStartPre=-/bin/awk '{system("/sbin/ip netns exec amphora-haproxy ifup " $2)}' /var/lib/octavia/plugged_interfaces
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
#
|
#
|
||||||
ExecStart=/sbin/ip netns exec {{ amphora_nsname }} /usr/sbin/haproxy-systemd-wrapper -f {{ haproxy_cfg }} -p {{ haproxy_pid }} -L {{ peer_name }} $EXTRAOPTS
|
ExecStart=/sbin/ip netns exec {{ amphora_nsname }} /usr/sbin/haproxy-systemd-wrapper -f {{ haproxy_cfg }} -f {{ haproxy_user_group_cfg }} -p {{ haproxy_pid }} -L {{ peer_name }} $EXTRAOPTS
|
||||||
ExecReload=/usr/sbin/haproxy -c -f {{ haproxy_cfg }}
|
ExecReload=/usr/sbin/haproxy -c -f {{ haproxy_cfg }} -f {{ haproxy_user_group_cfg }}
|
||||||
ExecReload=/bin/kill -USR2 $MAINPID
|
ExecReload=/bin/kill -USR2 $MAINPID
|
||||||
KillMode=mixed
|
KillMode=mixed
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
|
@ -31,11 +31,13 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||||
PIDFILE={{ haproxy_pid }}
|
PIDFILE={{ haproxy_pid }}
|
||||||
CONFIG={{ haproxy_cfg }}
|
CONFIG={{ haproxy_cfg }}
|
||||||
HAPROXY={{ haproxy_cmd }}
|
HAPROXY={{ haproxy_cmd }}
|
||||||
|
USER_GROUP_CONF_PATH={{ haproxy_user_group_cfg }}
|
||||||
|
|
||||||
EXTRAOPTS=
|
EXTRAOPTS=
|
||||||
ENABLED=1
|
ENABLED=1
|
||||||
|
|
||||||
test -x $HAPROXY || exit 0
|
test -x $HAPROXY || exit 0
|
||||||
test -f "$CONFIG" || exit 0
|
test -f "$CONFIG" -f "$USER_GROUP_CONF_PATH" || exit 0
|
||||||
|
|
||||||
if [ -e /etc/default/haproxy ]; then
|
if [ -e /etc/default/haproxy ]; then
|
||||||
. /etc/default/haproxy
|
. /etc/default/haproxy
|
||||||
|
@ -66,7 +68,7 @@ haproxy_start()
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
start-stop-daemon --start --pidfile "$PIDFILE" \
|
start-stop-daemon --start --pidfile "$PIDFILE" \
|
||||||
--exec $HAPROXY -- -f "$CONFIG" -D -p "$PIDFILE" \
|
--exec $HAPROXY -- -f "$CONFIG" -f "$USER_GROUP_CONF_PATH" -D -p "$PIDFILE" \
|
||||||
$EXTRAOPTS || return 2
|
$EXTRAOPTS || return 2
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -86,7 +88,7 @@ haproxy_stop()
|
||||||
|
|
||||||
haproxy_reload()
|
haproxy_reload()
|
||||||
{
|
{
|
||||||
$HAPROXY -f "$CONFIG" -p $PIDFILE -D $EXTRAOPTS -sf $(cat $PIDFILE) \
|
$HAPROXY -f "$CONFIG" -f "$USER_GROUP_CONF_PATH" -p $PIDFILE -D $EXTRAOPTS -sf $(cat $PIDFILE) \
|
||||||
|| return 2
|
|| return 2
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -95,7 +97,7 @@ haproxy_checkconf()
|
||||||
{
|
{
|
||||||
rcode=0
|
rcode=0
|
||||||
|
|
||||||
$HAPROXY -c -f "$CONFIG"
|
$HAPROXY -c -f "$CONFIG" -f "$USER_GROUP_CONF_PATH"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
rcode=1
|
rcode=1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -24,6 +24,7 @@ stop on runlevel [!2345]
|
||||||
env PID_PATH={{ haproxy_pid }}
|
env PID_PATH={{ haproxy_pid }}
|
||||||
env BIN_PATH={{ haproxy_cmd }}
|
env BIN_PATH={{ haproxy_cmd }}
|
||||||
env CONF_PATH={{ haproxy_cfg }}
|
env CONF_PATH={{ haproxy_cfg }}
|
||||||
|
env USER_GROUP_CONF_PATH={{ haproxy_user_group_cfg }}
|
||||||
env PEER_NAME={{ peer_name }}
|
env PEER_NAME={{ peer_name }}
|
||||||
|
|
||||||
respawn
|
respawn
|
||||||
|
@ -53,9 +54,10 @@ script
|
||||||
exec /bin/bash <<EOF
|
exec /bin/bash <<EOF
|
||||||
echo \$(date) Starting HAProxy
|
echo \$(date) Starting HAProxy
|
||||||
# The -L trick fixes the HAProxy limitation to have long peer names
|
# The -L trick fixes the HAProxy limitation to have long peer names
|
||||||
ip netns exec {{ amphora_nsname }} $BIN_PATH -f $CONF_PATH -L $PEER_NAME -D -p $PID_PATH
|
|
||||||
|
|
||||||
trap "ip netns exec {{ amphora_nsname }} $BIN_PATH -f $CONF_PATH -L $PEER_NAME -p $PID_PATH -sf \\\$(cat $PID_PATH)" SIGHUP
|
ip netns exec {{ amphora_nsname }} $BIN_PATH -f $CONF_PATH -f $USER_GROUP_CONF_PATH -L $PEER_NAME -D -p $PID_PATH
|
||||||
|
|
||||||
|
trap "ip netns exec {{ amphora_nsname }} $BIN_PATH -f $CONF_PATH -f $USER_GROUP_CONF_PATH -L $PEER_NAME -p $PID_PATH -sf \\\$(cat $PID_PATH)" SIGHUP
|
||||||
trap "kill -TERM \\\$(cat $PID_PATH) && rm $PID_PATH;echo \\\$(date) Exiting HAProxy; exit 0" SIGTERM SIGINT
|
trap "kill -TERM \\\$(cat $PID_PATH) && rm $PID_PATH;echo \\\$(date) Exiting HAProxy; exit 0" SIGTERM SIGINT
|
||||||
|
|
||||||
while true; do # Iterate to keep job running.
|
while true; do # Iterate to keep job running.
|
||||||
|
|
|
@ -172,8 +172,9 @@ haproxy_amphora_opts = [
|
||||||
default=5,
|
default=5,
|
||||||
help=_('Retry timeout between build attempts in '
|
help=_('Retry timeout between build attempts in '
|
||||||
'seconds.')),
|
'seconds.')),
|
||||||
cfg.StrOpt('user_group',
|
cfg.StrOpt('user_group', deprecated_for_removal=True,
|
||||||
default='nogroup',
|
deprecated_reason='This is now automatically discovered '
|
||||||
|
' and configured.',
|
||||||
help=_('The user group for haproxy to run under inside the '
|
help=_('The user group for haproxy to run under inside the '
|
||||||
'amphora.')),
|
'amphora.')),
|
||||||
cfg.StrOpt('haproxy_stick_size', default='10k',
|
cfg.StrOpt('haproxy_stick_size', default='10k',
|
||||||
|
|
|
@ -339,6 +339,7 @@ KEEPALIVED_JINJA2_SYSVINIT = 'keepalived.sysvinit.j2'
|
||||||
CHECK_SCRIPT_CONF = 'keepalived_check_script.conf.j2'
|
CHECK_SCRIPT_CONF = 'keepalived_check_script.conf.j2'
|
||||||
|
|
||||||
PLUGGED_INTERFACES = '/var/lib/octavia/plugged_interfaces'
|
PLUGGED_INTERFACES = '/var/lib/octavia/plugged_interfaces'
|
||||||
|
HAPROXY_USER_GROUP_CFG = '/var/lib/octavia/haproxy-default-user-group.conf'
|
||||||
AMPHORA_NAMESPACE = 'amphora-haproxy'
|
AMPHORA_NAMESPACE = 'amphora-haproxy'
|
||||||
|
|
||||||
# List of HTTP headers which are supported for insertion
|
# List of HTTP headers which are supported for insertion
|
||||||
|
|
|
@ -112,13 +112,13 @@ class TestServerTestCase(base.TestCase):
|
||||||
data='test')
|
data='test')
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
mock_open.assert_called_with(file_name, flags, mode)
|
mock_open.assert_called_with(file_name, flags, mode)
|
||||||
mock_fdopen.assert_called_with(123, 'wb')
|
mock_fdopen.assert_called_with(123, 'w')
|
||||||
self.assertEqual(202, rv.status_code)
|
self.assertEqual(202, rv.status_code)
|
||||||
handle = m()
|
m().write.assert_called_once_with('test')
|
||||||
handle.write.assert_called_once_with(six.b('test'))
|
|
||||||
mock_subprocess.assert_any_call(
|
mock_subprocess.assert_any_call(
|
||||||
"haproxy -c -L {peer} -f {config_file}".format(
|
"haproxy -c -L {peer} -f {config_file} -f {haproxy_ug}".format(
|
||||||
config_file=file_name,
|
config_file=file_name,
|
||||||
|
haproxy_ug=consts.HAPROXY_USER_GROUP_CFG,
|
||||||
peer=(octavia_utils.
|
peer=(octavia_utils.
|
||||||
base64_sha1_string('amp_123').rstrip('='))).split(),
|
base64_sha1_string('amp_123').rstrip('='))).split(),
|
||||||
stderr=-2)
|
stderr=-2)
|
||||||
|
@ -187,7 +187,7 @@ class TestServerTestCase(base.TestCase):
|
||||||
mock_open.assert_called_with(init_path, flags, mode)
|
mock_open.assert_called_with(init_path, flags, mode)
|
||||||
mock_fdopen.assert_called_with(123, 'w')
|
mock_fdopen.assert_called_with(123, 'w')
|
||||||
handle = mock_fdopen()
|
handle = mock_fdopen()
|
||||||
handle.write.assert_any_call(six.b('test'))
|
handle.write.assert_any_call('test')
|
||||||
# skip the template stuff
|
# skip the template stuff
|
||||||
mock_makedirs.assert_called_with('/var/lib/octavia/123')
|
mock_makedirs.assert_called_with('/var/lib/octavia/123')
|
||||||
|
|
||||||
|
@ -212,12 +212,13 @@ class TestServerTestCase(base.TestCase):
|
||||||
json.loads(rv.data.decode('utf-8')))
|
json.loads(rv.data.decode('utf-8')))
|
||||||
mode = stat.S_IRUSR | stat.S_IWUSR
|
mode = stat.S_IRUSR | stat.S_IWUSR
|
||||||
mock_open.assert_called_with(file_name, flags, mode)
|
mock_open.assert_called_with(file_name, flags, mode)
|
||||||
mock_fdopen.assert_called_with(123, 'wb')
|
mock_fdopen.assert_called_with(123, 'w')
|
||||||
handle = mock_fdopen()
|
handle = mock_fdopen()
|
||||||
handle.write.assert_called_with(six.b('test'))
|
handle.write.assert_called_with('test')
|
||||||
mock_subprocess.assert_called_with(
|
mock_subprocess.assert_called_with(
|
||||||
"haproxy -c -L {peer} -f {config_file}".format(
|
"haproxy -c -L {peer} -f {config_file} -f {haproxy_ug}".format(
|
||||||
config_file=file_name,
|
config_file=file_name,
|
||||||
|
haproxy_ug=consts.HAPROXY_USER_GROUP_CFG,
|
||||||
peer=(octavia_utils.
|
peer=(octavia_utils.
|
||||||
base64_sha1_string('amp_123').rstrip('='))).split(),
|
base64_sha1_string('amp_123').rstrip('='))).split(),
|
||||||
stderr=-2)
|
stderr=-2)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- The amphora haproxy user_group setting is now automatically detected for
|
||||||
|
Ubuntu, CentOS, Fedora, or RHEL based amphora.
|
||||||
|
deprecations:
|
||||||
|
- haproxy user_group is no longer being used. it is now auto-detected for
|
||||||
|
Ubuntu, CentOS, Fedora and RHEL based amphora images.
|
Loading…
Reference in New Issue