Merge "DVR: Always initialize floating IP host"
This commit is contained in:
commit
99babf1a5e
|
@ -172,6 +172,10 @@ VALID_FLOATINGIP_STATUS = (lib_constants.FLOATINGIP_STATUS_ACTIVE,
|
|||
lib_constants.FLOATINGIP_STATUS_DOWN,
|
||||
lib_constants.FLOATINGIP_STATUS_ERROR)
|
||||
|
||||
# Floating IP host binding states
|
||||
FLOATING_IP_HOST_UNBOUND = "FLOATING_IP_HOST_UNBOUND"
|
||||
FLOATING_IP_HOST_NEEDS_BINDING = "FLOATING_IP_HOST_NEEDS_BINDING"
|
||||
|
||||
# Possible types of values (e.g. in QoS rule types)
|
||||
VALUES_TYPE_CHOICES = "choices"
|
||||
VALUES_TYPE_RANGE = "range"
|
||||
|
|
|
@ -639,57 +639,55 @@ class _DVRAgentInterfaceMixin(object):
|
|||
|
||||
return routers_dict
|
||||
|
||||
@staticmethod
|
||||
def _get_floating_ip_host(floating_ip):
|
||||
"""Function to return floating IP host binding state
|
||||
|
||||
By default, floating IPs are not bound to any host. Instead
|
||||
of using the empty string to denote this use a constant.
|
||||
"""
|
||||
return floating_ip.get('host', l3_const.FLOATING_IP_HOST_UNBOUND)
|
||||
|
||||
def _process_floating_ips_dvr(self, context, routers_dict,
|
||||
floating_ips, host, agent):
|
||||
LOG.debug("FIP Agent : %s ", agent.id)
|
||||
for floating_ip in floating_ips:
|
||||
router = routers_dict.get(floating_ip['router_id'])
|
||||
if router:
|
||||
router_floatingips = router.get(const.FLOATINGIP_KEY, [])
|
||||
if router['distributed']:
|
||||
fip_host = floating_ip.get('host')
|
||||
fip_dest_host = floating_ip.get('dest_host')
|
||||
# Skip if floatingip need not be processed for the
|
||||
# given agent.
|
||||
if self._should_skip_floating_ip_processed_for_given_agent(
|
||||
floating_ip, fip_host, fip_dest_host, agent):
|
||||
if self._skip_floating_ip_for_mismatched_agent_or_host(
|
||||
floating_ip, agent, host):
|
||||
continue
|
||||
# Also skip floatingip if the fip port have a host defined
|
||||
# and if the host does not match.
|
||||
if self._check_floating_ip_not_valid_for_given_host(
|
||||
fip_host, fip_dest_host, host):
|
||||
continue
|
||||
LOG.debug("Floating IP host: %s", fip_host)
|
||||
router_floatingips = router.get(const.FLOATINGIP_KEY, [])
|
||||
router_floatingips.append(floating_ip)
|
||||
router[const.FLOATINGIP_KEY] = router_floatingips
|
||||
|
||||
def _check_floating_ip_not_valid_for_given_host(
|
||||
self, fip_host, fip_dest_host, host):
|
||||
"""Function to check if floatingip host match for the given agent.
|
||||
def _skip_floating_ip_for_mismatched_agent_or_host(self, floating_ip,
|
||||
agent, host):
|
||||
"""Function to check if floating IP processing can be skipped."""
|
||||
fip_host = self._get_floating_ip_host(floating_ip)
|
||||
|
||||
Check if the given floatingip host matches with the requesting
|
||||
host when floatingip dest_host is None.
|
||||
If floatingip dest_host is not None it means that the floatingip
|
||||
is migrating to a new compute host and the original host will not
|
||||
match.
|
||||
"""
|
||||
host_mismatch = (
|
||||
fip_host != host and fip_dest_host is None)
|
||||
return (fip_host is not None and host_mismatch)
|
||||
# Skip if it is unbound
|
||||
if fip_host == l3_const.FLOATING_IP_HOST_UNBOUND:
|
||||
return True
|
||||
|
||||
def _should_skip_floating_ip_processed_for_given_agent(
|
||||
self, floating_ip, fip_host, fip_dest_host, agent):
|
||||
"""Function to check if floatingip need to be processed or skipped.
|
||||
|
||||
Skip if host and dest_host is none and the agent
|
||||
requesting is not dvr_snat agent, and the fip has
|
||||
not already been assigned 'dvr_snat_bound' state.
|
||||
"""
|
||||
# Skip if the given agent is in the wrong mode - SNAT bound
|
||||
# requires DVR_SNAT agent.
|
||||
agent_mode = self._get_agent_mode(agent)
|
||||
return (fip_host is None and (fip_dest_host is None) and
|
||||
agent_mode in [const.L3_AGENT_MODE_LEGACY,
|
||||
const.L3_AGENT_MODE_DVR] and
|
||||
not floating_ip.get(l3_const.DVR_SNAT_BOUND))
|
||||
if (agent_mode in [const.L3_AGENT_MODE_LEGACY,
|
||||
const.L3_AGENT_MODE_DVR] and
|
||||
floating_ip.get(l3_const.DVR_SNAT_BOUND)):
|
||||
return True
|
||||
|
||||
# Skip if it is bound, but not to the given host
|
||||
fip_dest_host = floating_ip.get('dest_host')
|
||||
if (fip_host != l3_const.FLOATING_IP_HOST_NEEDS_BINDING and
|
||||
fip_host != host and fip_dest_host is None):
|
||||
return True
|
||||
|
||||
# not being skipped, log host
|
||||
LOG.debug("Floating IP host: %s", fip_host)
|
||||
return False
|
||||
|
||||
def _get_fip_agent_gw_ports(self, context, fip_agent_id):
|
||||
"""Return list of floating agent gateway ports for the agent."""
|
||||
|
@ -753,30 +751,29 @@ class _DVRAgentInterfaceMixin(object):
|
|||
port_dict.update({port['id']: port})
|
||||
# Add the port binding host to the floatingip dictionary
|
||||
for fip in floating_ips:
|
||||
# Assume no host binding required
|
||||
fip['host'] = l3_const.FLOATING_IP_HOST_UNBOUND
|
||||
vm_port = port_dict.get(fip['port_id'], None)
|
||||
if vm_port:
|
||||
# Default value if host port-binding required
|
||||
fip['host'] = l3_const.FLOATING_IP_HOST_NEEDS_BINDING
|
||||
port_host = vm_port[portbindings.HOST_ID]
|
||||
if port_host:
|
||||
fip['host'] = port_host
|
||||
fip['dest_host'] = (
|
||||
self._get_dvr_migrating_service_port_hostid(
|
||||
context, fip['port_id'], port=vm_port))
|
||||
vm_port_agent_mode = vm_port.get('agent', None)
|
||||
if vm_port_agent_mode == (
|
||||
if vm_port_agent_mode != (
|
||||
l3_const.L3_AGENT_MODE_DVR_NO_EXTERNAL):
|
||||
# For floatingip configured on ports that
|
||||
# reside on 'dvr_no_external' agent, get rid of
|
||||
# the fip host binding since it would be created
|
||||
# For floatingip configured on ports that do not
|
||||
# reside on a 'dvr_no_external' agent, add the
|
||||
# fip host binding, else it will be created
|
||||
# in the 'dvr_snat' agent.
|
||||
fip['host'] = None
|
||||
else:
|
||||
# If no port-binding assign the fip['host']
|
||||
# value to None.
|
||||
fip['host'] = None
|
||||
fip['host'] = port_host
|
||||
# Handle the case were there is no host binding
|
||||
# for the private ports that are associated with
|
||||
# floating ip.
|
||||
if not fip['host'] or fip['host'] is None:
|
||||
if fip['host'] == l3_const.FLOATING_IP_HOST_NEEDS_BINDING:
|
||||
fip[l3_const.DVR_SNAT_BOUND] = True
|
||||
routers_dict = self._process_routers(context, routers, agent)
|
||||
self._process_floating_ips_dvr(context, routers_dict,
|
||||
|
|
|
@ -748,6 +748,87 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
|||
floatingips = router_info[0][constants.FLOATINGIP_KEY]
|
||||
self.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND])
|
||||
|
||||
def test_dvr_process_floatingips_for_dvr_on_full_sync(self):
|
||||
HOST1 = 'host1'
|
||||
helpers.register_l3_agent(
|
||||
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||
router = self._create_router(ha=False)
|
||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
||||
kwargs = {'arg_list': (external_net.EXTERNAL,),
|
||||
external_net.EXTERNAL: True}
|
||||
ext_net = self._make_network(self.fmt, '', True, **kwargs)
|
||||
self._make_subnet(
|
||||
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
||||
ip_version=4, enable_dhcp=True)
|
||||
# Schedule the router to the dvr_snat node
|
||||
self.l3_plugin.schedule_router(self.context,
|
||||
router['id'],
|
||||
candidates=[self.l3_agent])
|
||||
|
||||
# Set gateway to router
|
||||
self.l3_plugin._update_router_gw_info(
|
||||
self.context, router['id'],
|
||||
{'network_id': ext_net['network']['id']})
|
||||
private_subnet1 = self._make_subnet(
|
||||
self.fmt,
|
||||
private_net1,
|
||||
'10.1.0.1',
|
||||
cidr='10.1.0.0/24',
|
||||
ip_version=4,
|
||||
enable_dhcp=True)
|
||||
with self.port(
|
||||
subnet=private_subnet1,
|
||||
device_owner=DEVICE_OWNER_COMPUTE) as int_port1,\
|
||||
self.port(
|
||||
subnet=private_subnet1) as int_port2:
|
||||
self.l3_plugin.add_router_interface(
|
||||
self.context, router['id'],
|
||||
{'subnet_id': private_subnet1['subnet']['id']})
|
||||
router_handle = (
|
||||
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
|
||||
self.context, self.l3_agent['host'], [router['id']]))
|
||||
self.assertEqual(self.l3_agent['host'],
|
||||
router_handle[0]['gw_port_host'])
|
||||
with mock.patch.object(self.l3_plugin,
|
||||
'_l3_rpc_notifier') as l3_notifier:
|
||||
self.core_plugin.update_port(
|
||||
self.context, int_port1['port']['id'],
|
||||
{'port': {portbindings.HOST_ID: HOST1}})
|
||||
# Now let us assign the floatingip to the bound port
|
||||
# and unbound port.
|
||||
fip1 = {'floating_network_id': ext_net['network']['id'],
|
||||
'router_id': router['id'],
|
||||
'port_id': int_port1['port']['id'],
|
||||
'tenant_id': int_port1['port']['tenant_id']}
|
||||
self.l3_plugin.create_floatingip(
|
||||
self.context, {'floatingip': fip1})
|
||||
expected_routers_updated_calls = [
|
||||
mock.call(self.context, mock.ANY, HOST1)]
|
||||
l3_notifier.routers_updated_on_host.assert_has_calls(
|
||||
expected_routers_updated_calls)
|
||||
self.assertFalse(l3_notifier.routers_updated.called)
|
||||
fip2 = {'floating_network_id': ext_net['network']['id'],
|
||||
'router_id': router['id'],
|
||||
'port_id': int_port2['port']['id'],
|
||||
'tenant_id': int_port2['port']['tenant_id']}
|
||||
self.l3_plugin.create_floatingip(
|
||||
self.context, {'floatingip': fip2})
|
||||
router_info = (
|
||||
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
|
||||
self.context, self.l3_agent['host'], [router['id']]))
|
||||
floatingips = router_info[0][constants.FLOATINGIP_KEY]
|
||||
self.assertEqual(1, len(floatingips))
|
||||
self.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND])
|
||||
self.assertEqual(n_const.FLOATING_IP_HOST_NEEDS_BINDING,
|
||||
floatingips[0]['host'])
|
||||
router1_info = (
|
||||
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
|
||||
self.context, HOST1, [router['id']]))
|
||||
floatingips = router1_info[0][constants.FLOATINGIP_KEY]
|
||||
self.assertEqual(1, len(floatingips))
|
||||
self.assertEqual(HOST1, floatingips[0]['host'])
|
||||
self.assertIsNone(floatingips[0]['dest_host'])
|
||||
|
||||
def test_dvr_router_centralized_floating_ip(self):
|
||||
HOST1 = 'host1'
|
||||
helpers.register_l3_agent(
|
||||
|
|
|
@ -363,9 +363,10 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
|||
'id': _uuid(),
|
||||
'port_id': _uuid(),
|
||||
'router_id': 'foo_router_id',
|
||||
'host': hostid
|
||||
}
|
||||
if not hostid:
|
||||
if hostid is not None:
|
||||
floatingip['host'] = hostid
|
||||
else:
|
||||
hostid = 'not_my_host_id'
|
||||
routers = {
|
||||
'foo_router_id': router
|
||||
|
@ -389,7 +390,7 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
|||
hostid, agent)
|
||||
return (router, floatingip)
|
||||
|
||||
def test_floatingip_on_port_not_host(self):
|
||||
def test_floatingip_on_port_no_host_key(self):
|
||||
router, fip = self._floatingip_on_port_test_setup(None)
|
||||
|
||||
self.assertNotIn(const.FLOATINGIP_KEY, router)
|
||||
|
|
Loading…
Reference in New Issue