Adds support for systemd amphora images
This patch enables auto-detection of the init system used in the amphora image and adds support for systemd amphora. This patch allows Ubuntu xenial amphora images to work. It also merges two functional test files into one file to reduce code duplication. This is a scenario gate fix. Change-Id: I5fec1680bd47719ae9f2fcb6abaaba8a78e2ae8b Closes-Bug: #1640866
This commit is contained in:
parent
5e76bab500
commit
c4408c4c78
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=OpenStack Octavia Amphora Agent
|
||||
After=network.target syslog.service
|
||||
Wants=syslog.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/amphora-agent --config-file /etc/octavia/amphora-agent.conf
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then
|
||||
set -x
|
||||
fi
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
if [[ -f /bin/systemctl ]]; then
|
||||
/bin/systemctl enable amphora-agent
|
||||
fi
|
|
@ -1,3 +1,4 @@
|
|||
os-svc-install
|
||||
package-installs
|
||||
pkg-map
|
||||
sysctl
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"haproxy/trusty-backports": null
|
||||
"haproxy": null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"release": {
|
||||
"ubuntu": {
|
||||
"trusty": {
|
||||
"haproxy": "haproxy/trusty-backports"
|
||||
}
|
||||
}
|
||||
},
|
||||
"distro": {
|
||||
"ubuntu": {
|
||||
"haproxy": "haproxy"
|
||||
}
|
||||
},
|
||||
"family": {
|
||||
"debian": {
|
||||
"haproxy": "haproxy"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"haproxy": "haproxy"
|
||||
}
|
||||
}
|
|
@ -3,4 +3,6 @@
|
|||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
update-rc.d -f haproxy remove
|
||||
# Doing both here as just remove doesn't seem to work on xenial
|
||||
update-rc.d haproxy disable || true
|
||||
update-rc.d -f haproxy remove || true
|
||||
|
|
|
@ -4,4 +4,6 @@
|
|||
set -eu
|
||||
set -o xtrace
|
||||
|
||||
echo deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse > /etc/apt/sources.list.d/backports.list
|
||||
if [ "$DISTRO_NAME" == "ubuntu" ] && [ "$DIB_RELEASE" == "trusty" ]; then
|
||||
echo deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse > /etc/apt/sources.list.d/backports.list
|
||||
fi
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
os-svc-install
|
||||
package-installs
|
||||
pkg-map
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"keepalived/trusty-backports": null
|
||||
"keepalived": null
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"release": {
|
||||
"ubuntu": {
|
||||
"trusty": {
|
||||
"keepalived": "keepalived/trusty-backports"
|
||||
}
|
||||
}
|
||||
},
|
||||
"distro": {
|
||||
"ubuntu": {
|
||||
"keepalived": "keepalived"
|
||||
}
|
||||
},
|
||||
"family": {
|
||||
"debian": {
|
||||
"keepalived": "keepalived"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"keepalived": "keepalived"
|
||||
}
|
||||
|
||||
}
|
|
@ -4,4 +4,6 @@
|
|||
set -eu
|
||||
set -o xtrace
|
||||
|
||||
echo deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse > /etc/apt/sources.list.d/backports.list
|
||||
if [ "$DISTRO_NAME" == "ubuntu" ] && [ "$DIB_RELEASE" == "trusty" ]; then
|
||||
echo deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse > /etc/apt/sources.list.d/backports.list
|
||||
fi
|
||||
|
|
|
@ -124,7 +124,10 @@
|
|||
# respawn_interval = 2
|
||||
# client_cert = /etc/octavia/certs/client.pem
|
||||
# server_ca = /etc/octavia/certs/server_ca.pem
|
||||
#
|
||||
# This setting is deprecated. It is now automatically discovered.
|
||||
# use_upstart = True
|
||||
#
|
||||
# rest_request_conn_timeout = 10
|
||||
# rest_request_read_timeout = 60
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
j2_env = jinja2.Environment(autoescape=True, loader=jinja2.FileSystemLoader(
|
||||
os.path.dirname(os.path.realpath(__file__)) + consts.AGENT_API_TEMPLATES))
|
||||
template = j2_env.get_template(consts.KEEPALIVED_CONF)
|
||||
UPSTART_TEMPLATE = j2_env.get_template(consts.KEEPALIVED_JINJA2_UPSTART)
|
||||
SYSVINIT_TEMPLATE = j2_env.get_template(consts.KEEPALIVED_JINJA2_SYSVINIT)
|
||||
SYSTEMD_TEMPLATE = j2_env.get_template(consts.KEEPALIVED_JINJA2_SYSTEMD)
|
||||
check_script_template = j2_env.get_template(consts.CHECK_SCRIPT_CONF)
|
||||
|
||||
|
||||
|
@ -54,10 +56,28 @@ class Keepalived(object):
|
|||
f.write(b)
|
||||
b = stream.read(BUFFER)
|
||||
|
||||
file_path = util.keepalived_init_path()
|
||||
# mode 00755
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
init_system = util.get_os_init_system()
|
||||
|
||||
file_path = util.keepalived_init_path(init_system)
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
template = SYSTEMD_TEMPLATE
|
||||
init_enable_cmd = "systemctl enable octavia-keepalived"
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
template = UPSTART_TEMPLATE
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
template = SYSVINIT_TEMPLATE
|
||||
init_enable_cmd = "insserv {file}".format(file=file_path)
|
||||
else:
|
||||
raise util.UnknownInitError()
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
# mode 00644
|
||||
mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
||||
else:
|
||||
# mode 00755
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
if not os.path.exists(file_path):
|
||||
with os.fdopen(os.open(file_path, flags, mode), 'w') as text_file:
|
||||
text = template.render(
|
||||
|
@ -71,6 +91,9 @@ class Keepalived(object):
|
|||
|
||||
# Renders the Keepalived check script
|
||||
keepalived_path = util.keepalived_check_script_path()
|
||||
# mode 00755
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
open_obj = os.open(keepalived_path, flags, mode)
|
||||
with os.fdopen(open_obj, 'w') as text_file:
|
||||
text = check_script_template.render(
|
||||
|
@ -78,6 +101,18 @@ class Keepalived(object):
|
|||
)
|
||||
text_file.write(text)
|
||||
|
||||
# Make sure the new service is enabled on boot
|
||||
if init_system != consts.INIT_UPSTART:
|
||||
try:
|
||||
subprocess.check_output(init_enable_cmd.split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.debug("Failed to enable octavia-keepalived service: "
|
||||
"%(err)s", {'err': e})
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Error enabling octavia-keepalived service",
|
||||
details=e.output)), 500)
|
||||
|
||||
res = flask.make_response(flask.jsonify({
|
||||
'message': 'OK'}), 200)
|
||||
res.headers['ETag'] = stream.get_md5()
|
||||
|
|
|
@ -30,12 +30,14 @@ from octavia.amphorae.backends.agent.api_server import util
|
|||
from octavia.amphorae.backends.utils import haproxy_query as query
|
||||
from octavia.common import constants as consts
|
||||
from octavia.common import utils as octavia_utils
|
||||
from octavia.i18n import _LE
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
BUFFER = 100
|
||||
|
||||
UPSTART_CONF = 'upstart.conf.j2'
|
||||
SYSVINIT_CONF = 'sysvinit.conf.j2'
|
||||
SYSTEMD_CONF = 'systemd.conf.j2'
|
||||
|
||||
JINJA_ENV = jinja2.Environment(
|
||||
autoescape=True,
|
||||
|
@ -44,6 +46,7 @@ JINJA_ENV = jinja2.Environment(
|
|||
) + consts.AGENT_API_TEMPLATES))
|
||||
UPSTART_TEMPLATE = JINJA_ENV.get_template(UPSTART_CONF)
|
||||
SYSVINIT_TEMPLATE = JINJA_ENV.get_template(SYSVINIT_CONF)
|
||||
SYSTEMD_TEMPLATE = JINJA_ENV.get_template(SYSTEMD_CONF)
|
||||
|
||||
|
||||
class ParsingError(Exception):
|
||||
|
@ -113,7 +116,7 @@ class Listener(object):
|
|||
try:
|
||||
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.debug("Failed to verify haproxy file: %s", e)
|
||||
LOG.error(_LE("Failed to verify haproxy file: %s"), e)
|
||||
os.remove(name) # delete file
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Invalid request",
|
||||
|
@ -122,15 +125,44 @@ class Listener(object):
|
|||
# file ok - move it
|
||||
os.rename(name, util.config_path(listener_id))
|
||||
|
||||
use_upstart = util.CONF.haproxy_amphora.use_upstart
|
||||
file = util.init_path(listener_id)
|
||||
# mode 00755
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
if not os.path.exists(file):
|
||||
with os.fdopen(os.open(file, flags, mode), 'w') as text_file:
|
||||
template = (UPSTART_TEMPLATE if use_upstart
|
||||
else SYSVINIT_TEMPLATE)
|
||||
try:
|
||||
|
||||
init_system = util.get_os_init_system()
|
||||
|
||||
LOG.debug('Found init system: {0}'.format(init_system))
|
||||
|
||||
init_path = util.init_path(listener_id, init_system)
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
template = SYSTEMD_TEMPLATE
|
||||
init_enable_cmd = "systemctl enable haproxy-{list}".format(
|
||||
list=listener_id)
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
template = UPSTART_TEMPLATE
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
template = SYSVINIT_TEMPLATE
|
||||
init_enable_cmd = "insserv {file}".format(file=init_path)
|
||||
else:
|
||||
raise util.UnknownInitError()
|
||||
|
||||
except util.UnknownInitError:
|
||||
LOG.error(_LE("Unknown init system found."))
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Unknown init system in amphora",
|
||||
details="The amphora image is running an unknown init "
|
||||
"system. We can't create the init configuration "
|
||||
"file for the load balancing process.")), 500)
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
# mode 00644
|
||||
mode = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
|
||||
else:
|
||||
# mode 00755
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
if not os.path.exists(init_path):
|
||||
with os.fdopen(os.open(init_path, flags, mode), 'w') as text_file:
|
||||
|
||||
text = template.render(
|
||||
peer_name=peer_name,
|
||||
haproxy_pid=util.pid_path(listener_id),
|
||||
|
@ -143,18 +175,18 @@ class Listener(object):
|
|||
)
|
||||
text_file.write(text)
|
||||
|
||||
if not use_upstart:
|
||||
insrvcmd = ("insserv {file}".format(file=file))
|
||||
|
||||
# Make sure the new service is enabled on boot
|
||||
if init_system != consts.INIT_UPSTART:
|
||||
try:
|
||||
subprocess.check_output(insrvcmd.split(),
|
||||
subprocess.check_output(init_enable_cmd.split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.debug("Failed to make %(file)s executable: %(err)s",
|
||||
{'file': file, 'err': e})
|
||||
LOG.error(_LE("Failed to enable haproxy-%(list)s "
|
||||
"service: %(err)s"),
|
||||
{'list': listener_id, 'err': e})
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Error making file {0} executable".format(file),
|
||||
details=e.output)), 500)
|
||||
message="Error enabling haproxy-{0} service".format(
|
||||
listener_id), details=e.output)), 500)
|
||||
|
||||
res = flask.make_response(flask.jsonify({
|
||||
'message': 'OK'}), 202)
|
||||
|
@ -221,7 +253,7 @@ class Listener(object):
|
|||
try:
|
||||
subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.debug("Failed to stop HAProxy service: %s", e)
|
||||
LOG.error(_LE("Failed to stop HAProxy service: %s"), e)
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Error stopping haproxy",
|
||||
details=e.output)), 500)
|
||||
|
@ -239,10 +271,34 @@ class Listener(object):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
# disable the service
|
||||
init_system = util.get_os_init_system()
|
||||
init_path = util.init_path(listener_id, init_system)
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
init_disable_cmd = "systemctl disable haproxy-{list}".format(
|
||||
list=listener_id)
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
init_disable_cmd = "insserv -r {file}".format(file=init_path)
|
||||
elif init_system != consts.INIT_UPSTART:
|
||||
raise util.UnknownInitError()
|
||||
|
||||
if init_system != consts.INIT_UPSTART:
|
||||
try:
|
||||
subprocess.check_output(init_disable_cmd.split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
LOG.error(_LE("Failed to disable haproxy-%(list)s "
|
||||
"service: %(err)s"),
|
||||
{'list': listener_id, 'err': e})
|
||||
return flask.make_response(flask.jsonify(dict(
|
||||
message="Error disabling haproxy-{0} service".format(
|
||||
listener_id), details=e.output)), 500)
|
||||
|
||||
# delete the directory + init script for that listener
|
||||
shutil.rmtree(util.haproxy_dir(listener_id))
|
||||
if os.path.exists(util.init_path(listener_id)):
|
||||
os.remove(util.init_path(listener_id))
|
||||
if os.path.exists(init_path):
|
||||
os.remove(init_path)
|
||||
|
||||
return flask.jsonify({'message': 'OK'})
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
{#
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
#}
|
||||
#!/bin/sh
|
||||
|
||||
RETVAL=0
|
||||
|
||||
prog="octavia-keepalived"
|
||||
|
||||
start() {
|
||||
echo -n $"Starting $prog"
|
||||
ip netns exec {{ amphora_nsname }} {{ keepalived_cmd }} -D -d -f {{ keepalived_cfg }}
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && touch {{ keepalived_pid }}
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo -n $"Stopping $prog"
|
||||
kill -9 `pidof keepalived`
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f {{ keepalived_pid }}
|
||||
}
|
||||
|
||||
status() {
|
||||
kill -0 `pidof keepalived`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && echo -n $"$prog is running"
|
||||
[ $RETVAL -eq 1 ] && echo -n $"$prog is not found"
|
||||
echo
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|reload|status}"
|
||||
RETVAL=1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Keepalive Daemon (LVS and VRRP)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
KillMode=process
|
||||
ExecStart=/sbin/ip netns exec {{ amphora_nsname }} {{ keepalived_cmd }} -D -d -f {{ keepalived_cfg }}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,83 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# keepalived LVS cluster monitor daemon.
|
||||
#
|
||||
# Written by Andres Salomon <dilinger@voxel.net>
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: keepalived
|
||||
# Required-Start: $syslog $network $remote_fs
|
||||
# Required-Stop: $syslog $network $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Starts keepalived
|
||||
# Description: Starts keepalived lvs loadbalancer
|
||||
### END INIT INFO
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON="ip netns exec {{ amphora_nsname }} {{ keepalived_cmd }}"
|
||||
NAME=octavia-keepalived
|
||||
DESC=octavia-keepalived
|
||||
TMPFILES="/tmp/.vrrp /tmp/.healthcheckers"
|
||||
DAEMON_ARGS="-D -d -f {{ keepalived_cfg }}"
|
||||
|
||||
#includes lsb functions
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
test -f $DAEMON || exit 0
|
||||
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC" "$NAME"
|
||||
for file in $TMPFILES
|
||||
do
|
||||
test -e $file && test ! -L $file && rm $file
|
||||
done
|
||||
if start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
|
||||
--exec $DAEMON -- $DAEMON_ARGS; then
|
||||
log_end_msg 0
|
||||
else
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
if start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.pid \
|
||||
--exec $DAEMON; then
|
||||
log_end_msg 0
|
||||
else
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
reload|force-reload)
|
||||
log_action_begin_msg "Reloading $DESC configuration..."
|
||||
if start-stop-daemon --stop --quiet --signal 1 --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON; then
|
||||
log_end_msg 0
|
||||
else
|
||||
log_action_end_msg 1
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
log_action_begin_msg "Restarting $DESC" "$NAME"
|
||||
|
||||
start-stop-daemon --stop --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON || true
|
||||
sleep 1
|
||||
if start-stop-daemon --start --quiet --pidfile \
|
||||
/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_ARGS; then
|
||||
log_end_msg 0
|
||||
else
|
||||
log_end_msg 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/$NAME {start|stop|restart|reload|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,25 @@
|
|||
{#
|
||||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
# Copyright 2016 Rackspace
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
#}
|
||||
description "Octavia keepalived"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
exec /sbin/ip netns exec {{ amphora_nsname }} {{ keepalived_cmd }} -n -D -d -f {{ keepalived_cfg }}
|
|
@ -0,0 +1,29 @@
|
|||
[Unit]
|
||||
Description=HAProxy Load Balancer
|
||||
Documentation=man:haproxy(1)
|
||||
Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz
|
||||
After=network.target syslog.service
|
||||
Wants=syslog.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=-/etc/default/haproxy
|
||||
ExecStartPre=/usr/sbin/haproxy -f {{ haproxy_cfg }} -c -q
|
||||
# Re-add the namespace
|
||||
ExecStartPre=-/sbin/ip netns add {{ amphora_nsname }}
|
||||
# Load the system sysctl into the new namespace
|
||||
ExecStartPre=-/sbin/ip netns exec {{ amphora_nsname }} sysctl --system
|
||||
# We need the plugged_interfaces file sorted to join the host interfaces
|
||||
ExecStartPre=-/bin/sh -c '/usr/bin/sort -k 1 /var/lib/octavia/plugged_interfaces > /var/lib/octavia/plugged_interfaces.sorted'
|
||||
# Assign the interfaces into the namespace with the appropriate name
|
||||
ExecStartPre=-/bin/sh -c '/sbin/ip link | awk \'{getline n; print $0,n}\' | awk \'{sub(":","",$2)} {print $17 " " $2}\' | sort -k 1 | join -j 1 - /var/lib/octavia/plugged_interfaces.sorted | awk \'{system("ip link set "$2" netns {{ amphora_nsname }} name "$3"")}\''
|
||||
# Bring up all of the namespace interfaces
|
||||
ExecStartPre=-/sbin/ip netns exec {{ amphora_nsname }} ifup -a
|
||||
#
|
||||
ExecStart=/sbin/ip netns exec {{ amphora_nsname }} /usr/sbin/haproxy-systemd-wrapper -f {{ haproxy_cfg }} -p {{ haproxy_pid }} -L {{ peer_name }} $EXTRAOPTS
|
||||
ExecReload=/usr/sbin/haproxy -c -f {{ haproxy_cfg }}
|
||||
ExecReload=/bin/kill -USR2 $MAINPID
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -14,23 +14,33 @@
|
|||
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from octavia.common import constants as consts
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_group('amphora_agent', 'octavia.common.config')
|
||||
CONF.import_group('haproxy_amphora', 'octavia.common.config')
|
||||
|
||||
UPSTART_DIR = '/etc/init'
|
||||
KEEPALIVED_INIT_DIR = '/etc/init.d'
|
||||
SYSVINIT_DIR = '/etc/init.d'
|
||||
|
||||
class UnknownInitError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def init_path(listener_id):
|
||||
use_upstart = CONF.haproxy_amphora.use_upstart
|
||||
hconf = 'haproxy-{0}.conf' if use_upstart else 'haproxy-{0}'
|
||||
idir = UPSTART_DIR if use_upstart else SYSVINIT_DIR
|
||||
return os.path.join(idir, hconf.format(listener_id))
|
||||
def init_path(listener_id, init_system):
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
return os.path.join(consts.SYSTEMD_DIR,
|
||||
'haproxy-{0}.service'.format(listener_id))
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
return os.path.join(consts.UPSTART_DIR,
|
||||
'haproxy-{0}.conf'.format(listener_id))
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
return os.path.join(consts.SYSVINIT_DIR,
|
||||
'haproxy-{0}'.format(listener_id))
|
||||
else:
|
||||
raise UnknownInitError()
|
||||
|
||||
|
||||
def haproxy_dir(listener_id):
|
||||
|
@ -63,8 +73,15 @@ def keepalived_dir():
|
|||
return os.path.join(CONF.haproxy_amphora.base_path, 'vrrp')
|
||||
|
||||
|
||||
def keepalived_init_path():
|
||||
return os.path.join(KEEPALIVED_INIT_DIR, 'octavia-keepalived')
|
||||
def keepalived_init_path(init_system):
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
return os.path.join(consts.SYSTEMD_DIR, consts.KEEPALIVED_SYSTEMD)
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
return os.path.join(consts.UPSTART_DIR, consts.KEEPALIVED_UPSTART)
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
return os.path.join(consts.SYSVINIT_DIR, consts.KEEPALIVED_SYSVINIT)
|
||||
else:
|
||||
raise UnknownInitError()
|
||||
|
||||
|
||||
def keepalived_pid_path():
|
||||
|
@ -115,3 +132,21 @@ def get_network_interface_file(interface):
|
|||
return CONF.amphora_agent.agent_server_network_file
|
||||
return os.path.join(CONF.amphora_agent.agent_server_network_dir,
|
||||
interface + '.cfg')
|
||||
|
||||
|
||||
def get_os_init_system():
|
||||
if os.path.exists(consts.INIT_PROC_COMM_PATH):
|
||||
with open(consts.INIT_PROC_COMM_PATH, 'r') as init_comm:
|
||||
init_proc_name = init_comm.read().rstrip('\n')
|
||||
if init_proc_name == consts.INIT_SYSTEMD:
|
||||
return consts.INIT_SYSTEMD
|
||||
if init_proc_name == 'init':
|
||||
init_path = consts.INIT_PATH
|
||||
if os.path.exists(init_path):
|
||||
args = [init_path, '--version']
|
||||
init_version = subprocess.check_output(args, shell=False)
|
||||
if consts.INIT_UPSTART in init_version:
|
||||
return consts.INIT_UPSTART
|
||||
else:
|
||||
return consts.INIT_SYSVINIT
|
||||
return consts.INIT_UNKOWN
|
||||
|
|
|
@ -191,6 +191,9 @@ haproxy_amphora_opts = [
|
|||
cfg.StrOpt('server_ca', default='/etc/octavia/certs/server_ca.pem',
|
||||
help=_("The ca which signed the server certificates")),
|
||||
cfg.BoolOpt('use_upstart', default=True,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason='This is now automatically discovered '
|
||||
' and configured.',
|
||||
help=_("If False, use sysvinit.")),
|
||||
]
|
||||
|
||||
|
|
|
@ -310,7 +310,9 @@ HAPROXY_MEMBER_STATUSES = (UP, DOWN, NO_CHECK)
|
|||
API_VERSION = '0.5'
|
||||
|
||||
HAPROXY_BASE_PEER_PORT = 1025
|
||||
KEEPALIVED_CONF = 'keepalived.conf.j2'
|
||||
KEEPALIVED_JINJA2_UPSTART = 'keepalived.upstart.j2'
|
||||
KEEPALIVED_JINJA2_SYSTEMD = 'keepalived.systemd.j2'
|
||||
KEEPALIVED_JINJA2_SYSVINIT = 'keepalived.sysvinit.j2'
|
||||
CHECK_SCRIPT_CONF = 'keepalived_check_script.conf.j2'
|
||||
|
||||
PLUGGED_INTERFACES = '/var/lib/octavia/plugged_interfaces'
|
||||
|
@ -336,3 +338,20 @@ AMP_ACTION_START = 'start'
|
|||
AMP_ACTION_STOP = 'stop'
|
||||
AMP_ACTION_RELOAD = 'reload'
|
||||
GLANCE_IMAGE_ACTIVE = 'active'
|
||||
|
||||
INIT_SYSTEMD = 'systemd'
|
||||
INIT_UPSTART = 'upstart'
|
||||
INIT_SYSVINIT = 'sysvinit'
|
||||
INIT_UNKOWN = 'unknown'
|
||||
VALID_INIT_SYSTEMS = (INIT_SYSTEMD, INIT_SYSVINIT, INIT_UPSTART)
|
||||
INIT_PATH = '/sbin/init'
|
||||
|
||||
SYSTEMD_DIR = '/usr/lib/systemd/system'
|
||||
SYSVINIT_DIR = '/etc/init.d'
|
||||
UPSTART_DIR = '/etc/init'
|
||||
|
||||
INIT_PROC_COMM_PATH = '/proc/1/comm'
|
||||
|
||||
KEEPALIVED_SYSTEMD = 'octavia-keepalived.service'
|
||||
KEEPALIVED_SYSVINIT = 'octavia-keepalived'
|
||||
KEEPALIVED_UPSTART = 'octavia-keepalived.conf'
|
||||
|
|
|
@ -51,13 +51,48 @@ class TestServerTestCase(base.TestCase):
|
|||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
conf.config(group="haproxy_amphora", base_path='/var/lib/octavia')
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_haproxy(self, mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists):
|
||||
def test_haproxy_systemd(self, mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system):
|
||||
self._test_haproxy(mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system,
|
||||
consts.INIT_SYSTEMD)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSVINIT)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_haproxy_sysvinit(self, mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system):
|
||||
self._test_haproxy(mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system,
|
||||
consts.INIT_SYSVINIT)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_UPSTART)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_haproxy_upstart(self, mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system):
|
||||
self._test_haproxy(mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system,
|
||||
consts.INIT_UPSTART)
|
||||
|
||||
def _test_haproxy(self, mock_remove, mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists, mock_init_system,
|
||||
init_system):
|
||||
|
||||
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||
mock_exists.return_value = True
|
||||
|
@ -77,7 +112,7 @@ class TestServerTestCase(base.TestCase):
|
|||
self.assertEqual(202, rv.status_code)
|
||||
handle = m()
|
||||
handle.write.assert_called_once_with(six.b('test'))
|
||||
mock_subprocess.assert_called_once_with(
|
||||
mock_subprocess.assert_any_call(
|
||||
"haproxy -c -L {peer} -f {config_file}".format(
|
||||
config_file=file_name,
|
||||
peer=(octavia_utils.
|
||||
|
@ -87,6 +122,17 @@ class TestServerTestCase(base.TestCase):
|
|||
'/var/lib/octavia/123/haproxy.cfg.new',
|
||||
'/var/lib/octavia/123/haproxy.cfg')
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
mock_subprocess.assert_any_call(
|
||||
"systemctl enable haproxy-123".split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
mock_subprocess.assert_any_call(
|
||||
"insserv /etc/init.d/haproxy-123".split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
else:
|
||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||
|
||||
# exception writing
|
||||
m = self.useFixture(test_utils.OpenFixture(file_name)).mock_open
|
||||
m.side_effect = IOError() # open crashes
|
||||
|
@ -98,7 +144,15 @@ class TestServerTestCase(base.TestCase):
|
|||
|
||||
# check if files get created
|
||||
mock_exists.return_value = False
|
||||
init_path = '/etc/init/haproxy-123.conf'
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
init_path = consts.SYSTEMD_DIR + '/haproxy-123.service'
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
init_path = consts.UPSTART_DIR + '/haproxy-123.conf'
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
init_path = consts.SYSVINIT_DIR + '/haproxy-123'
|
||||
else:
|
||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||
|
||||
m = self.useFixture(test_utils.OpenFixture(init_path)).mock_open
|
||||
# happy case upstart file exists
|
||||
with mock.patch('os.open') as mock_open, mock.patch.object(
|
||||
|
@ -109,8 +163,12 @@ class TestServerTestCase(base.TestCase):
|
|||
data='test')
|
||||
|
||||
self.assertEqual(202, rv.status_code)
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
mode = (stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP |
|
||||
stat.S_IROTH)
|
||||
else:
|
||||
mode = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
||||
stat.S_IROTH | stat.S_IXOTH)
|
||||
mock_open.assert_called_with(init_path, flags, mode)
|
||||
mock_fdopen.assert_called_with(123, 'w')
|
||||
handle = mock_fdopen()
|
||||
|
@ -145,6 +203,16 @@ class TestServerTestCase(base.TestCase):
|
|||
stderr=-2)
|
||||
mock_remove.assert_called_once_with(file_name)
|
||||
|
||||
# unhappy path with bogus init system
|
||||
mock_init_system.return_value = 'bogus'
|
||||
with mock.patch('os.open') as mock_open, mock.patch.object(
|
||||
os, 'fdopen', m) as mock_fdopen:
|
||||
mock_open.return_value = 123
|
||||
rv = self.app.put('/' + api_server.VERSION +
|
||||
'/listeners/amp_123/123/haproxy',
|
||||
data='test')
|
||||
self.assertEqual(500, rv.status_code)
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.listener.Listener.'
|
||||
'vrrp_check_script_update')
|
||||
|
@ -247,14 +315,53 @@ class TestServerTestCase(base.TestCase):
|
|||
hostname='test-host'),
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.' +
|
||||
'get_haproxy_pid')
|
||||
@mock.patch('shutil.rmtree')
|
||||
@mock.patch('os.remove')
|
||||
def test_delete_listener(self, mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists):
|
||||
def test_delete_listener_systemd(self, mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_delete_listener(mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
consts.INIT_SYSTEMD)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSVINIT)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.' +
|
||||
'get_haproxy_pid')
|
||||
@mock.patch('shutil.rmtree')
|
||||
@mock.patch('os.remove')
|
||||
def test_delete_listener_sysvinit(self, mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_delete_listener(mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
consts.INIT_SYSVINIT)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_UPSTART)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.' +
|
||||
'get_haproxy_pid')
|
||||
@mock.patch('shutil.rmtree')
|
||||
@mock.patch('os.remove')
|
||||
def test_delete_listener_upstart(self, mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_delete_listener(mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists,
|
||||
consts.INIT_UPSTART)
|
||||
|
||||
def _test_delete_listener(self, mock_remove, mock_rmtree, mock_pid,
|
||||
mock_check_output, mock_exists, init_system):
|
||||
mock_exists.return_value = False
|
||||
rv = self.app.delete('/' + api_server.VERSION + '/listeners/123')
|
||||
self.assertEqual(404, rv.status_code)
|
||||
|
@ -271,7 +378,19 @@ class TestServerTestCase(base.TestCase):
|
|||
self.assertEqual({u'message': u'OK'},
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
mock_rmtree.assert_called_with('/var/lib/octavia/123')
|
||||
mock_exists.assert_called_with('/etc/init/haproxy-123.conf')
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
mock_exists.assert_called_with(consts.SYSTEMD_DIR +
|
||||
'/haproxy-123.service')
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
mock_exists.assert_called_with(consts.UPSTART_DIR +
|
||||
'/haproxy-123.conf')
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
mock_exists.assert_called_with(consts.SYSVINIT_DIR +
|
||||
'/haproxy-123')
|
||||
else:
|
||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||
|
||||
mock_exists.assert_any_call('/var/lib/octavia/123/123.pid')
|
||||
|
||||
# service is stopped + upstart script
|
||||
|
@ -280,7 +399,18 @@ class TestServerTestCase(base.TestCase):
|
|||
self.assertEqual(200, rv.status_code)
|
||||
self.assertEqual({u'message': u'OK'},
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
mock_remove.assert_called_once_with('/etc/init/haproxy-123.conf')
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
mock_remove.assert_called_with(consts.SYSTEMD_DIR +
|
||||
'/haproxy-123.service')
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
mock_remove.assert_called_with(consts.UPSTART_DIR +
|
||||
'/haproxy-123.conf')
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
mock_remove.assert_called_with(consts.SYSVINIT_DIR +
|
||||
'/haproxy-123')
|
||||
else:
|
||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||
|
||||
# service is running + upstart script
|
||||
mock_exists.side_effect = [True, True, True, True]
|
||||
|
@ -290,9 +420,23 @@ class TestServerTestCase(base.TestCase):
|
|||
self.assertEqual({u'message': u'OK'},
|
||||
json.loads(rv.data.decode('utf-8')))
|
||||
mock_pid.assert_called_once_with('123')
|
||||
mock_check_output.assert_called_once_with(
|
||||
mock_check_output.assert_any_call(
|
||||
['/usr/sbin/service', 'haproxy-123', 'stop'], stderr=-2)
|
||||
|
||||
if init_system == consts.INIT_SYSTEMD:
|
||||
mock_check_output.assert_any_call(
|
||||
"systemctl disable haproxy-123".split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
elif init_system == consts.INIT_UPSTART:
|
||||
mock_remove.assert_any_call(consts.UPSTART_DIR +
|
||||
'/haproxy-123.conf')
|
||||
elif init_system == consts.INIT_SYSVINIT:
|
||||
mock_check_output.assert_any_call(
|
||||
"insserv -r /etc/init.d/haproxy-123".split(),
|
||||
stderr=subprocess.STDOUT)
|
||||
else:
|
||||
self.assertIn(init_system, consts.VALID_INIT_SYSTEMS)
|
||||
|
||||
# service is running + stopping fails
|
||||
mock_exists.side_effect = [True, True, True]
|
||||
mock_check_output.side_effect = subprocess.CalledProcessError(
|
||||
|
@ -1239,12 +1383,58 @@ class TestServerTestCase(base.TestCase):
|
|||
content_type='application/json')
|
||||
self.assertEqual(400, rv.status_code)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSTEMD)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_upload_keepalived_config(self, mock_remove,
|
||||
mock_rename, mock_makedirs, mock_exists):
|
||||
def test_upload_keepalived_config_systemd(self, mock_remove,
|
||||
mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_upload_keepalived_config(mock_remove, mock_subprocess,
|
||||
mock_rename, mock_makedirs,
|
||||
mock_exists, mock_init_system,
|
||||
consts.INIT_SYSTEMD)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_UPSTART)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_upload_keepalived_config_upstart(self, mock_remove,
|
||||
mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_upload_keepalived_config(mock_remove, mock_subprocess,
|
||||
mock_rename, mock_makedirs,
|
||||
mock_exists, mock_init_system,
|
||||
consts.INIT_UPSTART)
|
||||
|
||||
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
||||
'get_os_init_system', return_value=consts.INIT_SYSVINIT)
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('os.rename')
|
||||
@mock.patch('subprocess.check_output')
|
||||
@mock.patch('os.remove')
|
||||
def test_upload_keepalived_config_sysvinit(self, mock_remove,
|
||||
mock_subprocess, mock_rename,
|
||||
mock_makedirs, mock_exists,
|
||||
mock_init_system):
|
||||
self._test_upload_keepalived_config(mock_remove, mock_subprocess,
|
||||
mock_rename, mock_makedirs,
|
||||
mock_exists, mock_init_system,
|
||||
consts.INIT_SYSVINIT)
|
||||
|
||||
def _test_upload_keepalived_config(self, mock_remove, mock_subprocess,
|
||||
mock_rename, mock_makedirs,
|
||||
mock_exists, mock_init_system,
|
||||
init_system):
|
||||
|
||||
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
features:
|
||||
- Adds support for amphora images that use systemd.
|
||||
- Add support for Ubuntu Xenial amphora images.
|
||||
deprecations:
|
||||
- The "use_upstart" configuration option is now deprecated
|
||||
because the amphora agent can now automatically discover
|
||||
the init system in use in the amphora image.
|
Loading…
Reference in New Issue