Merge "Add sanity_check for keepalived ipv6 support"

This commit is contained in:
Jenkins 2015-07-18 00:53:11 +00:00 committed by Gerrit Code Review
commit d1f768e064
3 changed files with 144 additions and 0 deletions

View File

@ -14,16 +14,24 @@
# under the License. # under the License.
import re import re
import shutil
import tempfile
import netaddr import netaddr
from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import uuidutils from oslo_utils import uuidutils
import six import six
from neutron.agent.common import ovs_lib from neutron.agent.common import ovs_lib
from neutron.agent.l3 import ha_router
from neutron.agent.l3 import namespaces
from neutron.agent.linux import external_process
from neutron.agent.linux import ip_lib from neutron.agent.linux import ip_lib
from neutron.agent.linux import ip_link_support from neutron.agent.linux import ip_link_support
from neutron.agent.linux import keepalived
from neutron.agent.linux import utils as agent_utils from neutron.agent.linux import utils as agent_utils
from neutron.common import constants as n_consts
from neutron.common import utils from neutron.common import utils
from neutron.i18n import _LE from neutron.i18n import _LE
from neutron.plugins.common import constants as const from neutron.plugins.common import constants as const
@ -166,6 +174,124 @@ def dnsmasq_version_supported():
return True return True
class KeepalivedIPv6Test(object):
def __init__(self, ha_port, gw_port, gw_vip, default_gw):
self.ha_port = ha_port
self.gw_port = gw_port
self.gw_vip = gw_vip
self.default_gw = default_gw
self.manager = None
self.config = None
self.config_path = None
self.nsname = "keepalivedtest-" + uuidutils.generate_uuid()
self.pm = external_process.ProcessMonitor(cfg.CONF, 'router')
self.orig_interval = cfg.CONF.AGENT.check_child_processes_interval
def configure(self):
config = keepalived.KeepalivedConf()
instance1 = keepalived.KeepalivedInstance('MASTER', self.ha_port, 1,
['169.254.192.0/18'],
advert_int=5)
instance1.track_interfaces.append(self.ha_port)
# Configure keepalived with an IPv6 address (gw_vip) on gw_port.
vip_addr1 = keepalived.KeepalivedVipAddress(self.gw_vip, self.gw_port)
instance1.vips.append(vip_addr1)
# Configure keepalived with an IPv6 default route on gw_port.
gateway_route = keepalived.KeepalivedVirtualRoute(n_consts.IPv6_ANY,
self.default_gw,
self.gw_port)
instance1.virtual_routes.gateway_routes = [gateway_route]
config.add_instance(instance1)
self.config = config
def start_keepalived_process(self):
# Disable process monitoring for Keepalived process.
cfg.CONF.set_override('check_child_processes_interval', 0, 'AGENT')
# Create a temp directory to store keepalived configuration.
self.config_path = tempfile.mkdtemp()
# Instantiate keepalived manager with the IPv6 configuration.
self.manager = keepalived.KeepalivedManager('router1', self.config,
namespace=self.nsname, process_monitor=self.pm,
conf_path=self.config_path)
self.manager.spawn()
def verify_ipv6_address_assignment(self, gw_dev):
process = self.manager.get_process()
agent_utils.wait_until_true(lambda: process.active)
def _gw_vip_assigned():
iface_ip = gw_dev.addr.list(ip_version=6, scope='global')
if iface_ip:
return self.gw_vip == iface_ip[0]['cidr']
agent_utils.wait_until_true(_gw_vip_assigned)
def __enter__(self):
ip_lib.IPWrapper().netns.add(self.nsname)
return self
def __exit__(self, exc_type, exc_value, exc_tb):
self.pm.stop()
if self.manager:
self.manager.disable()
if self.config_path:
shutil.rmtree(self.config_path, ignore_errors=True)
ip_lib.IPWrapper().netns.delete(self.nsname)
cfg.CONF.set_override('check_child_processes_interval',
self.orig_interval, 'AGENT')
def keepalived_ipv6_supported():
"""Check if keepalived supports IPv6 functionality.
Validation is done as follows.
1. Create a namespace.
2. Create OVS bridge with two ports (ha_port and gw_port)
3. Move the ovs ports to the namespace.
4. Spawn keepalived process inside the namespace with IPv6 configuration.
5. Verify if IPv6 address is assigned to gw_port.
6. Verify if IPv6 default route is configured by keepalived.
"""
random_str = utils.get_random_string(6)
br_name = "ka-test-" + random_str
ha_port = ha_router.HA_DEV_PREFIX + random_str
gw_port = namespaces.INTERNAL_DEV_PREFIX + random_str
gw_vip = 'fdf8:f53b:82e4::10/64'
expected_default_gw = 'fe80:f816::1'
with ovs_lib.OVSBridge(br_name) as br:
with KeepalivedIPv6Test(ha_port, gw_port, gw_vip,
expected_default_gw) as ka:
br.add_port(ha_port, ('type', 'internal'))
br.add_port(gw_port, ('type', 'internal'))
ha_dev = ip_lib.IPDevice(ha_port)
gw_dev = ip_lib.IPDevice(gw_port)
ha_dev.link.set_netns(ka.nsname)
gw_dev.link.set_netns(ka.nsname)
ha_dev.link.set_up()
gw_dev.link.set_up()
ka.configure()
ka.start_keepalived_process()
ka.verify_ipv6_address_assignment(gw_dev)
default_gw = gw_dev.route.get_gateway(ip_version=6)
if default_gw:
default_gw = default_gw['gateway']
return expected_default_gw == default_gw
def ovsdb_native_supported(): def ovsdb_native_supported():
# Running the test should ensure we are configured for OVSDB native # Running the test should ensure we are configured for OVSDB native
try: try:

View File

@ -21,6 +21,7 @@ from oslo_log import log as logging
from neutron.agent import dhcp_agent from neutron.agent import dhcp_agent
from neutron.cmd.sanity import checks from neutron.cmd.sanity import checks
from neutron.common import config from neutron.common import config
from neutron.db import l3_hamode_db
from neutron.i18n import _LE, _LW from neutron.i18n import _LE, _LW
@ -35,6 +36,7 @@ cfg.CONF.import_group('ml2', 'neutron.plugins.ml2.config')
cfg.CONF.import_group('ml2_sriov', cfg.CONF.import_group('ml2_sriov',
'neutron.plugins.ml2.drivers.mech_sriov.mech_driver') 'neutron.plugins.ml2.drivers.mech_sriov.mech_driver')
dhcp_agent.register_options() dhcp_agent.register_options()
cfg.CONF.register_opts(l3_hamode_db.L3_HA_OPTS)
class BoolOptCallback(cfg.BoolOpt): class BoolOptCallback(cfg.BoolOpt):
@ -105,6 +107,15 @@ def check_dnsmasq_version():
return result return result
def check_keepalived_ipv6_support():
result = checks.keepalived_ipv6_supported()
if not result:
LOG.error(_LE('The installed version of keepalived does not support '
'IPv6. Please update to at least version 1.2.10 for '
'IPv6 support.'))
return result
def check_nova_notify(): def check_nova_notify():
result = checks.nova_notify_supported() result = checks.nova_notify_supported()
if not result: if not result:
@ -181,6 +192,8 @@ OPTS = [
help=_('Check ovsdb native interface support')), help=_('Check ovsdb native interface support')),
BoolOptCallback('ebtables_installed', check_ebtables, BoolOptCallback('ebtables_installed', check_ebtables,
help=_('Check ebtables installation')), help=_('Check ebtables installation')),
BoolOptCallback('keepalived_ipv6_support', check_keepalived_ipv6_support,
help=_('Check keepalived IPv6 support')),
] ]
@ -214,6 +227,8 @@ def enable_tests_from_config():
cfg.CONF.set_override('dnsmasq_version', True) cfg.CONF.set_override('dnsmasq_version', True)
if cfg.CONF.OVS.ovsdb_interface == 'native': if cfg.CONF.OVS.ovsdb_interface == 'native':
cfg.CONF.set_override('ovsdb_native', True) cfg.CONF.set_override('ovsdb_native', True)
if cfg.CONF.l3_ha:
cfg.CONF.set_override('keepalived_ipv6_support', True)
def all_tests_passed(): def all_tests_passed():

View File

@ -67,3 +67,6 @@ class SanityTestCaseRoot(functional_base.BaseSudoTestCase):
def test_ovsdb_native_supported_runs(self): def test_ovsdb_native_supported_runs(self):
checks.ovsdb_native_supported() checks.ovsdb_native_supported()
def test_keepalived_ipv6_support(self):
checks.keepalived_ipv6_supported()