Merge ""keepalived_state_change" needs to use threading to send arping"

This commit is contained in:
Zuul 2020-04-06 16:30:18 +00:00 committed by Gerrit Code Review
commit fc96f5b2b3
3 changed files with 42 additions and 16 deletions

View File

@ -141,7 +141,8 @@ class MonitorDaemon(daemon.Daemon):
self.namespace, self.namespace,
event['name'], event['name'],
ip_address, ip_address,
log_exception=False log_exception=False,
use_eventlet=False
) )
LOG.debug('Sent GARP to %(ip_address)s from %(device_name)s', LOG.debug('Sent GARP to %(ip_address)s from %(device_name)s',
{'ip_address': ip_address, 'device_name': event['name']}) {'ip_address': ip_address, 'device_name': event['name']})

View File

@ -1044,7 +1044,8 @@ def _arping(ns_name, iface_name, address, count, log_exception):
def send_ip_addr_adv_notif( def send_ip_addr_adv_notif(
ns_name, iface_name, address, count=3, log_exception=True): ns_name, iface_name, address, count=3, log_exception=True,
use_eventlet=True):
"""Send advance notification of an IP address assignment. """Send advance notification of an IP address assignment.
If the address is in the IPv4 family, send gratuitous ARP. If the address is in the IPv4 family, send gratuitous ARP.
@ -1062,12 +1063,18 @@ def send_ip_addr_adv_notif(
:param log_exception: (Optional) True if possible failures should be logged :param log_exception: (Optional) True if possible failures should be logged
on exception level. Otherwise they are logged on on exception level. Otherwise they are logged on
WARNING level. Default is True. WARNING level. Default is True.
:param use_eventlet: (Optional) True if the arping command will be spawned
using eventlet, False to use Python threads
(threading).
""" """
def arping(): def arping():
_arping(ns_name, iface_name, address, count, log_exception) _arping(ns_name, iface_name, address, count, log_exception)
if count > 0 and netaddr.IPAddress(address).version == 4: if count > 0 and netaddr.IPAddress(address).version == 4:
eventlet.spawn_n(arping) if use_eventlet:
eventlet.spawn_n(arping)
else:
threading.Thread(target=arping).start()
def sysctl(cmd, namespace=None, log_fail_as_error=True): def sysctl(cmd, namespace=None, log_fail_as_error=True):

View File

@ -52,19 +52,7 @@ class TestMonitorDaemon(base.BaseLoggingTestCase):
self.router, self.peer = self.machines.machines[:2] self.router, self.peer = self.machines.machines[:2]
self.router_id = uuidutils.generate_uuid() self.router_id = uuidutils.generate_uuid()
self.cmd_opts = [ self._generate_cmd_opts()
ha_router.STATE_CHANGE_PROC_NAME,
'--router_id=%s' % self.router_id,
'--namespace=%s' % self.router.namespace,
'--conf_dir=%s' % self.conf_dir,
'--log-file=%s' % self.log_file,
'--monitor_interface=%s' % self.router.port.name,
'--monitor_cidr=%s' % self.cidr,
'--pid_file=%s' % self.pid_file,
'--state_path=%s' % self.conf_dir,
'--user=%s' % os.geteuid(),
'--group=%s' % os.getegid()
]
self.ext_process = external_process.ProcessManager( self.ext_process = external_process.ProcessManager(
None, '%s.monitor' % self.pid_file, None, service='test_ip_mon', None, '%s.monitor' % self.pid_file, None, service='test_ip_mon',
pids_path=self.conf_dir, default_cmd_callback=self._callback, pids_path=self.conf_dir, default_cmd_callback=self._callback,
@ -85,6 +73,22 @@ class TestMonitorDaemon(base.BaseLoggingTestCase):
def _callback(self, *args): def _callback(self, *args):
return self.cmd_opts return self.cmd_opts
def _generate_cmd_opts(self, monitor_interface=None, cidr=None):
monitor_interface = monitor_interface or self.router.port.name
cidr = cidr or self.cidr
self.cmd_opts = [
ha_router.STATE_CHANGE_PROC_NAME,
'--router_id=%s' % self.router_id,
'--namespace=%s' % self.router.namespace,
'--conf_dir=%s' % self.conf_dir,
'--log-file=%s' % self.log_file,
'--monitor_interface=%s' % monitor_interface,
'--monitor_cidr=%s' % cidr,
'--pid_file=%s' % self.pid_file,
'--state_path=%s' % self.conf_dir,
'--user=%s' % os.geteuid(),
'--group=%s' % os.getegid()]
def _search_in_file(self, file_name, text): def _search_in_file(self, file_name, text):
def text_in_file(): def text_in_file():
try: try:
@ -106,11 +110,22 @@ class TestMonitorDaemon(base.BaseLoggingTestCase):
'file_content': open(file_name).read()}) 'file_content': open(file_name).read()})
def test_new_fip_sends_garp(self): def test_new_fip_sends_garp(self):
ns_ip_wrapper = ip_lib.IPWrapper(self.router.namespace)
new_interface = ns_ip_wrapper.add_dummy('new_interface')
new_interface_cidr = '169.254.152.1/24'
new_interface.link.set_up()
new_interface.addr.add(new_interface_cidr)
self._generate_cmd_opts(monitor_interface='new_interface',
cidr=new_interface_cidr)
self._run_monitor() self._run_monitor()
next_ip_cidr = net_helpers.increment_ip_cidr(self.machines.ip_cidr, 2) next_ip_cidr = net_helpers.increment_ip_cidr(self.machines.ip_cidr, 2)
expected_ip = str(netaddr.IPNetwork(next_ip_cidr).ip) expected_ip = str(netaddr.IPNetwork(next_ip_cidr).ip)
# Create incomplete ARP entry # Create incomplete ARP entry
self.peer.assert_no_ping(expected_ip) self.peer.assert_no_ping(expected_ip)
# Wait for ping expiration
eventlet.sleep(1)
has_entry = has_expected_arp_entry( has_entry = has_expected_arp_entry(
self.peer.port.name, self.peer.port.name,
self.peer.namespace, self.peer.namespace,
@ -133,6 +148,9 @@ class TestMonitorDaemon(base.BaseLoggingTestCase):
self.router.port.link.address)) self.router.port.link.address))
utils.wait_until_true(has_arp_entry_predicate, timeout=15, utils.wait_until_true(has_arp_entry_predicate, timeout=15,
exception=exc) exception=exc)
msg = ('Sent GARP to %(cidr)s from %(device)s' %
{'cidr': expected_ip, 'device': self.router.port.name})
self._search_in_file(self.log_file, msg)
def test_read_queue_change_state(self): def test_read_queue_change_state(self):
self._run_monitor() self._run_monitor()