DVR: Server side patch to schedule an unbound port with Floating IP
Unbound ports that are associated with a Floating IP and connected to DVR Routers will not be serviced by the DVR Routers, unless we bind it to a valid host. This server side patch allows the neutron server to schedule the unbound port Floating IP on the network node or the node with dvr_snat agent where the SNAT functionality resides. The DNAT rules for the unbound ports will be configured in the SNAT namespace on the network node. Related-Bug: #1583694 Change-Id: I05d0bfb3fa275b1e4e479928000cf8494da858f6
This commit is contained in:
parent
1a11bc9605
commit
cced31c6b9
|
@ -28,6 +28,7 @@ HA_ROUTER_STATE_KEY = '_ha_state'
|
||||||
METERING_LABEL_KEY = '_metering_labels'
|
METERING_LABEL_KEY = '_metering_labels'
|
||||||
FLOATINGIP_AGENT_INTF_KEY = '_floatingip_agent_interfaces'
|
FLOATINGIP_AGENT_INTF_KEY = '_floatingip_agent_interfaces'
|
||||||
SNAT_ROUTER_INTF_KEY = '_snat_router_interfaces'
|
SNAT_ROUTER_INTF_KEY = '_snat_router_interfaces'
|
||||||
|
DVR_SNAT_BOUND = 'dvr_snat_bound'
|
||||||
|
|
||||||
HA_NETWORK_NAME = 'HA network tenant %s'
|
HA_NETWORK_NAME = 'HA network tenant %s'
|
||||||
HA_SUBNET_NAME = 'HA subnet tenant %s'
|
HA_SUBNET_NAME = 'HA subnet tenant %s'
|
||||||
|
|
|
@ -350,10 +350,6 @@ class DVRResourceOperationHandler(object):
|
||||||
fixed_ip_address))
|
fixed_ip_address))
|
||||||
if not addr_pair_active_service_port_list:
|
if not addr_pair_active_service_port_list:
|
||||||
return
|
return
|
||||||
if len(addr_pair_active_service_port_list) > 1:
|
|
||||||
LOG.warning(_LW("Multiple active ports associated "
|
|
||||||
"with the allowed_address_pairs."))
|
|
||||||
return
|
|
||||||
self._inherit_service_port_and_arp_update(
|
self._inherit_service_port_and_arp_update(
|
||||||
context, addr_pair_active_service_port_list[0],
|
context, addr_pair_active_service_port_list[0],
|
||||||
port)
|
port)
|
||||||
|
@ -365,16 +361,8 @@ class DVRResourceOperationHandler(object):
|
||||||
service_port)
|
service_port)
|
||||||
address_pair_list = service_port_dict.get('allowed_address_pairs')
|
address_pair_list = service_port_dict.get('allowed_address_pairs')
|
||||||
for address_pair in address_pair_list:
|
for address_pair in address_pair_list:
|
||||||
updated_port = (
|
self.update_arp_entry_for_dvr_service_port(context,
|
||||||
self.l3plugin.update_unbound_allowed_address_pair_port_binding(
|
service_port_dict)
|
||||||
context, service_port_dict,
|
|
||||||
address_pair,
|
|
||||||
address_pair_port=allowed_address_port))
|
|
||||||
if not updated_port:
|
|
||||||
LOG.warning(_LW("Allowed_address_pair port update failed: %s"),
|
|
||||||
updated_port)
|
|
||||||
self.l3plugin.update_arp_entry_for_dvr_service_port(
|
|
||||||
context, service_port_dict)
|
|
||||||
|
|
||||||
@registry.receives(resources.ROUTER_INTERFACE, [events.BEFORE_CREATE])
|
@registry.receives(resources.ROUTER_INTERFACE, [events.BEFORE_CREATE])
|
||||||
@db_api.retry_if_session_inactive()
|
@db_api.retry_if_session_inactive()
|
||||||
|
@ -638,19 +626,57 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
return routers_dict
|
return routers_dict
|
||||||
|
|
||||||
def _process_floating_ips_dvr(self, context, routers_dict,
|
def _process_floating_ips_dvr(self, context, routers_dict,
|
||||||
floating_ips, host):
|
floating_ips, host, agent):
|
||||||
|
LOG.debug("FIP Agent : %s ", agent.id)
|
||||||
for floating_ip in floating_ips:
|
for floating_ip in floating_ips:
|
||||||
router = routers_dict.get(floating_ip['router_id'])
|
router = routers_dict.get(floating_ip['router_id'])
|
||||||
if router:
|
if router:
|
||||||
router_floatingips = router.get(const.FLOATINGIP_KEY, [])
|
router_floatingips = router.get(const.FLOATINGIP_KEY, [])
|
||||||
if router['distributed']:
|
if router['distributed']:
|
||||||
if (floating_ip.get('host', None) != host and
|
fip_host = floating_ip.get('host')
|
||||||
floating_ip.get('dest_host') is None):
|
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):
|
||||||
continue
|
continue
|
||||||
LOG.debug("Floating IP host: %s", floating_ip['host'])
|
# 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.append(floating_ip)
|
router_floatingips.append(floating_ip)
|
||||||
router[const.FLOATINGIP_KEY] = router_floatingips
|
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.
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
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))
|
||||||
|
|
||||||
def _get_fip_agent_gw_ports(self, context, fip_agent_id):
|
def _get_fip_agent_gw_ports(self, context, fip_agent_id):
|
||||||
"""Return list of floating agent gateway ports for the agent."""
|
"""Return list of floating agent gateway ports for the agent."""
|
||||||
if not fip_agent_id:
|
if not fip_agent_id:
|
||||||
|
@ -684,7 +710,11 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
port_in_migration = (
|
port_in_migration = (
|
||||||
port_profile and
|
port_profile and
|
||||||
port_profile.get('migrating_to') == host)
|
port_profile.get('migrating_to') == host)
|
||||||
if (port[portbindings.HOST_ID] == host or port_in_migration):
|
# All unbound ports with floatingip irrespective of
|
||||||
|
# the device owner should be included as valid ports
|
||||||
|
# and updated.
|
||||||
|
if (port[portbindings.HOST_ID] == host or port_in_migration or
|
||||||
|
self._is_unbound_port(port)):
|
||||||
port_dict.update({port['id']: port})
|
port_dict.update({port['id']: port})
|
||||||
# Add the port binding host to the floatingip dictionary
|
# Add the port binding host to the floatingip dictionary
|
||||||
for fip in floating_ips:
|
for fip in floating_ips:
|
||||||
|
@ -695,9 +725,14 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
fip['dest_host'] = (
|
fip['dest_host'] = (
|
||||||
self._get_dvr_migrating_service_port_hostid(
|
self._get_dvr_migrating_service_port_hostid(
|
||||||
context, fip['port_id'], port=vm_port))
|
context, fip['port_id'], port=vm_port))
|
||||||
|
# Handle the case were there is no host binding
|
||||||
|
# for the private ports that are associated with
|
||||||
|
# floating ip.
|
||||||
|
if not fip['host']:
|
||||||
|
fip[l3_const.DVR_SNAT_BOUND] = True
|
||||||
routers_dict = self._process_routers(context, routers, agent)
|
routers_dict = self._process_routers(context, routers, agent)
|
||||||
self._process_floating_ips_dvr(context, routers_dict,
|
self._process_floating_ips_dvr(context, routers_dict,
|
||||||
floating_ips, host)
|
floating_ips, host, agent)
|
||||||
ports_to_populate = []
|
ports_to_populate = []
|
||||||
for router in routers_dict.values():
|
for router in routers_dict.values():
|
||||||
if router.get('gw_port'):
|
if router.get('gw_port'):
|
||||||
|
@ -711,12 +746,14 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
self._process_interfaces(routers_dict, interfaces)
|
self._process_interfaces(routers_dict, interfaces)
|
||||||
return list(routers_dict.values())
|
return list(routers_dict.values())
|
||||||
|
|
||||||
|
def _is_unbound_port(self, port):
|
||||||
|
"""Check for port-bindings irrespective of device_owner."""
|
||||||
|
return not port[portbindings.HOST_ID]
|
||||||
|
|
||||||
def _get_dvr_service_port_hostid(self, context, port_id, port=None):
|
def _get_dvr_service_port_hostid(self, context, port_id, port=None):
|
||||||
"""Returns the portbinding host_id for dvr service port."""
|
"""Returns the portbinding host_id for dvr service port."""
|
||||||
port_db = port or self._core_plugin.get_port(context, port_id)
|
port_db = port or self._core_plugin.get_port(context, port_id)
|
||||||
device_owner = port_db['device_owner'] if port_db else ""
|
return port_db[portbindings.HOST_ID] or None
|
||||||
if n_utils.is_dvr_serviced(device_owner):
|
|
||||||
return port_db[portbindings.HOST_ID]
|
|
||||||
|
|
||||||
def _get_dvr_migrating_service_port_hostid(
|
def _get_dvr_migrating_service_port_hostid(
|
||||||
self, context, port_id, port=None):
|
self, context, port_id, port=None):
|
||||||
|
@ -726,8 +763,6 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
port_dest_host = None
|
port_dest_host = None
|
||||||
if port_profile:
|
if port_profile:
|
||||||
port_dest_host = port_profile.get('migrating_to')
|
port_dest_host = port_profile.get('migrating_to')
|
||||||
device_owner = port_db['device_owner'] if port_db else ""
|
|
||||||
if n_utils.is_dvr_serviced(device_owner):
|
|
||||||
return port_dest_host
|
return port_dest_host
|
||||||
|
|
||||||
def _get_agent_gw_ports_exist_for_network(
|
def _get_agent_gw_ports_exist_for_network(
|
||||||
|
@ -814,11 +849,6 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
'subnet_id': subnet}
|
'subnet_id': subnet}
|
||||||
notifier(context, router_id, arp_table)
|
notifier(context, router_id, arp_table)
|
||||||
|
|
||||||
def _should_update_arp_entry_for_dvr_service_port(self, port_dict):
|
|
||||||
# Check this is a valid VM or service port
|
|
||||||
return (n_utils.is_dvr_serviced(port_dict['device_owner']) and
|
|
||||||
port_dict['fixed_ips'])
|
|
||||||
|
|
||||||
def _get_subnet_id_for_given_fixed_ip(
|
def _get_subnet_id_for_given_fixed_ip(
|
||||||
self, context, fixed_ip, port_dict):
|
self, context, fixed_ip, port_dict):
|
||||||
"""Returns the subnet_id that matches the fixedip on a network."""
|
"""Returns the subnet_id that matches the fixedip on a network."""
|
||||||
|
@ -855,9 +885,9 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
If there are any allowed_address_pairs associated with the port
|
If there are any allowed_address_pairs associated with the port
|
||||||
those fixed_ips should also be updated in the ARP table.
|
those fixed_ips should also be updated in the ARP table.
|
||||||
"""
|
"""
|
||||||
if not self._should_update_arp_entry_for_dvr_service_port(port_dict):
|
|
||||||
return
|
|
||||||
fixed_ips = port_dict['fixed_ips']
|
fixed_ips = port_dict['fixed_ips']
|
||||||
|
if not fixed_ips:
|
||||||
|
return
|
||||||
allowed_address_pair_fixed_ips = (
|
allowed_address_pair_fixed_ips = (
|
||||||
self._get_allowed_address_pair_fixed_ips(context, port_dict))
|
self._get_allowed_address_pair_fixed_ips(context, port_dict))
|
||||||
changed_fixed_ips = fixed_ips + allowed_address_pair_fixed_ips
|
changed_fixed_ips = fixed_ips + allowed_address_pair_fixed_ips
|
||||||
|
@ -876,10 +906,10 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
If there are any allowed_address_pairs associated with the
|
If there are any allowed_address_pairs associated with the
|
||||||
port, those fixed_ips should be removed from the ARP table.
|
port, those fixed_ips should be removed from the ARP table.
|
||||||
"""
|
"""
|
||||||
if not self._should_update_arp_entry_for_dvr_service_port(port_dict):
|
fixed_ips = port_dict['fixed_ips']
|
||||||
|
if not fixed_ips:
|
||||||
return
|
return
|
||||||
if not fixed_ips_to_delete:
|
if not fixed_ips_to_delete:
|
||||||
fixed_ips = port_dict['fixed_ips']
|
|
||||||
allowed_address_pair_fixed_ips = (
|
allowed_address_pair_fixed_ips = (
|
||||||
self._get_allowed_address_pair_fixed_ips(context, port_dict))
|
self._get_allowed_address_pair_fixed_ips(context, port_dict))
|
||||||
fixed_ips_to_delete = fixed_ips + allowed_address_pair_fixed_ips
|
fixed_ips_to_delete = fixed_ips + allowed_address_pair_fixed_ips
|
||||||
|
@ -900,65 +930,6 @@ class _DVRAgentInterfaceMixin(object):
|
||||||
return self._core_plugin.get_port(
|
return self._core_plugin.get_port(
|
||||||
context, fip.fixed_port_id) if fip else None
|
context, fip.fixed_port_id) if fip else None
|
||||||
|
|
||||||
def update_unbound_allowed_address_pair_port_binding(
|
|
||||||
self, context, service_port_dict,
|
|
||||||
port_address_pairs, address_pair_port=None):
|
|
||||||
"""Update allowed address pair port with host and device_owner
|
|
||||||
|
|
||||||
This function sets the host and device_owner to the port
|
|
||||||
associated with the port_addr_pair_ip with the port_dict's
|
|
||||||
host and device_owner.
|
|
||||||
"""
|
|
||||||
port_addr_pair_ip = port_address_pairs['ip_address']
|
|
||||||
if not address_pair_port:
|
|
||||||
address_pair_port = self._get_address_pair_active_port_with_fip(
|
|
||||||
context, service_port_dict, port_addr_pair_ip)
|
|
||||||
if address_pair_port:
|
|
||||||
host = service_port_dict[portbindings.HOST_ID]
|
|
||||||
dev_owner = service_port_dict['device_owner']
|
|
||||||
address_pair_dev_owner = address_pair_port.get('device_owner')
|
|
||||||
# If the allowed_address_pair port already has an associated
|
|
||||||
# device owner, and if the device_owner is a dvr serviceable
|
|
||||||
# port, then don't update the device_owner.
|
|
||||||
port_profile = address_pair_port.get(portbindings.PROFILE, {})
|
|
||||||
if n_utils.is_dvr_serviced(address_pair_dev_owner):
|
|
||||||
port_profile['original_owner'] = address_pair_dev_owner
|
|
||||||
port_data = {portbindings.HOST_ID: host,
|
|
||||||
portbindings.PROFILE: port_profile}
|
|
||||||
else:
|
|
||||||
port_data = {portbindings.HOST_ID: host,
|
|
||||||
'device_owner': dev_owner}
|
|
||||||
update_port = self._core_plugin.update_port(
|
|
||||||
context, address_pair_port['id'], {'port': port_data})
|
|
||||||
return update_port
|
|
||||||
|
|
||||||
def remove_unbound_allowed_address_pair_port_binding(
|
|
||||||
self, context, service_port_dict,
|
|
||||||
port_address_pairs, address_pair_port=None):
|
|
||||||
"""Remove allowed address pair port binding and device_owner
|
|
||||||
|
|
||||||
This function clears the host and device_owner associated with
|
|
||||||
the port_addr_pair_ip.
|
|
||||||
"""
|
|
||||||
port_addr_pair_ip = port_address_pairs['ip_address']
|
|
||||||
if not address_pair_port:
|
|
||||||
address_pair_port = self._get_address_pair_active_port_with_fip(
|
|
||||||
context, service_port_dict, port_addr_pair_ip)
|
|
||||||
if address_pair_port:
|
|
||||||
# Before reverting the changes, fetch the original
|
|
||||||
# device owner saved in profile and update the port
|
|
||||||
port_profile = address_pair_port.get(portbindings.PROFILE)
|
|
||||||
orig_device_owner = ""
|
|
||||||
if port_profile:
|
|
||||||
orig_device_owner = port_profile.get('original_owner')
|
|
||||||
del port_profile['original_owner']
|
|
||||||
port_data = {portbindings.HOST_ID: "",
|
|
||||||
'device_owner': orig_device_owner,
|
|
||||||
portbindings.PROFILE: port_profile}
|
|
||||||
update_port = self._core_plugin.update_port(
|
|
||||||
context, address_pair_port['id'], {'port': port_data})
|
|
||||||
return update_port
|
|
||||||
|
|
||||||
|
|
||||||
class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin,
|
class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin,
|
||||||
DVRResourceOperationHandler,
|
DVRResourceOperationHandler,
|
||||||
|
@ -1009,11 +980,14 @@ class L3_NAT_with_dvr_db_mixin(_DVRAgentInterfaceMixin,
|
||||||
host = self._get_dvr_service_port_hostid(context, fixed_port_id)
|
host = self._get_dvr_service_port_hostid(context, fixed_port_id)
|
||||||
dest_host = self._get_dvr_migrating_service_port_hostid(
|
dest_host = self._get_dvr_migrating_service_port_hostid(
|
||||||
context, fixed_port_id)
|
context, fixed_port_id)
|
||||||
self.l3_rpc_notifier.routers_updated_on_host(
|
if host is not None:
|
||||||
context, [router_id], host)
|
|
||||||
if dest_host and dest_host != host:
|
|
||||||
self.l3_rpc_notifier.routers_updated_on_host(
|
self.l3_rpc_notifier.routers_updated_on_host(
|
||||||
context, [router_id], dest_host)
|
context, [router_id], host)
|
||||||
|
if dest_host and dest_host != host:
|
||||||
|
self.l3_rpc_notifier.routers_updated_on_host(
|
||||||
|
context, [router_id], dest_host)
|
||||||
|
else:
|
||||||
|
self.notify_router_updated(context, router_id)
|
||||||
else:
|
else:
|
||||||
self.notify_router_updated(context, router_id)
|
self.notify_router_updated(context, router_id)
|
||||||
|
|
||||||
|
|
|
@ -343,22 +343,11 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
|
||||||
|
|
||||||
def _dvr_handle_unbound_allowed_addr_pair_add(
|
def _dvr_handle_unbound_allowed_addr_pair_add(
|
||||||
plugin, context, port, allowed_address_pair):
|
plugin, context, port, allowed_address_pair):
|
||||||
updated_port = plugin.update_unbound_allowed_address_pair_port_binding(
|
|
||||||
context, port, allowed_address_pair)
|
|
||||||
if updated_port:
|
|
||||||
LOG.debug("Allowed address pair port binding updated "
|
|
||||||
"based on service port binding: %s", updated_port)
|
|
||||||
plugin.dvr_handle_new_service_port(context, updated_port)
|
|
||||||
plugin.update_arp_entry_for_dvr_service_port(context, port)
|
plugin.update_arp_entry_for_dvr_service_port(context, port)
|
||||||
|
|
||||||
|
|
||||||
def _dvr_handle_unbound_allowed_addr_pair_del(
|
def _dvr_handle_unbound_allowed_addr_pair_del(
|
||||||
plugin, context, port, allowed_address_pair):
|
plugin, context, port, allowed_address_pair):
|
||||||
updated_port = plugin.remove_unbound_allowed_address_pair_port_binding(
|
|
||||||
context, port, allowed_address_pair)
|
|
||||||
if updated_port:
|
|
||||||
LOG.debug("Allowed address pair port binding removed "
|
|
||||||
"from service port binding: %s", updated_port)
|
|
||||||
aa_fixed_ips = plugin._get_allowed_address_pair_fixed_ips(context, port)
|
aa_fixed_ips = plugin._get_allowed_address_pair_fixed_ips(context, port)
|
||||||
if aa_fixed_ips:
|
if aa_fixed_ips:
|
||||||
plugin.delete_arp_entry_for_dvr_service_port(
|
plugin.delete_arp_entry_for_dvr_service_port(
|
||||||
|
|
|
@ -253,6 +253,13 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.subnet(cidr='20.0.0.0/24') as int_subnet,\
|
self.subnet(cidr='20.0.0.0/24') as int_subnet,\
|
||||||
self.port(subnet=int_subnet,
|
self.port(subnet=int_subnet,
|
||||||
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
||||||
|
self.core_plugin.update_port(
|
||||||
|
self.context, int_port['port']['id'],
|
||||||
|
{'port': {portbindings.HOST_ID: 'host1'}})
|
||||||
|
# and create l3 agents on corresponding hosts
|
||||||
|
helpers.register_l3_agent(host='host1',
|
||||||
|
agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
|
|
||||||
# make net external
|
# make net external
|
||||||
ext_net_id = ext_subnet['subnet']['network_id']
|
ext_net_id = ext_subnet['subnet']['network_id']
|
||||||
self._update('networks', ext_net_id,
|
self._update('networks', ext_net_id,
|
||||||
|
@ -279,7 +286,7 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
if dvr:
|
if dvr:
|
||||||
l3_notif.routers_updated_on_host.assert_called_once_with(
|
l3_notif.routers_updated_on_host.assert_called_once_with(
|
||||||
self.context, [router['id']],
|
self.context, [router['id']],
|
||||||
int_port['port'][portbindings.HOST_ID])
|
'host1')
|
||||||
self.assertFalse(l3_notif.routers_updated.called)
|
self.assertFalse(l3_notif.routers_updated.called)
|
||||||
else:
|
else:
|
||||||
l3_notif.routers_updated.assert_called_once_with(
|
l3_notif.routers_updated.assert_called_once_with(
|
||||||
|
@ -378,6 +385,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.subnet(cidr='20.0.0.0/24') as int_subnet,\
|
self.subnet(cidr='20.0.0.0/24') as int_subnet,\
|
||||||
self.port(subnet=int_subnet,
|
self.port(subnet=int_subnet,
|
||||||
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
||||||
|
self.core_plugin.update_port(
|
||||||
|
self.context, int_port['port']['id'],
|
||||||
|
{'port': {portbindings.HOST_ID: 'host1'}})
|
||||||
|
# and create l3 agents on corresponding hosts
|
||||||
|
helpers.register_l3_agent(host='host1',
|
||||||
|
agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
# make net external
|
# make net external
|
||||||
ext_net_id = ext_subnet['subnet']['network_id']
|
ext_net_id = ext_subnet['subnet']['network_id']
|
||||||
self._update('networks', ext_net_id,
|
self._update('networks', ext_net_id,
|
||||||
|
@ -406,7 +419,7 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
if dvr:
|
if dvr:
|
||||||
l3_notif.routers_updated_on_host.assert_called_once_with(
|
l3_notif.routers_updated_on_host.assert_called_once_with(
|
||||||
self.context, [router['id']],
|
self.context, [router['id']],
|
||||||
int_port['port'][portbindings.HOST_ID])
|
'host1')
|
||||||
self.assertFalse(l3_notif.routers_updated.called)
|
self.assertFalse(l3_notif.routers_updated.called)
|
||||||
else:
|
else:
|
||||||
l3_notif.routers_updated.assert_called_once_with(
|
l3_notif.routers_updated.assert_called_once_with(
|
||||||
|
@ -480,11 +493,14 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.assertEqual(1, len(snat_router_intfs[router1['id']]))
|
self.assertEqual(1, len(snat_router_intfs[router1['id']]))
|
||||||
self.assertEqual(1, len(fixed_ips))
|
self.assertEqual(1, len(fixed_ips))
|
||||||
|
|
||||||
def test_allowed_addr_pairs_arp_update_for_port_with_original_owner(self):
|
def test_unbound_allowed_addr_pairs_fip_with_multiple_active_vms(self):
|
||||||
HOST1 = 'host1'
|
HOST1 = 'host1'
|
||||||
helpers.register_l3_agent(
|
helpers.register_l3_agent(
|
||||||
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
router = self._create_router()
|
HOST2 = 'host2'
|
||||||
|
helpers.register_l3_agent(
|
||||||
|
host=HOST2, agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
|
router = self._create_router(ha=False)
|
||||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
private_net1 = self._make_network(self.fmt, 'net1', True)
|
||||||
test_allocation_pools = [{'start': '10.1.0.2',
|
test_allocation_pools = [{'start': '10.1.0.2',
|
||||||
'end': '10.1.0.20'}]
|
'end': '10.1.0.20'}]
|
||||||
|
@ -495,6 +511,10 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self._make_subnet(
|
self._make_subnet(
|
||||||
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
||||||
ip_version=4, enable_dhcp=True)
|
ip_version=4, enable_dhcp=True)
|
||||||
|
self.l3_plugin.schedule_router(self.context,
|
||||||
|
router['id'],
|
||||||
|
candidates=[self.l3_agent])
|
||||||
|
|
||||||
# Set gateway to router
|
# Set gateway to router
|
||||||
self.l3_plugin._update_router_gw_info(
|
self.l3_plugin._update_router_gw_info(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
|
@ -510,70 +530,80 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
vrrp_port = self._make_port(
|
vrrp_port = self._make_port(
|
||||||
self.fmt,
|
self.fmt,
|
||||||
private_net1['network']['id'],
|
private_net1['network']['id'],
|
||||||
device_owner=constants.DEVICE_OWNER_LOADBALANCER,
|
device_owner='',
|
||||||
fixed_ips=fixed_vrrp_ip)
|
fixed_ips=fixed_vrrp_ip)
|
||||||
allowed_address_pairs = [
|
allowed_address_pairs = [
|
||||||
{'ip_address': '10.1.0.201',
|
{'ip_address': '10.1.0.201',
|
||||||
'mac_address': vrrp_port['port']['mac_address']}]
|
'mac_address': vrrp_port['port']['mac_address']}]
|
||||||
with self.port(
|
with self.port(
|
||||||
subnet=private_subnet1,
|
subnet=private_subnet1,
|
||||||
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
device_owner=DEVICE_OWNER_COMPUTE) as int_port1,\
|
||||||
|
self.port(
|
||||||
|
subnet=private_subnet1,
|
||||||
|
device_owner=DEVICE_OWNER_COMPUTE) as int_port2:
|
||||||
self.l3_plugin.add_router_interface(
|
self.l3_plugin.add_router_interface(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
{'subnet_id': private_subnet1['subnet']['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,
|
with mock.patch.object(self.l3_plugin,
|
||||||
'_l3_rpc_notifier') as l3_notifier:
|
'_l3_rpc_notifier') as l3_notifier:
|
||||||
vm_port = self.core_plugin.update_port(
|
vm_port1 = self.core_plugin.update_port(
|
||||||
self.context, int_port['port']['id'],
|
self.context, int_port1['port']['id'],
|
||||||
{'port': {portbindings.HOST_ID: HOST1}})
|
{'port': {portbindings.HOST_ID: HOST1}})
|
||||||
l3_notifier.routers_updated_on_host.assert_called_once_with(
|
vm_port2 = self.core_plugin.update_port(
|
||||||
self.context, {router['id']}, HOST1)
|
self.context, int_port2['port']['id'],
|
||||||
self.assertEqual(1, l3_notifier.add_arp_entry.call_count)
|
{'port': {portbindings.HOST_ID: HOST2}})
|
||||||
l3_notifier.reset_mock()
|
vrrp_port_db = self.core_plugin.get_port(
|
||||||
|
self.context, vrrp_port['port']['id'])
|
||||||
|
# Make sure that the VRRP port is not bound to any host
|
||||||
|
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
|
||||||
|
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST2)
|
||||||
|
self.assertNotEqual(
|
||||||
|
vrrp_port_db[portbindings.HOST_ID], self.l3_agent['host'])
|
||||||
|
# Now update both the VM ports with the allowed_address_pair ip
|
||||||
|
self.core_plugin.update_port(
|
||||||
|
self.context, vm_port1['id'],
|
||||||
|
{'port': {
|
||||||
|
'allowed_address_pairs': allowed_address_pairs}})
|
||||||
|
updated_vm_port1 = self.core_plugin.get_port(
|
||||||
|
self.context, vm_port1['id'])
|
||||||
|
expected_allowed_address_pairs1 = updated_vm_port1.get(
|
||||||
|
'allowed_address_pairs')
|
||||||
|
self.assertEqual(expected_allowed_address_pairs1,
|
||||||
|
allowed_address_pairs)
|
||||||
|
self.core_plugin.update_port(
|
||||||
|
self.context, vm_port2['id'],
|
||||||
|
{'port': {
|
||||||
|
'allowed_address_pairs': allowed_address_pairs}})
|
||||||
|
updated_vm_port2 = self.core_plugin.get_port(
|
||||||
|
self.context, vm_port2['id'])
|
||||||
|
expected_allowed_address_pairs2 = updated_vm_port2.get(
|
||||||
|
'allowed_address_pairs')
|
||||||
|
self.assertEqual(expected_allowed_address_pairs2,
|
||||||
|
allowed_address_pairs)
|
||||||
|
# Now let us assign the floatingip to the vrrp port that is
|
||||||
|
# unbound to any host.
|
||||||
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
||||||
'router_id': router['id'],
|
'router_id': router['id'],
|
||||||
'port_id': vrrp_port['port']['id'],
|
'port_id': vrrp_port['port']['id'],
|
||||||
'tenant_id': vrrp_port['port']['tenant_id']}
|
'tenant_id': vrrp_port['port']['tenant_id']}
|
||||||
floating_ip = self.l3_plugin.create_floatingip(
|
floating_ip = self.l3_plugin.create_floatingip(
|
||||||
self.context, {'floatingip': floating_ip})
|
self.context, {'floatingip': floating_ip})
|
||||||
vrrp_port_db = self.core_plugin.get_port(
|
expected_routers_updated_calls = [
|
||||||
self.context, vrrp_port['port']['id'])
|
mock.call(self.context, mock.ANY, HOST1),
|
||||||
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
|
mock.call(self.context, mock.ANY, HOST2)]
|
||||||
# Now update the VM port with the allowed_address_pair
|
l3_notifier.routers_updated_on_host.assert_has_calls(
|
||||||
l3_notifier.reset_mock()
|
expected_routers_updated_calls)
|
||||||
self.core_plugin.update_port(
|
self.assertTrue(l3_notifier.routers_updated.called)
|
||||||
self.context, vm_port['id'],
|
router_info = (
|
||||||
{'port': {
|
self.l3_plugin.list_active_sync_routers_on_active_l3_agent(
|
||||||
'allowed_address_pairs': allowed_address_pairs}})
|
self.context, self.l3_agent['host'], [router['id']]))
|
||||||
updated_vm_port = self.core_plugin.get_port(
|
floatingips = router_info[0][constants.FLOATINGIP_KEY]
|
||||||
self.context, vm_port['id'])
|
self.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND])
|
||||||
expected_allowed_address_pairs = updated_vm_port.get(
|
|
||||||
'allowed_address_pairs')
|
|
||||||
self.assertEqual(expected_allowed_address_pairs,
|
|
||||||
allowed_address_pairs)
|
|
||||||
cur_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, vrrp_port['port']['id'])
|
|
||||||
self.assertEqual(cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
self.assertTrue(cur_vrrp_port_db.get(portbindings.PROFILE))
|
|
||||||
port_profile = cur_vrrp_port_db.get(portbindings.PROFILE)
|
|
||||||
self.assertTrue(port_profile)
|
|
||||||
self.assertEqual(port_profile['original_owner'],
|
|
||||||
constants.DEVICE_OWNER_LOADBALANCER)
|
|
||||||
l3_notifier.reset_mock()
|
|
||||||
port_profile['new_owner'] = 'test_owner'
|
|
||||||
self.core_plugin.update_port(
|
|
||||||
self.context, cur_vrrp_port_db['id'],
|
|
||||||
{'port': {portbindings.PROFILE: port_profile}})
|
|
||||||
# Now the vrrp port should have an 'original_owner'
|
|
||||||
# and gets updated with a new profile. In this case
|
|
||||||
# the update triggers a notification to the neutron
|
|
||||||
# server, but this should not trigger another arp
|
|
||||||
# update of this port or router_updated event to the
|
|
||||||
# agent, otherwise this will mess up with the arp
|
|
||||||
# table in the router namespace.
|
|
||||||
self.assertEqual(0, l3_notifier.add_arp_entry.call_count)
|
|
||||||
self.assertEqual(
|
|
||||||
0, l3_notifier.routers_updated_on_host.call_count)
|
|
||||||
|
|
||||||
def test_allowed_addr_pairs_delayed_fip_and_update_arp_entry(self):
|
def test_allowed_addr_pairs_delayed_fip_and_update_arp_entry(self):
|
||||||
HOST1 = 'host1'
|
HOST1 = 'host1'
|
||||||
|
@ -582,7 +612,7 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
HOST2 = 'host2'
|
HOST2 = 'host2'
|
||||||
helpers.register_l3_agent(
|
helpers.register_l3_agent(
|
||||||
host=HOST2, agent_mode=constants.L3_AGENT_MODE_DVR)
|
host=HOST2, agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
router = self._create_router()
|
router = self._create_router(ha=False)
|
||||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
private_net1 = self._make_network(self.fmt, 'net1', True)
|
||||||
test_allocation_pools = [{'start': '10.1.0.2',
|
test_allocation_pools = [{'start': '10.1.0.2',
|
||||||
'end': '10.1.0.20'}]
|
'end': '10.1.0.20'}]
|
||||||
|
@ -593,6 +623,10 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self._make_subnet(
|
self._make_subnet(
|
||||||
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
||||||
ip_version=4, enable_dhcp=True)
|
ip_version=4, enable_dhcp=True)
|
||||||
|
self.l3_plugin.schedule_router(self.context,
|
||||||
|
router['id'],
|
||||||
|
candidates=[self.l3_agent])
|
||||||
|
|
||||||
# Set gateway to router
|
# Set gateway to router
|
||||||
self.l3_plugin._update_router_gw_info(
|
self.l3_plugin._update_router_gw_info(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
|
@ -620,6 +654,11 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.l3_plugin.add_router_interface(
|
self.l3_plugin.add_router_interface(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
{'subnet_id': private_subnet1['subnet']['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,
|
with mock.patch.object(self.l3_plugin,
|
||||||
'_l3_rpc_notifier') as l3_notifier:
|
'_l3_rpc_notifier') as l3_notifier:
|
||||||
vm_port = self.core_plugin.update_port(
|
vm_port = self.core_plugin.update_port(
|
||||||
|
@ -635,7 +674,6 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
vm_port2 = self.core_plugin.update_port(
|
vm_port2 = self.core_plugin.update_port(
|
||||||
self.context, int_port2['port']['id'],
|
self.context, int_port2['port']['id'],
|
||||||
{'port': {portbindings.HOST_ID: HOST2}})
|
{'port': {portbindings.HOST_ID: HOST2}})
|
||||||
l3_notifier.reset_mock()
|
|
||||||
# Now update the VM port with the allowed_address_pair
|
# Now update the VM port with the allowed_address_pair
|
||||||
self.core_plugin.update_port(
|
self.core_plugin.update_port(
|
||||||
self.context, vm_port['id'],
|
self.context, vm_port['id'],
|
||||||
|
@ -646,12 +684,11 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
{'port': {
|
{'port': {
|
||||||
'allowed_address_pairs': allowed_address_pairs}})
|
'allowed_address_pairs': allowed_address_pairs}})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
0, l3_notifier.routers_updated_on_host.call_count)
|
2, l3_notifier.routers_updated_on_host.call_count)
|
||||||
updated_vm_port1 = self.core_plugin.get_port(
|
updated_vm_port1 = self.core_plugin.get_port(
|
||||||
self.context, vm_port['id'])
|
self.context, vm_port['id'])
|
||||||
updated_vm_port2 = self.core_plugin.get_port(
|
updated_vm_port2 = self.core_plugin.get_port(
|
||||||
self.context, vm_port2['id'])
|
self.context, vm_port2['id'])
|
||||||
self.assertEqual(4, l3_notifier.add_arp_entry.call_count)
|
|
||||||
expected_allowed_address_pairs = updated_vm_port1.get(
|
expected_allowed_address_pairs = updated_vm_port1.get(
|
||||||
'allowed_address_pairs')
|
'allowed_address_pairs')
|
||||||
self.assertEqual(expected_allowed_address_pairs,
|
self.assertEqual(expected_allowed_address_pairs,
|
||||||
|
@ -669,52 +706,42 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
cur_vrrp_port_db[portbindings.HOST_ID], HOST2)
|
cur_vrrp_port_db[portbindings.HOST_ID], HOST2)
|
||||||
# Before we try to associate a floatingip make sure that
|
|
||||||
# only one of the Service port associated with the
|
|
||||||
# allowed_address_pair port is active and the other one
|
|
||||||
# is DOWN
|
|
||||||
mod_vm_port2 = self.core_plugin.update_port(
|
|
||||||
self.context, updated_vm_port2['id'],
|
|
||||||
{'port': {
|
|
||||||
'admin_state_up': False}})
|
|
||||||
self.assertFalse(mod_vm_port2['admin_state_up'])
|
|
||||||
# Next we can try to associate the floatingip to the
|
# Next we can try to associate the floatingip to the
|
||||||
# VRRP port that is already attached to the VM port
|
# VRRP port that is already attached to the VM port
|
||||||
l3_notifier.reset_mock()
|
|
||||||
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
||||||
'router_id': router['id'],
|
'router_id': router['id'],
|
||||||
'port_id': vrrp_port['port']['id'],
|
'port_id': vrrp_port['port']['id'],
|
||||||
'tenant_id': vrrp_port['port']['tenant_id']}
|
'tenant_id': vrrp_port['port']['tenant_id']}
|
||||||
floating_ip = self.l3_plugin.create_floatingip(
|
floating_ip = self.l3_plugin.create_floatingip(
|
||||||
self.context, {'floatingip': floating_ip})
|
self.context, {'floatingip': floating_ip})
|
||||||
self.assertEqual(
|
|
||||||
2, l3_notifier.routers_updated_on_host.call_count)
|
|
||||||
self.assertEqual(3, l3_notifier.add_arp_entry.call_count)
|
|
||||||
|
|
||||||
post_update_vrrp_port_db = self.core_plugin.get_port(
|
post_update_vrrp_port_db = self.core_plugin.get_port(
|
||||||
self.context, vrrp_port['port']['id'])
|
self.context, vrrp_port['port']['id'])
|
||||||
vrrp_port_fixed_ips = post_update_vrrp_port_db['fixed_ips']
|
vrrp_port_fixed_ips = post_update_vrrp_port_db['fixed_ips']
|
||||||
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
|
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
|
||||||
vrrp_arp_table = {
|
vrrp_arp_table1 = {
|
||||||
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
||||||
'mac_address': vm_port_mac,
|
'mac_address': vm_port_mac,
|
||||||
'subnet_id': vrrp_port_subnet_id}
|
'subnet_id': vrrp_port_subnet_id}
|
||||||
vrrp_arp_table1 = {
|
|
||||||
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
|
||||||
'mac_address': vrrp_port['port']['mac_address'],
|
|
||||||
'subnet_id': vrrp_port_subnet_id}
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
post_update_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
mock.call(self.context,
|
|
||||||
router['id'], vrrp_arp_table1),
|
|
||||||
mock.call(self.context,
|
mock.call(self.context,
|
||||||
router['id'], vm_arp_table),
|
router['id'], vm_arp_table),
|
||||||
mock.call(self.context,
|
mock.call(self.context,
|
||||||
router['id'], vrrp_arp_table)]
|
router['id'], vrrp_arp_table1)]
|
||||||
l3_notifier.add_arp_entry.assert_has_calls(
|
l3_notifier.add_arp_entry.assert_has_calls(
|
||||||
expected_calls)
|
expected_calls)
|
||||||
|
expected_routers_updated_calls = [
|
||||||
|
mock.call(self.context, mock.ANY, HOST1),
|
||||||
|
mock.call(self.context, mock.ANY, HOST2)]
|
||||||
|
l3_notifier.routers_updated_on_host.assert_has_calls(
|
||||||
|
expected_routers_updated_calls)
|
||||||
|
self.assertTrue(l3_notifier.routers_updated.called)
|
||||||
|
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.assertTrue(floatingips[0][n_const.DVR_SNAT_BOUND])
|
||||||
|
|
||||||
def test_dvr_gateway_host_binding_is_set(self):
|
def test_dvr_gateway_host_binding_is_set(self):
|
||||||
router = self._create_router(ha=False)
|
router = self._create_router(ha=False)
|
||||||
|
@ -754,7 +781,7 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
HOST1 = 'host1'
|
HOST1 = 'host1'
|
||||||
helpers.register_l3_agent(
|
helpers.register_l3_agent(
|
||||||
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
||||||
router = self._create_router()
|
router = self._create_router(ha=False)
|
||||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
private_net1 = self._make_network(self.fmt, 'net1', True)
|
||||||
test_allocation_pools = [{'start': '10.1.0.2',
|
test_allocation_pools = [{'start': '10.1.0.2',
|
||||||
'end': '10.1.0.20'}]
|
'end': '10.1.0.20'}]
|
||||||
|
@ -765,6 +792,9 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self._make_subnet(
|
self._make_subnet(
|
||||||
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
self.fmt, ext_net, '10.20.0.1', '10.20.0.0/24',
|
||||||
ip_version=4, enable_dhcp=True)
|
ip_version=4, enable_dhcp=True)
|
||||||
|
self.l3_plugin.schedule_router(self.context,
|
||||||
|
router['id'],
|
||||||
|
candidates=[self.l3_agent])
|
||||||
# Set gateway to router
|
# Set gateway to router
|
||||||
self.l3_plugin._update_router_gw_info(
|
self.l3_plugin._update_router_gw_info(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
|
@ -790,6 +820,11 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.l3_plugin.add_router_interface(
|
self.l3_plugin.add_router_interface(
|
||||||
self.context, router['id'],
|
self.context, router['id'],
|
||||||
{'subnet_id': private_subnet1['subnet']['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,
|
with mock.patch.object(self.l3_plugin,
|
||||||
'_l3_rpc_notifier') as l3_notifier:
|
'_l3_rpc_notifier') as l3_notifier:
|
||||||
vm_port = self.core_plugin.update_port(
|
vm_port = self.core_plugin.update_port(
|
||||||
|
@ -802,12 +837,7 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
'ip_address': vm_port_fixed_ips[0]['ip_address'],
|
'ip_address': vm_port_fixed_ips[0]['ip_address'],
|
||||||
'mac_address': vm_port_mac,
|
'mac_address': vm_port_mac,
|
||||||
'subnet_id': vm_port_subnet_id}
|
'subnet_id': vm_port_subnet_id}
|
||||||
|
|
||||||
l3_notifier.routers_updated_on_host.assert_called_once_with(
|
|
||||||
self.context, {router['id']}, HOST1)
|
|
||||||
|
|
||||||
self.assertEqual(1, l3_notifier.add_arp_entry.call_count)
|
self.assertEqual(1, l3_notifier.add_arp_entry.call_count)
|
||||||
l3_notifier.reset_mock()
|
|
||||||
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
||||||
'router_id': router['id'],
|
'router_id': router['id'],
|
||||||
'port_id': vrrp_port['port']['id'],
|
'port_id': vrrp_port['port']['id'],
|
||||||
|
@ -818,16 +848,12 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.context, vrrp_port['port']['id'])
|
self.context, vrrp_port['port']['id'])
|
||||||
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
|
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
|
||||||
# Now update the VM port with the allowed_address_pair
|
# Now update the VM port with the allowed_address_pair
|
||||||
l3_notifier.reset_mock()
|
|
||||||
self.core_plugin.update_port(
|
self.core_plugin.update_port(
|
||||||
self.context, vm_port['id'],
|
self.context, vm_port['id'],
|
||||||
{'port': {
|
{'port': {
|
||||||
'allowed_address_pairs': allowed_address_pairs}})
|
'allowed_address_pairs': allowed_address_pairs}})
|
||||||
self.assertEqual(
|
|
||||||
2, l3_notifier.routers_updated_on_host.call_count)
|
|
||||||
updated_vm_port = self.core_plugin.get_port(
|
updated_vm_port = self.core_plugin.get_port(
|
||||||
self.context, vm_port['id'])
|
self.context, vm_port['id'])
|
||||||
self.assertEqual(3, l3_notifier.add_arp_entry.call_count)
|
|
||||||
expected_allowed_address_pairs = updated_vm_port.get(
|
expected_allowed_address_pairs = updated_vm_port.get(
|
||||||
'allowed_address_pairs')
|
'allowed_address_pairs')
|
||||||
self.assertEqual(expected_allowed_address_pairs,
|
self.assertEqual(expected_allowed_address_pairs,
|
||||||
|
@ -836,163 +862,23 @@ class L3DvrTestCase(L3DvrTestCaseBase):
|
||||||
self.context, vrrp_port['port']['id'])
|
self.context, vrrp_port['port']['id'])
|
||||||
vrrp_port_fixed_ips = cur_vrrp_port_db['fixed_ips']
|
vrrp_port_fixed_ips = cur_vrrp_port_db['fixed_ips']
|
||||||
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
|
vrrp_port_subnet_id = vrrp_port_fixed_ips[0]['subnet_id']
|
||||||
vrrp_arp_table = {
|
vrrp_arp_table1 = {
|
||||||
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
||||||
'mac_address': vm_port_mac,
|
'mac_address': vm_port_mac,
|
||||||
'subnet_id': vrrp_port_subnet_id}
|
'subnet_id': vrrp_port_subnet_id}
|
||||||
vrrp_arp_table1 = {
|
|
||||||
'ip_address': vrrp_port_fixed_ips[0]['ip_address'],
|
|
||||||
'mac_address': vrrp_port['port']['mac_address'],
|
|
||||||
'subnet_id': vrrp_port_subnet_id}
|
|
||||||
|
|
||||||
self.assertEqual(cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
mock.call(self.context,
|
|
||||||
router['id'], vrrp_arp_table1),
|
|
||||||
mock.call(self.context,
|
mock.call(self.context,
|
||||||
router['id'], vm_arp_table),
|
router['id'], vm_arp_table),
|
||||||
mock.call(self.context,
|
mock.call(self.context,
|
||||||
router['id'], vrrp_arp_table)]
|
router['id'], vrrp_arp_table1)]
|
||||||
l3_notifier.add_arp_entry.assert_has_calls(
|
l3_notifier.add_arp_entry.assert_has_calls(
|
||||||
expected_calls)
|
expected_calls)
|
||||||
|
expected_routers_updated_calls = [
|
||||||
def test_update_service_port_with_allowed_address_pairs(self):
|
mock.call(self.context, mock.ANY, HOST1)]
|
||||||
HOST1 = 'host1'
|
l3_notifier.routers_updated_on_host.assert_has_calls(
|
||||||
helpers.register_l3_agent(
|
expected_routers_updated_calls)
|
||||||
host=HOST1, agent_mode=constants.L3_AGENT_MODE_DVR)
|
self.assertTrue(l3_notifier.routers_updated.called)
|
||||||
router = self._create_router()
|
|
||||||
private_net1 = self._make_network(self.fmt, 'net1', True)
|
|
||||||
test_allocation_pools = [{'start': '10.1.0.2',
|
|
||||||
'end': '10.1.0.20'}]
|
|
||||||
fixed_vrrp_ip = [{'ip_address': '10.1.0.201'}]
|
|
||||||
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)
|
|
||||||
# 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,
|
|
||||||
allocation_pools=test_allocation_pools,
|
|
||||||
enable_dhcp=True)
|
|
||||||
vrrp_port = self._make_port(
|
|
||||||
self.fmt,
|
|
||||||
private_net1['network']['id'],
|
|
||||||
device_owner=constants.DEVICE_OWNER_LOADBALANCER,
|
|
||||||
fixed_ips=fixed_vrrp_ip)
|
|
||||||
allowed_address_pairs = [
|
|
||||||
{'ip_address': '10.1.0.201',
|
|
||||||
'mac_address': vrrp_port['port']['mac_address']}]
|
|
||||||
with self.port(
|
|
||||||
subnet=private_subnet1,
|
|
||||||
device_owner=DEVICE_OWNER_COMPUTE) as int_port:
|
|
||||||
self.l3_plugin.add_router_interface(
|
|
||||||
self.context, router['id'],
|
|
||||||
{'subnet_id': private_subnet1['subnet']['id']})
|
|
||||||
with mock.patch.object(self.l3_plugin,
|
|
||||||
'_l3_rpc_notifier') as l3_notifier:
|
|
||||||
self.core_plugin.update_port(
|
|
||||||
self.context, int_port['port']['id'],
|
|
||||||
{'port': {portbindings.HOST_ID: HOST1}})
|
|
||||||
|
|
||||||
l3_notifier.routers_updated_on_host.assert_called_once_with(
|
|
||||||
self.context, {router['id']}, HOST1)
|
|
||||||
|
|
||||||
floating_ip = {'floating_network_id': ext_net['network']['id'],
|
|
||||||
'router_id': router['id'],
|
|
||||||
'port_id': vrrp_port['port']['id'],
|
|
||||||
'tenant_id': vrrp_port['port']['tenant_id']}
|
|
||||||
floating_ip = self.l3_plugin.create_floatingip(
|
|
||||||
self.context, {'floatingip': floating_ip})
|
|
||||||
|
|
||||||
vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, vrrp_port['port']['id'])
|
|
||||||
self.assertNotEqual(vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
# Now update the VM port with the allowed_address_pair
|
|
||||||
cur_int_port = self.core_plugin.update_port(
|
|
||||||
self.context, int_port['port']['id'],
|
|
||||||
{'port': {
|
|
||||||
'allowed_address_pairs': allowed_address_pairs}})
|
|
||||||
cur_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, vrrp_port['port']['id'])
|
|
||||||
# Check to make sure that we are not chaning the existing
|
|
||||||
# device_owner for the allowed_address_pair port.
|
|
||||||
self.assertEqual(
|
|
||||||
cur_vrrp_port_db['device_owner'],
|
|
||||||
constants.DEVICE_OWNER_LOADBALANCER)
|
|
||||||
self.assertEqual(cur_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
self.assertTrue(cur_vrrp_port_db.get(portbindings.PROFILE))
|
|
||||||
port_profile = cur_vrrp_port_db.get(portbindings.PROFILE)
|
|
||||||
self.assertTrue(port_profile)
|
|
||||||
self.assertEqual(port_profile['original_owner'],
|
|
||||||
constants.DEVICE_OWNER_LOADBALANCER)
|
|
||||||
# Now change the compute port admin_state_up from True to
|
|
||||||
# False, and see if the vrrp ports device_owner and binding
|
|
||||||
# inheritance reverts back to normal
|
|
||||||
mod_int_port = self.core_plugin.update_port(
|
|
||||||
self.context, cur_int_port['id'],
|
|
||||||
{'port': {
|
|
||||||
'admin_state_up': False}})
|
|
||||||
self.assertFalse(mod_int_port['admin_state_up'])
|
|
||||||
new_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, cur_vrrp_port_db['id'])
|
|
||||||
new_port_profile = new_vrrp_port_db.get(portbindings.PROFILE)
|
|
||||||
self.assertEqual({}, new_port_profile)
|
|
||||||
self.assertNotEqual(
|
|
||||||
new_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
# Now change the compute port admin_state_up from False to
|
|
||||||
# True, and see if the vrrp ports device_owner and binding
|
|
||||||
# inherits from the associated parent compute port.
|
|
||||||
new_mod_int_port = self.core_plugin.update_port(
|
|
||||||
self.context, mod_int_port['id'],
|
|
||||||
{'port': {
|
|
||||||
'admin_state_up': True}})
|
|
||||||
self.assertTrue(new_mod_int_port['admin_state_up'])
|
|
||||||
cur_new_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, new_vrrp_port_db['id'])
|
|
||||||
self.assertNotEqual(
|
|
||||||
cur_new_vrrp_port_db['device_owner'], DEVICE_OWNER_COMPUTE)
|
|
||||||
self.assertEqual(
|
|
||||||
cur_new_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
# Now let us try to remove vrrp_port device_owner and see
|
|
||||||
# how it inherits from the compute port.
|
|
||||||
updated_vrrp_port = self.core_plugin.update_port(
|
|
||||||
self.context, cur_new_vrrp_port_db['id'],
|
|
||||||
{'port': {'device_owner': "",
|
|
||||||
portbindings.PROFILE: {'original_owner': ""}}})
|
|
||||||
updated_vm_port = self.core_plugin.update_port(
|
|
||||||
self.context, new_mod_int_port['id'],
|
|
||||||
{'port': {
|
|
||||||
'admin_state_up': False}})
|
|
||||||
self.assertFalse(updated_vm_port['admin_state_up'])
|
|
||||||
# This port admin_state down should not cause any issue
|
|
||||||
# with the existing vrrp port device_owner, but should
|
|
||||||
# only change the port_binding HOST_ID.
|
|
||||||
cur_new_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, updated_vrrp_port['id'])
|
|
||||||
self.assertEqual(
|
|
||||||
"", cur_new_vrrp_port_db['device_owner'])
|
|
||||||
self.assertEqual(
|
|
||||||
"", cur_new_vrrp_port_db[portbindings.HOST_ID])
|
|
||||||
updated_vm_port = self.core_plugin.update_port(
|
|
||||||
self.context, new_mod_int_port['id'],
|
|
||||||
{'port': {
|
|
||||||
'admin_state_up': True}})
|
|
||||||
self.assertTrue(updated_vm_port['admin_state_up'])
|
|
||||||
updated_vrrp_port_db = self.core_plugin.get_port(
|
|
||||||
self.context, new_vrrp_port_db['id'])
|
|
||||||
self.assertEqual(
|
|
||||||
updated_vrrp_port_db['device_owner'], DEVICE_OWNER_COMPUTE)
|
|
||||||
self.assertEqual(
|
|
||||||
updated_vrrp_port_db[portbindings.HOST_ID], HOST1)
|
|
||||||
|
|
||||||
def test_update_vm_port_host_router_update(self):
|
def test_update_vm_port_host_router_update(self):
|
||||||
# register l3 agents in dvr mode in addition to existing dvr_snat agent
|
# register l3 agents in dvr mode in addition to existing dvr_snat agent
|
||||||
|
|
|
@ -382,8 +382,10 @@ class L3DvrTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||||
return_value=fipagent)
|
return_value=fipagent)
|
||||||
self.mixin._get_fip_agent_gw_ports = mock.Mock(
|
self.mixin._get_fip_agent_gw_ports = mock.Mock(
|
||||||
return_value='fip_interface')
|
return_value='fip_interface')
|
||||||
|
agent = mock.Mock()
|
||||||
|
agent.id = fipagent['id']
|
||||||
self.mixin._process_floating_ips_dvr(self.ctx, routers, [floatingip],
|
self.mixin._process_floating_ips_dvr(self.ctx, routers, [floatingip],
|
||||||
hostid)
|
hostid, agent)
|
||||||
return (router, floatingip)
|
return (router, floatingip)
|
||||||
|
|
||||||
def test_floatingip_on_port_not_host(self):
|
def test_floatingip_on_port_not_host(self):
|
||||||
|
|
|
@ -827,21 +827,12 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
port = kwargs.get('original_port')
|
port = kwargs.get('original_port')
|
||||||
port_addr_pairs = port['allowed_address_pairs']
|
|
||||||
l3plugin = mock.Mock()
|
l3plugin = mock.Mock()
|
||||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||||
'port', 'after_update', mock.ANY, **kwargs)
|
'port', 'after_update', mock.ANY, **kwargs)
|
||||||
l3plugin._get_allowed_address_pair_fixed_ips.return_value = (
|
l3plugin._get_allowed_address_pair_fixed_ips.return_value = (
|
||||||
['10.1.0.21'])
|
['10.1.0.21'])
|
||||||
self.assertTrue(
|
|
||||||
l3plugin.remove_unbound_allowed_address_pair_port_binding.
|
|
||||||
called)
|
|
||||||
l3plugin.remove_unbound_allowed_address_pair_port_binding.\
|
|
||||||
assert_called_once_with(
|
|
||||||
self.adminContext,
|
|
||||||
port,
|
|
||||||
port_addr_pairs[0])
|
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
||||||
l3plugin.delete_arp_entry_for_dvr_service_port.\
|
l3plugin.delete_arp_entry_for_dvr_service_port.\
|
||||||
|
@ -849,7 +840,6 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase):
|
||||||
self.adminContext,
|
self.adminContext,
|
||||||
port,
|
port,
|
||||||
fixed_ips_to_delete=mock.ANY)
|
fixed_ips_to_delete=mock.ANY)
|
||||||
self.assertFalse(l3plugin.dvr_handle_new_service_port.called)
|
|
||||||
|
|
||||||
def test__notify_l3_agent_update_port_with_allowed_address_pairs(self):
|
def test__notify_l3_agent_update_port_with_allowed_address_pairs(self):
|
||||||
port_id = uuidutils.generate_uuid()
|
port_id = uuidutils.generate_uuid()
|
||||||
|
@ -873,23 +863,12 @@ class L3DvrSchedulerTestCase(testlib_api.SqlTestCase):
|
||||||
'admin_state_up': True,
|
'admin_state_up': True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
port = kwargs.get('port')
|
|
||||||
port_addr_pairs = port['allowed_address_pairs']
|
|
||||||
l3plugin = mock.Mock()
|
l3plugin = mock.Mock()
|
||||||
directory.add_plugin(plugin_constants.L3, l3plugin)
|
directory.add_plugin(plugin_constants.L3, l3plugin)
|
||||||
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
l3_dvrscheduler_db._notify_l3_agent_port_update(
|
||||||
'port', 'after_update', mock.ANY, **kwargs)
|
'port', 'after_update', mock.ANY, **kwargs)
|
||||||
self.assertTrue(
|
|
||||||
l3plugin.update_unbound_allowed_address_pair_port_binding.
|
|
||||||
called)
|
|
||||||
l3plugin.update_unbound_allowed_address_pair_port_binding.\
|
|
||||||
assert_called_once_with(
|
|
||||||
self.adminContext,
|
|
||||||
port,
|
|
||||||
port_addr_pairs[0])
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
l3plugin.update_arp_entry_for_dvr_service_port.called)
|
||||||
self.assertTrue(l3plugin.dvr_handle_new_service_port.called)
|
|
||||||
|
|
||||||
def test__notify_l3_agent_update_port_no_removing_routers(self):
|
def test__notify_l3_agent_update_port_no_removing_routers(self):
|
||||||
port_id = 'fake-port'
|
port_id = 'fake-port'
|
||||||
|
|
Loading…
Reference in New Issue