Merge "Don't skip DVR port while neutron-openvswitch-agent is restared." into stable/pike
This commit is contained in:
commit
e1e37a891d
@ -248,6 +248,14 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
||||
|
||||
return agents
|
||||
|
||||
def agent_restarted(self, context):
|
||||
agent_host = context.host
|
||||
session = db_api.get_reader_session()
|
||||
agent = l2pop_db.get_agent_by_host(session, agent_host)
|
||||
if l2pop_db.get_agent_uptime(agent) < cfg.CONF.l2pop.agent_boot_time:
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_port_down(self, context):
|
||||
port = context.current
|
||||
agent_host = context.host
|
||||
@ -296,9 +304,8 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
||||
# with high concurrency more than 1 port may be activated on an agent
|
||||
# at the same time (like VM port + a DVR port) so checking for 1 or 2
|
||||
is_first_port = agent_active_ports in (1, 2)
|
||||
if is_first_port or (l2pop_db.get_agent_uptime(agent) <
|
||||
cfg.CONF.l2pop.agent_boot_time):
|
||||
# First port(s) activated on current agent in this network,
|
||||
if is_first_port or self.agent_restarted(context):
|
||||
# First port activated on current agent in this network,
|
||||
# we have to provide it with the whole list of fdb entries
|
||||
agent_fdb_entries = self._create_agent_fdb(session,
|
||||
agent,
|
||||
|
@ -304,24 +304,28 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
|
||||
port = ml2_db.get_port(rpc_context, port_id)
|
||||
if not port:
|
||||
return
|
||||
# NOTE: DVR ports are already handled and updated through l2pop
|
||||
# and so we don't need to update it again here
|
||||
if port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE:
|
||||
return
|
||||
port_context = plugin.get_bound_port_context(
|
||||
rpc_context, port_id)
|
||||
rpc_context, port_id, host)
|
||||
if not port_context:
|
||||
# port deleted
|
||||
return
|
||||
# NOTE: DVR ports are already handled and updated through l2pop
|
||||
# and so we don't need to update it again here. But, l2pop did not
|
||||
# handle DVR ports while restart neutron-*-agent, we need to handle
|
||||
# it here.
|
||||
if (port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE and
|
||||
not l2pop_driver.obj.agent_restarted(port_context)):
|
||||
return
|
||||
port = port_context.current
|
||||
if (status == n_const.PORT_STATUS_ACTIVE and
|
||||
if (port['device_owner'] != n_const.DEVICE_OWNER_DVR_INTERFACE and
|
||||
status == n_const.PORT_STATUS_ACTIVE and
|
||||
port[portbindings.HOST_ID] != host and
|
||||
not l3_hamode_db.is_ha_router_port(rpc_context,
|
||||
port['device_owner'],
|
||||
port['device_id'])):
|
||||
# don't setup ACTIVE forwarding entries unless bound to this
|
||||
# host or if it's an HA port (which is special-cased in the
|
||||
# mech driver)
|
||||
# host or if it's an HA or DVR port (which is special-cased in
|
||||
# the mech driver)
|
||||
return
|
||||
port_context.current['status'] = status
|
||||
port_context.current[portbindings.HOST_ID] = host
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
|
||||
from neutron_lib.api.definitions import port as port_def
|
||||
@ -353,6 +355,37 @@ class TestL2PopulationRpcTestCase(test_plugin.Ml2PluginV2TestCase):
|
||||
self.mock_fanout.assert_called_with(
|
||||
mock.ANY, 'remove_fdb_entries', expected)
|
||||
|
||||
def test_ovs_agent_restarted_with_dvr_port(self):
|
||||
plugin = directory.get_plugin()
|
||||
router = self._create_dvr_router()
|
||||
with mock.patch.object(l2pop_mech_driver.L2populationMechanismDriver,
|
||||
'agent_restarted', return_value=True):
|
||||
with self.subnet(network=self._network,
|
||||
enable_dhcp=False) as snet:
|
||||
with self.port(
|
||||
subnet=snet,
|
||||
device_owner=constants.DEVICE_OWNER_DVR_INTERFACE)\
|
||||
as port:
|
||||
port_id = port['port']['id']
|
||||
plugin.update_distributed_port_binding(self.adminContext,
|
||||
port_id, {'port': {portbindings.HOST_ID: HOST_4,
|
||||
'device_id': router['id']}})
|
||||
port = self._show('ports', port_id)
|
||||
self.assertEqual(portbindings.VIF_TYPE_DISTRIBUTED,
|
||||
port['port'][portbindings.VIF_TYPE])
|
||||
self.callbacks.update_device_up(self.adminContext,
|
||||
agent_id=HOST_4,
|
||||
device=port_id,
|
||||
host=HOST_4)
|
||||
fanout_expected = {port['port']['network_id']: {
|
||||
'network_type': u'vxlan',
|
||||
'ports': {
|
||||
u'20.0.0.4': [('00:00:00:00:00:00', '0.0.0.0')]},
|
||||
'segment_id': 1}}
|
||||
self.mock_fanout.assert_called_with(mock.ANY,
|
||||
'add_fdb_entries',
|
||||
fanout_expected)
|
||||
|
||||
def test_ha_agents_with_dvr_rtr_does_not_get_other_fdb(self):
|
||||
router = self._create_dvr_router()
|
||||
directory.add_plugin(plugin_constants.L3, self.plugin)
|
||||
@ -1454,3 +1487,25 @@ class TestL2PopulationMechDriver(base.BaseTestCase):
|
||||
mech_driver = l2pop_mech_driver.L2populationMechanismDriver()
|
||||
with testtools.ExpectedException(exceptions.InvalidInput):
|
||||
mech_driver.update_port_precommit(ctx)
|
||||
|
||||
def test_agent_restarted(self):
|
||||
mech_driver = l2pop_mech_driver.L2populationMechanismDriver()
|
||||
ctx = mock.Mock()
|
||||
ctx.host = "__host1__"
|
||||
ctx._plugin_context = {}
|
||||
agent = mock.Mock()
|
||||
agent.started_at = datetime.datetime(2018, 5, 25, 15, 51, 20)
|
||||
agent.heartbeat_timestamp = datetime.datetime(2018, 5, 25, 15,
|
||||
51, 50)
|
||||
|
||||
with mock.patch.object(l2pop_db, 'get_agent_by_host',
|
||||
return_value=agent):
|
||||
res = mech_driver.agent_restarted(ctx)
|
||||
self.assertTrue(res)
|
||||
|
||||
agent.heartbeat_timestamp = datetime.datetime(2018, 5, 25, 15,
|
||||
58, 30)
|
||||
with mock.patch.object(l2pop_db, 'get_agent_by_host',
|
||||
return_value=agent):
|
||||
res = mech_driver.agent_restarted(ctx)
|
||||
self.assertFalse(res)
|
||||
|
Loading…
Reference in New Issue
Block a user