Merge "[eventlet-removal] DHCP: move RPC init to service.start phase"

This commit is contained in:
Zuul
2025-06-05 20:14:36 +00:00
committed by Gerrit Code Review
3 changed files with 76 additions and 21 deletions

View File

@@ -121,13 +121,9 @@ class DhcpAgent(manager.Manager):
opt_value=self.conf.resync_throttle)
self._periodic_resync_event = threading.Event()
self.cache = NetworkCache()
self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, self.conf.host)
# create dhcp dir to store dhcp info
dhcp_dir = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
fileutils.ensure_tree(dhcp_dir, mode=0o755)
self.dhcp_version = self.dhcp_driver_cls.check_version()
self._populate_networks_cache()
# keep track of mappings between networks and routers for
# metadata processing
self._metadata_routers = {} # {network_id: router_id}
@@ -153,6 +149,12 @@ class DhcpAgent(manager.Manager):
self.restarted_metadata_proxy_set = set()
def init_host(self):
super().init_host()
self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, self.conf.host)
self.dhcp_version = self.dhcp_driver_cls.check_version()
self._populate_networks_cache()
self.sync_state()
def _populate_networks_cache(self):
@@ -1060,11 +1062,15 @@ class NetworkCache:
class DhcpAgentWithStateReport(DhcpAgent):
def __init__(self, host=None, conf=None):
super().__init__(host=host, conf=conf)
self.host = host
def init_host(self):
super().init_host()
self.state_rpc = agent_rpc.PluginReportStateAPI(topics.REPORTS)
self.failed_report_state = False
self.agent_state = {
'binary': constants.AGENT_PROCESS_DHCP,
'host': host,
'host': self.host,
'availability_zone': self.conf.AGENT.availability_zone,
'topic': topics.DHCP_AGENT,
'configurations': {

View File

@@ -86,6 +86,7 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
self.conf.set_override('check_child_processes_interval', 1, 'AGENT')
self.agent = agent.DhcpAgentWithStateReport('localhost')
self.agent.init_host()
self.ovs_driver = interface.OVSInterfaceDriver(self.conf)
mock.patch('neutron.agent.common.ovs_lib.'

View File

@@ -364,6 +364,7 @@ class TestDhcpAgent(base.BaseTestCase):
common_config.init(sys.argv[1:])
agent_mgr = dhcp_agent.DhcpAgentWithStateReport(
'testhost')
agent_mgr.init_host()
eventlet.greenthread.sleep(1)
agent_mgr.after_start()
mock_periodic_resync.assert_called_once_with(agent_mgr)
@@ -376,6 +377,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_run_completes_single_pass(self):
with mock.patch(DEVICE_MANAGER):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
attrs_to_mock = {
a: mock.DEFAULT for a in
['periodic_resync', 'start_ready_ports_loop',
@@ -392,6 +394,7 @@ class TestDhcpAgent(base.BaseTestCase):
network = mock.MagicMock()
network.id = '1'
dhcp = dhcp_agent.DhcpAgent(cfg.CONF)
dhcp.init_host()
self.assertTrue(dhcp.call_driver('foo', network))
self.driver.assert_called_once_with(cfg.CONF,
mock.ANY,
@@ -416,6 +419,7 @@ class TestDhcpAgent(base.BaseTestCase):
segments=[seg1, seg0])
agent = dhcp_agent.DhcpAgent(cfg.CONF)
agent.init_host()
with mock.patch.object(agent,
'_call_driver') as _call_driver:
self.assertTrue(agent.call_driver('enable', network))
@@ -428,6 +432,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_call_driver_no_network(self):
network = None
dhcp = dhcp_agent.DhcpAgent(cfg.CONF)
dhcp.init_host()
self.assertIsNone(dhcp.call_driver('foo', network))
def _test_call_driver_failure(self, exc=None,
@@ -436,6 +441,7 @@ class TestDhcpAgent(base.BaseTestCase):
network.id = '1'
self.driver.return_value.foo.side_effect = exc or Exception
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(dhcp,
'schedule_resync') as schedule_resync:
self.assertIsNone(dhcp.call_driver('foo', network))
@@ -475,6 +481,7 @@ class TestDhcpAgent(base.BaseTestCase):
network = mock.MagicMock()
self.driver().get_metadata_bind_interface.return_value = 'iface0'
agent = dhcp_agent.DhcpAgent(cfg.CONF)
agent.init_host()
self.assertEqual(
'iface0',
agent.call_driver('get_metadata_bind_interface', network))
@@ -486,6 +493,7 @@ class TestDhcpAgent(base.BaseTestCase):
network.subnets[0] = fake_subnet1
self.driver().get_metadata_bind_interface.return_value = 'iface0'
agent = dhcp_agent.DhcpAgent(cfg.CONF)
agent.init_host()
self.assertEqual(
'iface0',
agent.call_driver('get_metadata_bind_interface', network))
@@ -498,22 +506,23 @@ class TestDhcpAgent(base.BaseTestCase):
mock_plugin.get_active_networks_info.return_value = active_networks
plug.return_value = mock_plugin
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp_obj = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp_obj.init_host()
attrs_to_mock = {a: mock.DEFAULT
for a in ['disable_dhcp_helper', 'cache',
'safe_configure_dhcp_for_network']}
with mock.patch.multiple(dhcp, **attrs_to_mock) as mocks:
with mock.patch.multiple(dhcp_obj, **attrs_to_mock) as mocks:
mocks['cache'].get_network_ids.return_value = known_net_ids
mocks['cache'].get_port_ids.return_value = range(4)
dhcp.sync_state()
dhcp_obj.sync_state()
diff = set(known_net_ids) - set(active_net_ids)
exp_disable = [mock.call(net_id) for net_id in diff]
mocks['cache'].assert_has_calls([mock.call.get_network_ids()])
mocks['disable_dhcp_helper'].assert_has_calls(exp_disable)
self.assertEqual(set(range(4)), dhcp.dhcp_ready_ports)
self.assertEqual(set(range(4)), dhcp_obj.dhcp_ready_ports)
def test_sync_state_initial(self):
self._test_sync_state_helper([], ['a'])
@@ -529,7 +538,11 @@ class TestDhcpAgent(base.BaseTestCase):
active_net_ids = ['1', '2', '3', '4', '5']
known_net_ids = ['1', '2', '3', '4', '5']
self._test_sync_state_helper(known_net_ids, active_net_ids)
mock_wait.assert_called_once()
# As init_host called before the mocks take effect there are
# a 1st call for wait with TypeErrors (sync_state is executed and
# expects network objects via RPC)
wait_calls = [mock.call(mock.ANY), mock.call(mock.ANY)]
mock_wait.assert_has_calls(wait_calls)
def test_sync_state_for_all_networks_plugin_error(self):
with mock.patch(DHCP_PLUGIN) as plug:
@@ -539,6 +552,7 @@ class TestDhcpAgent(base.BaseTestCase):
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(dhcp,
'schedule_resync') as schedule_resync:
dhcp.sync_state()
@@ -555,6 +569,7 @@ class TestDhcpAgent(base.BaseTestCase):
with mock.patch.object(dhcp_agent.LOG, 'exception') as log:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(dhcp,
'schedule_resync') as schedule_resync:
dhcp.sync_state(['foo_network'])
@@ -564,18 +579,21 @@ class TestDhcpAgent(base.BaseTestCase):
def test_periodic_resync(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(dhcp_agent.eventlet, 'spawn') as spawn:
dhcp.periodic_resync()
spawn.assert_called_once_with(dhcp._periodic_resync_helper)
def test_start_ready_ports_loop(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(dhcp_agent.eventlet, 'spawn') as spawn:
dhcp.start_ready_ports_loop()
spawn.assert_called_once_with(dhcp._dhcp_ready_ports_loop)
def test__dhcp_ready_ports_doesnt_log_exception_on_timeout(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.dhcp_ready_ports = set(range(4))
with mock.patch.object(dhcp.plugin_rpc, 'dhcp_ready_on_ports',
@@ -590,6 +608,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test__dhcp_ready_ports_loop(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.dhcp_ready_ports = set(range(4))
with mock.patch.object(dhcp.plugin_rpc, 'dhcp_ready_on_ports',
@@ -604,6 +623,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_dhcp_ready_ports_loop_with_limit_ports_per_call(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
sync_max = dhcp_agent.DHCP_READY_PORTS_SYNC_MAX
port_count = sync_max + 1
dhcp.dhcp_ready_ports = set(range(port_count))
@@ -630,6 +650,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_dhcp_ready_ports_loop_with_limit_ports_per_call_prio(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
sync_max = dhcp_agent.DHCP_READY_PORTS_SYNC_MAX
port_count = 4
# port set ranges must be unique to differentiate results
@@ -679,6 +700,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_configure_dhcp_for_network(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(
dhcp, 'update_isolated_metadata_proxy') as ump, \
mock.patch.object(
@@ -691,6 +713,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_configure_dhcp_for_network_no_subnets_with_dhcp_enabled(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(
dhcp, 'update_isolated_metadata_proxy') as ump, \
mock.patch.object(
@@ -705,6 +728,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_safe_configure_dhcp_for_network(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(
dhcp, 'update_isolated_metadata_proxy') as ump, \
mock.patch.object(
@@ -718,6 +742,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_safe_configure_dhcp_for_network_exception(self):
# This should return without raising an exception
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
with mock.patch.object(
dhcp, 'configure_dhcp_for_network',
side_effect=RuntimeError):
@@ -732,6 +757,7 @@ class TestDhcpAgent(base.BaseTestCase):
'IpAddrCommand.wait_until_address_ready') as mock_wait:
mock_wait.return_value = True
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.update_isolated_metadata_proxy = mock.Mock()
self.assertEqual(set(), dhcp.dhcp_ready_ports)
dhcp.configure_dhcp_for_network(fake_network)
@@ -744,6 +770,7 @@ class TestDhcpAgent(base.BaseTestCase):
with mock.patch.object(metadata_driver,
'MetadataDriver') as md_cls:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.configure_dhcp_for_network(fake_network)
md_cls.spawn_monitored_metadata_proxy.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY, mock.ANY,
@@ -761,6 +788,7 @@ class TestDhcpAgent(base.BaseTestCase):
with mock.patch.object(metadata_driver,
'MetadataDriver') as md_cls:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.configure_dhcp_for_network(fake_network)
md_cls.destroy_monitored_metadata_proxy.assert_called_once_with(
mock.ANY, fake_network.id, mock.ANY, fake_network.namespace)
@@ -770,21 +798,36 @@ class TestDhcpAgent(base.BaseTestCase):
network_id=fake_network.id)
def test_report_state_revival_logic(self):
dhcp = dhcp_agent.DhcpAgentWithStateReport(HOSTNAME)
with mock.patch.object(dhcp.state_rpc,
'report_state') as report_state,\
mock.patch.object(dhcp, "run"):
report_state.return_value = agent_consts.AGENT_ALIVE
dhcp._report_state()
self.assertEqual({}, dhcp.needs_resync_reasons)
dhcp_ = dhcp_agent.DhcpAgentWithStateReport(HOSTNAME)
networks = [{'id': '1'}, {'id': '2'}]
dhcp_.init_host()
report_state.return_value = agent_consts.AGENT_REVIVED
dhcp._report_state()
self.assertEqual(dhcp.needs_resync_reasons[None],
['Agent has just been revived'])
with mock.patch.object(
dhcp_.plugin_rpc, 'get_active_networks_info',
return_value=[dhcp.NetModel(n) for n in networks]):
with mock.patch.object(dhcp_.state_rpc,
'report_state') as report_state,\
mock.patch.object(dhcp_, "run"):
dhcp_.sync_state()
report_state.return_value = agent_consts.AGENT_ALIVE
dhcp_._report_state()
# Only MessagingTimeout is in the list as init_host
# was called before the mock
self.assertIn(None, dhcp_.needs_resync_reasons.keys())
report_state.return_value = agent_consts.AGENT_REVIVED
dhcp_._report_state()
# The 1st item in the list is the MessagingTimeout,
# the 2nd one is the actual msg
self.assertEqual(dhcp_.needs_resync_reasons[None][1],
'Agent has just been revived')
def test_periodic_resync_helper(self):
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
resync_reasons = collections.OrderedDict(
(('a', 'reason1'), ('b', 'reason2')))
dhcp.needs_resync_reasons = resync_reasons
@@ -798,6 +841,7 @@ class TestDhcpAgent(base.BaseTestCase):
def test_periodic_resync_helper_with_event(self):
with mock.patch.object(dhcp_agent.LOG, 'debug') as log:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
dhcp.schedule_resync('reason1', 'a')
dhcp.schedule_resync('reason1', 'b')
reasons = list(dhcp.needs_resync_reasons.keys())
@@ -815,6 +859,7 @@ class TestDhcpAgent(base.BaseTestCase):
with mock.patch.object(dhcp_agent.LOG, 'debug') as log:
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
self.driver.existing_dhcp_networks.assert_called_once_with(
dhcp.conf,
@@ -828,6 +873,7 @@ class TestDhcpAgent(base.BaseTestCase):
self.driver.existing_dhcp_networks.return_value = networks
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.init_host()
self.driver.existing_dhcp_networks.assert_called_once_with(
dhcp.conf,
@@ -861,6 +907,7 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
cache_cls = self.cache_p.start()
self.cache = mock.Mock()
self.cache.is_port_message_stale.return_value = False
self.cache.get_network_ids.return_value = {1, 2, 3}
cache_cls.return_value = self.cache
self.mock_makedirs_p = mock.patch("os.makedirs")
self.mock_makedirs = self.mock_makedirs_p.start()
@@ -868,6 +915,7 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
'DhcpAgent._populate_networks_cache')
self.mock_init = self.mock_init_p.start()
self.dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
self.dhcp.init_host()
self.call_driver_p = mock.patch.object(self.dhcp, 'call_driver')
self.call_driver = self.call_driver_p.start()
self.schedule_resync_p = mock.patch.object(self.dhcp,