Merge "Move Floating IP processing to Router classes"

This commit is contained in:
Jenkins 2015-02-22 06:11:26 +00:00 committed by Gerrit Code Review
commit f7a00bcd79
11 changed files with 646 additions and 410 deletions

View File

@ -362,6 +362,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
}
if router.get('distributed'):
kwargs['host'] = self.host
return dvr_router.DvrRouter(*args, **kwargs)
if router.get('ha'):
@ -471,7 +472,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
prefix=INTERNAL_DEV_PREFIX)
def _process_external_gateway(self, ri):
ex_gw_port = self._get_ex_gw_port(ri)
ex_gw_port = ri.get_ex_gw_port()
ex_gw_port_id = (ex_gw_port and ex_gw_port['id'] or
ri.ex_gw_port and ri.ex_gw_port['id'])
@ -515,29 +516,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
ri.perform_snat_action(self._handle_router_snat_rules,
interface_name)
def _put_fips_in_error_state(self, ri):
fip_statuses = {}
for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
return fip_statuses
def _process_snat_dnat_for_fip(self, ri):
try:
self.process_router_floating_ip_nat_rules(ri)
except Exception:
# TODO(salv-orlando): Less broad catching
raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
'NAT for floating IPs')
def _configure_fip_addresses(self, ri, interface_name):
try:
return self.process_router_floating_ip_addresses(
ri, interface_name)
except Exception:
# TODO(salv-orlando): Less broad catching
raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
'floating IPs')
def _update_fip_statuses(self, ri, existing_floating_ips, fip_statuses):
# Identify floating IPs which were disabled
ri.floating_ips = set(fip_statuses.keys())
@ -558,7 +536,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
try:
with ri.iptables_manager.defer_apply():
self._process_external_gateway(ri)
ex_gw_port = self._get_ex_gw_port(ri)
ex_gw_port = ri.get_ex_gw_port()
# TODO(Carl) Return after setting existing_floating_ips and
# still call _update_fip_statuses?
if not ex_gw_port:
@ -568,19 +546,19 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
existing_floating_ips = ri.floating_ips
if ri.router['distributed']:
self.create_dvr_fip_interfaces(ri, ex_gw_port)
self._process_snat_dnat_for_fip(ri)
ri.process_snat_dnat_for_fip()
# Once NAT rules for floating IPs are safely in place
# configure their addresses on the external gateway port
interface_name = self._get_external_device_interface_name(
ri, ex_gw_port)
fip_statuses = self._configure_fip_addresses(ri, interface_name)
fip_statuses = ri.configure_fip_addresses(interface_name)
except (n_exc.FloatingIpSetupException,
n_exc.IpTablesApplyException) as e:
# All floating IPs must be put in error state
LOG.exception(e)
fip_statuses = self._put_fips_in_error_state(ri)
fip_statuses = ri.put_fips_in_error_state()
self._update_fip_statuses(ri, existing_floating_ips, fip_statuses)
@ -589,7 +567,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
# TODO(mrsmith) - we shouldn't need to check here
if 'distributed' not in ri.router:
ri.router['distributed'] = False
ex_gw_port = self._get_ex_gw_port(ri)
ex_gw_port = ri.get_ex_gw_port()
if ri.router.get('distributed') and ex_gw_port:
ri.fip_ns = self.get_fip_ns(ex_gw_port['network_id'])
ri.fip_ns.scan_fip_ports(ri)
@ -641,28 +619,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
break
iptables_manager.apply()
def process_router_floating_ip_nat_rules(self, ri):
"""Configure NAT rules for the router's floating IPs.
Configures iptables rules for the floating ips of the given router
"""
# Clear out all iptables rules for floating ips
ri.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
floating_ips = self.get_floating_ips(ri)
# Loop once to ensure that floating ips are configured.
for fip in floating_ips:
# Rebuild iptables rules for the floating ip.
fixed = fip['fixed_ip_address']
fip_ip = fip['floating_ip_address']
for chain, rule in self.floating_forward_rules(fip_ip, fixed):
ri.iptables_manager.ipv4['nat'].add_rule(chain, rule,
tag='floating_ip')
ri.iptables_manager.apply()
def create_dvr_fip_interfaces(self, ri, ex_gw_port):
floating_ips = self.get_floating_ips(ri)
floating_ips = ri.get_floating_ips()
fip_agent_port = self.get_floating_agent_gw_interface(
ri, ex_gw_port['network_id'])
LOG.debug("FloatingIP agent gateway port received from the plugin: "
@ -692,91 +650,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
else:
return self.get_external_device_name(ex_gw_port['id'])
def _add_floating_ip(self, ri, fip, interface_name, device):
fip_ip = fip['floating_ip_address']
ip_cidr = common_utils.ip_to_cidr(fip_ip)
if ri.is_ha:
ri._add_vip(ip_cidr, interface_name)
else:
net = netaddr.IPNetwork(ip_cidr)
try:
device.addr.add(net.version, ip_cidr, str(net.broadcast))
except RuntimeError:
# any exception occurred here should cause the floating IP
# to be set in error state
LOG.warn(_LW("Unable to configure IP address for "
"floating IP: %s"), fip['id'])
return l3_constants.FLOATINGIP_STATUS_ERROR
if ri.router['distributed']:
# Special Handling for DVR - update FIP namespace
# and ri.namespace to handle DVR based FIP
ri.floating_ip_added_dist(fip, ip_cidr)
else:
# As GARP is processed in a distinct thread the call below
# won't raise an exception to be handled.
ip_lib.send_gratuitous_arp(ri.ns_name,
interface_name,
fip_ip,
self.conf.send_arp_for_ha)
return l3_constants.FLOATINGIP_STATUS_ACTIVE
def _remove_floating_ip(self, ri, device, ip_cidr):
if ri.is_ha:
ri._remove_vip(ip_cidr)
else:
net = netaddr.IPNetwork(ip_cidr)
device.addr.delete(net.version, ip_cidr)
self.driver.delete_conntrack_state(namespace=ri.ns_name,
ip=ip_cidr)
if ri.router['distributed']:
ri.floating_ip_removed_dist(ip_cidr)
def _get_router_cidrs(self, ri, device):
if ri.is_ha:
return set(ri._ha_get_existing_cidrs(device.name))
else:
return set([addr['cidr'] for addr in device.addr.list()])
def process_router_floating_ip_addresses(self, ri, interface_name):
"""Configure IP addresses on router's external gateway interface.
Ensures addresses for existing floating IPs and cleans up
those that should not longer be configured.
"""
fip_statuses = {}
if interface_name is None:
LOG.debug('No Interface for floating IPs router: %s',
ri.router['id'])
return fip_statuses
device = ip_lib.IPDevice(interface_name, namespace=ri.ns_name)
existing_cidrs = self._get_router_cidrs(ri, device)
new_cidrs = set()
floating_ips = self.get_floating_ips(ri)
# Loop once to ensure that floating ips are configured.
for fip in floating_ips:
fip_ip = fip['floating_ip_address']
ip_cidr = common_utils.ip_to_cidr(fip_ip)
new_cidrs.add(ip_cidr)
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
if ip_cidr not in existing_cidrs:
fip_statuses[fip['id']] = self._add_floating_ip(
ri, fip, interface_name, device)
fips_to_remove = (
ip_cidr for ip_cidr in existing_cidrs - new_cidrs
if common_utils.is_cidr_host(ip_cidr))
for ip_cidr in fips_to_remove:
self._remove_floating_ip(ri, device, ip_cidr)
return fip_statuses
def _get_ex_gw_port(self, ri):
return ri.router.get('gw_port')
def get_internal_device_name(self, port_id):
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
@ -789,13 +662,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
def get_router_id(self, ns_name):
return ns_name[len(NS_PREFIX):]
def get_floating_ips(self, ri):
"""Filter Floating IPs to be hosted on this agent."""
floating_ips = ri.router.get(l3_constants.FLOATINGIP_KEY, [])
if ri.router['distributed']:
floating_ips = [i for i in floating_ips if i['host'] == self.host]
return floating_ips
def get_floating_agent_gw_interface(self, ri, ext_net_id):
"""Filter Floating Agent GW port for the external network."""
fip_ports = ri.router.get(l3_constants.FLOATINGIP_AGENT_INTF_KEY, [])
@ -829,7 +695,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
# Compute a list of addresses this router is supposed to have.
# This avoids unnecessarily removing those addresses and
# causing a momentarily network outage.
floating_ips = self.get_floating_ips(ri)
floating_ips = ri.get_floating_ips()
preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
for ip in floating_ips]
@ -852,7 +718,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
return
else:
ns_name = ri.ns_name
floating_ips = self.get_floating_ips(ri)
floating_ips = ri.get_floating_ips()
preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
for ip in floating_ips]
@ -886,12 +752,12 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
def external_gateway_removed(self, ri, ex_gw_port, interface_name):
if ri.router['distributed']:
self.process_router_floating_ip_nat_rules(ri)
# TODO(Carl) Should this be calling process_snat_dnat_for_fip?
ri.process_floating_ip_nat_rules()
if ri.fip_ns:
to_fip_interface_name = (
self._get_external_device_interface_name(ri, ex_gw_port))
self.process_router_floating_ip_addresses(
ri, to_fip_interface_name)
ri.process_floating_ip_addresses(to_fip_interface_name)
for p in ri.internal_ports:
internal_interface = self.get_internal_device_name(p['id'])
self._snat_redirect_remove(ri, p, internal_interface)
@ -959,7 +825,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
ri._ha_disable_addressing_on_interface(interface_name)
ri._add_vip(internal_cidr, interface_name)
ex_gw_port = self._get_ex_gw_port(ri)
ex_gw_port = ri.get_ex_gw_port()
if ri.router['distributed'] and ex_gw_port:
snat_ports = self.get_snat_interfaces(ri)
sn_port = self._map_internal_interfaces(ri, port, snat_ports)
@ -1007,14 +873,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
self.driver.unplug(interface_name, namespace=ri.ns_name,
prefix=INTERNAL_DEV_PREFIX)
def floating_forward_rules(self, floating_ip, fixed_ip):
return [('PREROUTING', '-d %s -j DNAT --to %s' %
(floating_ip, fixed_ip)),
('OUTPUT', '-d %s -j DNAT --to %s' %
(floating_ip, fixed_ip)),
('float-snat', '-s %s -j SNAT --to %s' %
(fixed_ip, floating_ip))]
def router_deleted(self, context, router_id):
"""Deal with router deletion RPC message."""
LOG.debug('Got router deleted notification for %s', router_id)
@ -1244,7 +1102,7 @@ class L3NATAgentWithStateReport(L3NATAgent):
router_infos = self.router_info.values()
num_routers = len(router_infos)
for ri in router_infos:
ex_gw_port = self._get_ex_gw_port(ri)
ex_gw_port = ri.get_ex_gw_port()
if ex_gw_port:
num_ex_gw_ports += 1
num_interfaces += len(ri.router.get(l3_constants.INTERFACE_KEY,

View File

@ -15,18 +15,27 @@
from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import router_info as router
from neutron.agent.linux import ip_lib
from neutron.common import constants as l3_constants
from neutron.common import utils as common_utils
class DvrRouter(router.RouterInfo):
def __init__(self, *args, **kwargs):
def __init__(self, host, *args, **kwargs):
super(DvrRouter, self).__init__(*args, **kwargs)
self.host = host
self.floating_ips_dict = {}
self.snat_iptables_manager = None
# Linklocal subnet for router and floating IP namespace link
self.rtr_fip_subnet = None
self.dist_fip_count = None
def get_floating_ips(self):
"""Filter Floating IPs to be hosted on this agent."""
floating_ips = super(DvrRouter, self).get_floating_ips()
return [i for i in floating_ips if i['host'] == self.host]
def _handle_fip_nat_rules(self, interface_name, action):
"""Configures NAT rules for Floating IPs for DVR.
@ -114,3 +123,17 @@ class DvrRouter(router.RouterInfo):
# semaphore to sync creation/deletion of this namespace.
self.fip_ns.destroy()
self.fip_ns = None
def add_floating_ip(self, fip, interface_name, device):
if not self._add_fip_addr_to_device(fip, device):
return l3_constants.FLOATINGIP_STATUS_ERROR
# Special Handling for DVR - update FIP namespace
# and ri.namespace to handle DVR based FIP
ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
self.floating_ip_added_dist(fip, ip_cidr)
return l3_constants.FLOATINGIP_STATUS_ACTIVE
def remove_floating_ip(self, device, ip_cidr):
super(DvrRouter, self).remove_floating_ip(device, ip_cidr)
self.floating_ip_removed_dist(ip_cidr)

View File

@ -20,6 +20,7 @@ from neutron.agent.l3 import router_info as router
from neutron.agent.linux import ip_lib
from neutron.agent.linux import keepalived
from neutron.agent.metadata import driver as metadata_driver
from neutron.common import utils as common_utils
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@ -164,6 +165,9 @@ class HaRouter(router.RouterInfo):
instance = self._get_keepalived_instance()
return instance.get_existing_vip_ip_addresses(interface_name)
def get_router_cidrs(self, device):
return set(self._ha_get_existing_cidrs(device.name))
def _ha_external_gateway_removed(self, interface_name):
self._clear_vips(interface_name)
@ -238,3 +242,13 @@ class HaRouter(router.RouterInfo):
old_gateway_cidr = self.ex_gw_port['ip_cidr']
self._remove_vip(old_gateway_cidr)
self._ha_external_gateway_added(ex_gw_port, interface_name)
def add_floating_ip(self, fip, interface_name, device):
fip_ip = fip['floating_ip_address']
ip_cidr = common_utils.ip_to_cidr(fip_ip)
self._add_vip(ip_cidr, interface_name)
# TODO(Carl) Should this return status?
# return l3_constants.FLOATINGIP_STATUS_ACTIVE
def remove_floating_ip(self, device, ip_cidr):
self._remove_vip(ip_cidr)

View File

@ -13,7 +13,19 @@
# under the License.
from neutron.agent.l3 import router_info as router
from neutron.agent.linux import ip_lib
from neutron.common import constants as l3_constants
class LegacyRouter(router.RouterInfo):
pass
def add_floating_ip(self, fip, interface_name, device):
if not self._add_fip_addr_to_device(fip, device):
return l3_constants.FLOATINGIP_STATUS_ERROR
# As GARP is processed in a distinct thread the call below
# won't raise an exception to be handled.
ip_lib.send_gratuitous_arp(self.ns_name,
interface_name,
fip['floating_ip_address'],
self.agent_conf.send_arp_for_ha)
return l3_constants.FLOATINGIP_STATUS_ACTIVE

View File

@ -12,9 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.common import constants as l3_constants
from neutron.common import exceptions as n_exc
from neutron.common import utils as common_utils
from neutron.i18n import _LW
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@ -102,3 +107,121 @@ class RouterInfo(object):
LOG.debug("Removed route entry is '%s'", route)
self._update_routing_table('delete', route)
self.routes = new_routes
def get_ex_gw_port(self):
return self.router.get('gw_port')
def get_floating_ips(self):
"""Filter Floating IPs to be hosted on this agent."""
return self.router.get(l3_constants.FLOATINGIP_KEY, [])
def floating_forward_rules(self, floating_ip, fixed_ip):
return [('PREROUTING', '-d %s -j DNAT --to %s' %
(floating_ip, fixed_ip)),
('OUTPUT', '-d %s -j DNAT --to %s' %
(floating_ip, fixed_ip)),
('float-snat', '-s %s -j SNAT --to %s' %
(fixed_ip, floating_ip))]
def process_floating_ip_nat_rules(self):
"""Configure NAT rules for the router's floating IPs.
Configures iptables rules for the floating ips of the given router
"""
# Clear out all iptables rules for floating ips
self.iptables_manager.ipv4['nat'].clear_rules_by_tag('floating_ip')
floating_ips = self.get_floating_ips()
# Loop once to ensure that floating ips are configured.
for fip in floating_ips:
# Rebuild iptables rules for the floating ip.
fixed = fip['fixed_ip_address']
fip_ip = fip['floating_ip_address']
for chain, rule in self.floating_forward_rules(fip_ip, fixed):
self.iptables_manager.ipv4['nat'].add_rule(chain, rule,
tag='floating_ip')
self.iptables_manager.apply()
def process_snat_dnat_for_fip(self):
try:
self.process_floating_ip_nat_rules()
except Exception:
# TODO(salv-orlando): Less broad catching
raise n_exc.FloatingIpSetupException(
'L3 agent failure to setup NAT for floating IPs')
def _add_fip_addr_to_device(self, fip, device):
"""Configures the floating ip address on the device.
"""
try:
ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
net = netaddr.IPNetwork(ip_cidr)
device.addr.add(net.version, ip_cidr, str(net.broadcast))
return True
except RuntimeError:
# any exception occurred here should cause the floating IP
# to be set in error state
LOG.warn(_LW("Unable to configure IP address for "
"floating IP: %s"), fip['id'])
def add_floating_ip(self, fip, interface_name, device):
raise NotImplementedError()
def remove_floating_ip(self, device, ip_cidr):
net = netaddr.IPNetwork(ip_cidr)
device.addr.delete(net.version, ip_cidr)
self.driver.delete_conntrack_state(namespace=self.ns_name, ip=ip_cidr)
def get_router_cidrs(self, device):
return set([addr['cidr'] for addr in device.addr.list()])
def process_floating_ip_addresses(self, interface_name):
"""Configure IP addresses on router's external gateway interface.
Ensures addresses for existing floating IPs and cleans up
those that should not longer be configured.
"""
fip_statuses = {}
if interface_name is None:
LOG.debug('No Interface for floating IPs router: %s',
self.router['id'])
return fip_statuses
device = ip_lib.IPDevice(interface_name, namespace=self.ns_name)
existing_cidrs = self.get_router_cidrs(device)
new_cidrs = set()
floating_ips = self.get_floating_ips()
# Loop once to ensure that floating ips are configured.
for fip in floating_ips:
fip_ip = fip['floating_ip_address']
ip_cidr = common_utils.ip_to_cidr(fip_ip)
new_cidrs.add(ip_cidr)
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
if ip_cidr not in existing_cidrs:
fip_statuses[fip['id']] = self.add_floating_ip(
fip, interface_name, device)
fips_to_remove = (
ip_cidr for ip_cidr in existing_cidrs - new_cidrs
if common_utils.is_cidr_host(ip_cidr))
for ip_cidr in fips_to_remove:
self.remove_floating_ip(device, ip_cidr)
return fip_statuses
def configure_fip_addresses(self, interface_name):
try:
return self.process_floating_ip_addresses(interface_name)
except Exception:
# TODO(salv-orlando): Less broad catching
raise n_exc.FloatingIpSetupException('L3 agent failure to setup '
'floating IPs')
def put_fips_in_error_state(self):
fip_statuses = {}
for fip in self.router.get(l3_constants.FLOATINGIP_KEY, []):
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
return fip_statuses

View File

@ -145,7 +145,7 @@ class L3AgentTestFramework(base.BaseOVSLinuxTestCase):
router_id = router.router_id
ha_device_name = router.get_ha_device_name(router.ha_port['id'])
ha_device_cidr = router.ha_port['ip_cidr']
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
ex_port_ipv6 = router._get_ipv6_lladdr(
external_port['mac_address'])
external_device_name = self.agent.get_external_device_name(
@ -158,7 +158,7 @@ class L3AgentTestFramework(base.BaseOVSLinuxTestCase):
internal_port['id'])
internal_device_cidr = internal_port['ip_cidr']
floating_ip_cidr = common_utils.ip_to_cidr(
self.agent.get_floating_ips(router)[0]['floating_ip_address'])
router.get_floating_ips()[0]['floating_ip_address'])
default_gateway_ip = external_port['subnet'].get('gateway_ip')
return """vrrp_instance VR_1 {
@ -367,7 +367,7 @@ class L3AgentTestCase(L3AgentTestFramework):
self.assertIn(new_fip, new_config)
self.assertNotIn(old_gw, new_config)
self.assertIn(new_gw, new_config)
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
external_device_name = self.agent.get_external_device_name(
external_port['id'])
self.assertNotIn('%s/24 dev %s' %
@ -382,7 +382,7 @@ class L3AgentTestCase(L3AgentTestFramework):
router = self.manage_router(self.agent, router_info)
if enable_ha:
port = self.agent._get_ex_gw_port(router)
port = router.get_ex_gw_port()
interface_name = self.agent.get_external_device_name(port['id'])
self._assert_no_ip_addresses_on_interface(router, interface_name)
helpers.wait_until_true(lambda: router.ha_state == 'master')
@ -422,13 +422,13 @@ class L3AgentTestCase(L3AgentTestFramework):
self.assertFalse(router.keepalived_manager.process.active)
def _assert_external_device(self, router):
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
self.assertTrue(self.device_exists_with_ip_mac(
external_port, self.agent.get_external_device_name,
router.ns_name))
def _assert_gateway(self, router):
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
external_device_name = self.agent.get_external_device_name(
external_port['id'])
external_device = ip_lib.IPDevice(external_device_name,
@ -440,7 +440,7 @@ class L3AgentTestCase(L3AgentTestFramework):
def _floating_ips_configured(self, router):
floating_ips = router.router[l3_constants.FLOATINGIP_KEY]
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
return len(floating_ips) and all(ip_lib.device_exists_with_ip_mac(
self.agent.get_external_device_name(external_port['id']),
'%s/32' % fip['floating_ip_address'],
@ -703,7 +703,7 @@ class TestDvrRouter(L3AgentTestFramework):
]
def _assert_dvr_external_device(self, router):
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
snat_ns_name = self.agent.get_snat_ns_name(router.router_id)
# if the agent is in dvr_snat mode, then we have to check
@ -741,7 +741,7 @@ class TestDvrRouter(L3AgentTestFramework):
def _assert_dvr_snat_gateway(self, router):
namespace = self.agent.get_snat_ns_name(router.router_id)
external_port = self.agent._get_ex_gw_port(router)
external_port = router.get_ex_gw_port()
external_device_name = self.agent.get_external_device_name(
external_port['id'])
external_device = ip_lib.IPDevice(external_device_name,

View File

@ -17,7 +17,9 @@ import netaddr
from neutron.agent.l3 import dvr_router
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron.common import constants as l3_constants
from neutron.common import utils as common_utils
from neutron.openstack.common import uuidutils
from neutron.tests import base
@ -33,12 +35,23 @@ class TestDvrRouterOperations(base.BaseTestCase):
def _create_router(self, router, **kwargs):
agent_conf = mock.Mock()
return dvr_router.DvrRouter(mock.sentinel.router_id,
return dvr_router.DvrRouter(mock.sentinel.myhost,
mock.sentinel.router_id,
router,
agent_conf,
mock.sentinel.interface_driver,
**kwargs)
def test_get_floating_ips_dvr(self):
router = mock.MagicMock()
router.get.return_value = [{'host': mock.sentinel.myhost},
{'host': mock.sentinel.otherhost}]
ri = self._create_router(router)
fips = ri.get_floating_ips()
self.assertEqual([{'host': mock.sentinel.myhost}], fips)
@mock.patch.object(ip_lib, 'send_garp_for_proxyarp')
@mock.patch.object(ip_lib, 'IPDevice')
@mock.patch.object(ip_lib, 'IpRule')
@ -115,3 +128,41 @@ class TestDvrRouterOperations(base.BaseTestCase):
mIPDevice().route.delete_gateway.assert_called_once_with(
str(fip_to_rtr.ip), table=16)
fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
def _test_add_floating_ip(self, ri, fip, is_failure):
ri._add_fip_addr_to_device = mock.Mock(return_value=is_failure)
ri.floating_ip_added_dist = mock.Mock()
result = ri.add_floating_ip(fip,
mock.sentinel.interface_name,
mock.sentinel.device)
ri._add_fip_addr_to_device.assert_called_once_with(
fip, mock.sentinel.device)
return result
def test_add_floating_ip(self):
ri = self._create_router(mock.MagicMock())
ip = '15.1.2.3'
fip = {'floating_ip_address': ip}
result = self._test_add_floating_ip(ri, fip, True)
ri.floating_ip_added_dist.assert_called_once_with(fip, ip + '/32')
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ACTIVE, result)
def test_add_floating_ip_error(self):
ri = self._create_router(mock.MagicMock())
result = self._test_add_floating_ip(
ri, {'floating_ip_address': '15.1.2.3'}, False)
self.assertFalse(ri.floating_ip_added_dist.called)
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ERROR, result)
@mock.patch.object(router_info.RouterInfo, 'remove_floating_ip')
def test_remove_floating_ip(self, super_remove_floating_ip):
ri = self._create_router(mock.MagicMock())
ri.floating_ip_removed_dist = mock.Mock()
ri.remove_floating_ip(mock.sentinel.device, mock.sentinel.ip_cidr)
super_remove_floating_ip.assert_called_once_with(
mock.sentinel.device, mock.sentinel.ip_cidr)
ri.floating_ip_removed_dist.assert_called_once_with(
mock.sentinel.ip_cidr)

View File

@ -0,0 +1,41 @@
# Copyright (c) 2015 Openstack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron.agent.l3 import ha_router
from neutron.tests import base
class TestBasicRouterOperations(base.BaseTestCase):
def setUp(self):
super(TestBasicRouterOperations, self).setUp()
def _create_router(self, router=None, **kwargs):
if not router:
router = mock.MagicMock()
return ha_router.HaRouter(mock.sentinel.router_id,
router,
mock.sentinel.agent_conf,
mock.sentinel.driver,
ns_name=mock.sentinel.namespace,
**kwargs)
def test_get_router_cidrs_returns_ha_cidrs(self):
ri = self._create_router()
device = mock.MagicMock()
device.name.return_value = 'eth2'
addresses = ['15.1.2.2/24', '15.1.2.3/32']
ri._ha_get_existing_cidrs = mock.MagicMock(return_value=addresses)
self.assertEqual(set(addresses), ri.get_router_cidrs(device))

View File

@ -0,0 +1,222 @@
# Copyright (c) 2015 Openstack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron.common import constants as l3_constants
from neutron.common import exceptions as n_exc
from neutron.openstack.common import uuidutils
from neutron.tests import base
_uuid = uuidutils.generate_uuid
class BasicRouterTestCaseFramework(base.BaseTestCase):
def _create_router(self, router=None, **kwargs):
if not router:
router = mock.MagicMock()
return router_info.RouterInfo(mock.sentinel.router_id,
router,
mock.sentinel.agent_conf,
mock.sentinel.interface_driver,
**kwargs)
class TestBasicRouterOperations(BasicRouterTestCaseFramework):
def test_get_floating_ips(self):
router = mock.MagicMock()
router.get.return_value = [mock.sentinel.floating_ip]
ri = self._create_router(router)
fips = ri.get_floating_ips()
self.assertEqual([mock.sentinel.floating_ip], fips)
def test_process_floating_ip_nat_rules(self):
ri = self._create_router()
fips = [{'fixed_ip_address': mock.sentinel.ip,
'floating_ip_address': mock.sentinel.fip}]
ri.get_floating_ips = mock.Mock(return_value=fips)
ri.iptables_manager = mock.MagicMock()
ipv4_nat = ri.iptables_manager.ipv4['nat']
ri.floating_forward_rules = mock.Mock(
return_value=[(mock.sentinel.chain, mock.sentinel.rule)])
ri.process_floating_ip_nat_rules()
# Be sure that the rules are cleared first and apply is called last
self.assertEqual(mock.call.clear_rules_by_tag('floating_ip'),
ipv4_nat.mock_calls[0])
self.assertEqual(mock.call.apply(), ri.iptables_manager.mock_calls[-1])
# Be sure that add_rule is called somewhere in the middle
ipv4_nat.add_rule.assert_called_once_with(mock.sentinel.chain,
mock.sentinel.rule,
tag='floating_ip')
def test_process_floating_ip_nat_rules_removed(self):
ri = self._create_router()
ri.get_floating_ips = mock.Mock(return_value=[])
ri.iptables_manager = mock.MagicMock()
ipv4_nat = ri.iptables_manager.ipv4['nat']
ri.process_floating_ip_nat_rules()
# Be sure that the rules are cleared first and apply is called last
self.assertEqual(mock.call.clear_rules_by_tag('floating_ip'),
ipv4_nat.mock_calls[0])
self.assertEqual(mock.call.apply(), ri.iptables_manager.mock_calls[-1])
# Be sure that add_rule is called somewhere in the middle
self.assertFalse(ipv4_nat.add_rule.called)
def _test_add_fip_addr_to_device_error(self, device):
ri = self._create_router()
ip = '15.1.2.3'
result = ri._add_fip_addr_to_device(
{'id': mock.sentinel.id, 'floating_ip_address': ip}, device)
device.addr.add.assert_called_with(4, ip + '/32', ip)
return result
def test__add_fip_addr_to_device(self):
result = self._test_add_fip_addr_to_device_error(mock.Mock())
self.assertTrue(result)
def test__add_fip_addr_to_device_error(self):
device = mock.Mock()
device.addr.add.side_effect = RuntimeError
result = self._test_add_fip_addr_to_device_error(device)
self.assertFalse(result)
def test_process_snat_dnat_for_fip(self):
ri = self._create_router()
ri.process_floating_ip_nat_rules = mock.Mock(side_effect=Exception)
self.assertRaises(n_exc.FloatingIpSetupException,
ri.process_snat_dnat_for_fip)
ri.process_floating_ip_nat_rules.assert_called_once_with()
def test_put_fips_in_error_state(self):
ri = self._create_router()
ri.router = mock.Mock()
ri.router.get.return_value = [{'id': mock.sentinel.id1},
{'id': mock.sentinel.id2}]
statuses = ri.put_fips_in_error_state()
expected = [{mock.sentinel.id1: l3_constants.FLOATINGIP_STATUS_ERROR,
mock.sentinel.id2: l3_constants.FLOATINGIP_STATUS_ERROR}]
self.assertNotEqual(expected, statuses)
def test_configure_fip_addresses(self):
ri = self._create_router()
ri.process_floating_ip_addresses = mock.Mock(
side_effect=Exception)
self.assertRaises(n_exc.FloatingIpSetupException,
ri.configure_fip_addresses,
mock.sentinel.interface_name)
ri.process_floating_ip_addresses.assert_called_once_with(
mock.sentinel.interface_name)
def test_get_router_cidrs_returns_cidrs(self):
ri = self._create_router()
addresses = ['15.1.2.2/24', '15.1.2.3/32']
device = mock.MagicMock()
device.addr.list.return_value = [{'cidr': addresses[0]},
{'cidr': addresses[1]}]
self.assertEqual(set(addresses), ri.get_router_cidrs(device))
@mock.patch.object(ip_lib, 'IPDevice')
class TestFloatingIpWithMockDevice(BasicRouterTestCaseFramework):
def test_process_floating_ip_addresses_remap(self, IPDevice):
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
ri = self._create_router()
ri.get_floating_ips = mock.Mock(return_value=[fip])
fip_statuses = ri.process_floating_ip_addresses(
mock.sentinel.interface_name)
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ACTIVE},
fip_statuses)
self.assertFalse(device.addr.add.called)
self.assertFalse(device.addr.delete.called)
def test_process_router_with_disabled_floating_ip(self, IPDevice):
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
ri = self._create_router()
ri.floating_ips = [fip]
ri.get_floating_ips = mock.Mock(return_value=[])
fip_statuses = ri.process_floating_ip_addresses(
mock.sentinel.interface_name)
self.assertIsNone(fip_statuses.get(fip_id))
def test_process_router_floating_ip_with_device_add_error(self, IPDevice):
IPDevice.return_value = device = mock.Mock(side_effect=RuntimeError)
device.addr.list.return_value = []
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
ri = self._create_router()
ri.add_floating_ip = mock.Mock(
return_value=l3_constants.FLOATINGIP_STATUS_ERROR)
ri.get_floating_ips = mock.Mock(return_value=[fip])
fip_statuses = ri.process_floating_ip_addresses(
mock.sentinel.interface_name)
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ERROR},
fip_statuses)
# TODO(mrsmith): refactor for DVR cases
def test_process_floating_ip_addresses_remove(self, IPDevice):
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
ri = self._create_router()
ri.remove_floating_ip = mock.Mock()
ri.router.get = mock.Mock(return_value=[])
fip_statuses = ri.process_floating_ip_addresses(
mock.sentinel.interface_name)
self.assertEqual({}, fip_statuses)
ri.remove_floating_ip.assert_called_once_with(device, '15.1.2.3/32')

View File

@ -0,0 +1,77 @@
# Copyright (c) 2015 Openstack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron.agent.l3 import legacy_router
from neutron.agent.linux import ip_lib
from neutron.common import constants as l3_constants
from neutron.tests import base
class BasicRouterTestCaseFramework(base.BaseTestCase):
def _create_router(self, router=None, **kwargs):
if not router:
router = mock.MagicMock()
self.agent_conf = mock.Mock()
self.driver = mock.Mock()
return legacy_router.LegacyRouter(mock.sentinel.router_id,
router,
self.agent_conf,
self.driver,
ns_name=mock.sentinel.namespace,
**kwargs)
class TestBasicRouterOperations(BasicRouterTestCaseFramework):
def test_remove_floating_ip(self):
ri = self._create_router(mock.MagicMock())
device = mock.Mock()
cidr = '15.1.2.3/32'
ri.remove_floating_ip(device, cidr)
device.addr.delete.assert_called_once_with(4, cidr)
self.driver.delete_conntrack_state.assert_called_once_with(
ip=cidr,
namespace=mock.sentinel.namespace)
@mock.patch.object(ip_lib, 'send_gratuitous_arp')
class TestAddFloatingIpWithMockGarp(BasicRouterTestCaseFramework):
def test_add_floating_ip(self, send_gratuitous_arp):
ri = self._create_router()
ri._add_fip_addr_to_device = mock.Mock(return_value=True)
self.agent_conf.send_arp_for_ha = mock.sentinel.arp_count
ri.ns_name = mock.sentinel.ns_name
ip = '15.1.2.3'
result = ri.add_floating_ip({'floating_ip_address': ip},
mock.sentinel.interface_name,
mock.sentinel.device)
ip_lib.send_gratuitous_arp.assert_called_once_with(
mock.sentinel.ns_name,
mock.sentinel.interface_name,
ip,
mock.sentinel.arp_count)
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ACTIVE, result)
def test_add_floating_ip_error(self, send_gratuitous_arp):
ri = self._create_router()
ri._add_fip_addr_to_device = mock.Mock(return_value=False)
result = ri.add_floating_ip({'floating_ip_address': '15.1.2.3'},
mock.sentinel.interface_name,
mock.sentinel.device)
self.assertFalse(ip_lib.send_gratuitous_arp.called)
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ERROR, result)

View File

@ -26,9 +26,9 @@ from neutron.agent.common import config as agent_config
from neutron.agent.l3 import agent as l3_agent
from neutron.agent.l3 import config as l3_config
from neutron.agent.l3 import dvr
from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import dvr_router
from neutron.agent.l3 import ha
from neutron.agent.l3 import legacy_router
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.l3 import router_info as l3router
from neutron.agent.linux import external_process
@ -753,7 +753,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
def test_process_dist_router(self):
router = prepare_router_data()
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri = dvr_router.DvrRouter(HOSTNAME,
router['id'],
router,
**self.ri_kwargs)
subnet_id = _get_subnet_id(router[l3_constants.INTERFACE_KEY][0])
ri.router['distributed'] = True
ri.router['_snat_router_interfaces'] = [{
@ -768,9 +771,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent.host = HOSTNAME
fake_fip_id = 'fake_fip_id'
agent.create_dvr_fip_interfaces = mock.Mock()
agent.process_router_floating_ip_addresses = mock.Mock()
agent.process_router_floating_ip_nat_rules = mock.Mock()
agent.process_router_floating_ip_addresses.return_value = {
ri.process_floating_ip_addresses = mock.Mock()
ri.process_floating_ip_nat_rules = mock.Mock()
ri.process_floating_ip_addresses.return_value = {
fake_fip_id: 'ACTIVE'}
agent.external_gateway_added = mock.Mock()
agent.external_gateway_updated = mock.Mock()
@ -781,11 +784,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
'port_id': _uuid(),
'host': HOSTNAME}]}
agent.process_router(ri)
agent.process_router_floating_ip_addresses.assert_called_with(
ri, mock.ANY)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
ri.process_floating_ip_addresses.assert_called_with(mock.ANY)
ri.process_floating_ip_addresses.reset_mock()
ri.process_floating_ip_nat_rules.assert_called_with()
ri.process_floating_ip_nat_rules.reset_mock()
agent.external_gateway_added.reset_mock()
# remap floating IP to a new fixed ip
@ -794,11 +796,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips2['floatingips']
agent.process_router(ri)
agent.process_router_floating_ip_addresses.assert_called_with(
ri, mock.ANY)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
ri.process_floating_ip_addresses.assert_called_with(mock.ANY)
ri.process_floating_ip_addresses.reset_mock()
ri.process_floating_ip_nat_rules.assert_called_with()
ri.process_floating_ip_nat_rules.reset_mock()
self.assertEqual(agent.external_gateway_added.call_count, 0)
self.assertEqual(agent.external_gateway_updated.call_count, 0)
agent.external_gateway_added.reset_mock()
@ -812,19 +813,18 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
ri.router['gw_port']['fixed_ips'][0]['ip_address'] = str(old_ip + 1)
agent.process_router(ri)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.reset_mock()
ri.process_floating_ip_addresses.reset_mock()
ri.process_floating_ip_nat_rules.reset_mock()
self.assertEqual(agent.external_gateway_added.call_count, 0)
self.assertEqual(agent.external_gateway_updated.call_count, 1)
# remove just the floating ips
del router[l3_constants.FLOATINGIP_KEY]
agent.process_router(ri)
agent.process_router_floating_ip_addresses.assert_called_with(
ri, mock.ANY)
agent.process_router_floating_ip_addresses.reset_mock()
agent.process_router_floating_ip_nat_rules.assert_called_with(ri)
agent.process_router_floating_ip_nat_rules.reset_mock()
ri.process_floating_ip_addresses.assert_called_with(mock.ANY)
ri.process_floating_ip_addresses.reset_mock()
ri.process_floating_ip_nat_rules.assert_called_with()
ri.process_floating_ip_nat_rules.reset_mock()
# now no ports so state is torn down
del router[l3_constants.INTERFACE_KEY]
@ -832,51 +832,32 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent.process_router(ri)
self.assertEqual(self.send_arp.call_count, 1)
distributed = ri.router.get('distributed', False)
self.assertEqual(agent.process_router_floating_ip_addresses.called,
self.assertEqual(ri.process_floating_ip_addresses.called,
distributed)
self.assertEqual(agent.process_router_floating_ip_nat_rules.called,
self.assertEqual(ri.process_floating_ip_nat_rules.called,
distributed)
@mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def _test_process_router_floating_ip_addresses_add(self, ri,
agent, IPDevice):
floating_ips = agent.get_floating_ips(ri)
def _test_process_floating_ip_addresses_add(self, ri, agent, IPDevice):
floating_ips = ri.get_floating_ips()
fip_id = floating_ips[0]['id']
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = []
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
ex_gw_port = {'id': _uuid(), 'network_id': mock.sentinel.ext_net_id}
ri.add_floating_ip = mock.Mock(
return_value=l3_constants.FLOATINGIP_STATUS_ACTIVE)
with mock.patch.object(lla.LinkLocalAllocator, '_write'):
if ri.router['distributed']:
ri.fip_ns = agent.get_fip_ns(ex_gw_port['network_id'])
agent.create_dvr_fip_interfaces(ri, ex_gw_port)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, ex_gw_port)
fip_statuses = ri.process_floating_ip_addresses(
mock.sentinel.interface_name)
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ACTIVE},
fip_statuses)
device.addr.add.assert_called_once_with(4, '15.1.2.3/32', '15.1.2.3')
def test_process_router_floating_ip_nat_rules_add(self):
fip = {
'id': _uuid(), 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.1'
}
ri = mock.MagicMock()
ri.router['distributed'].__nonzero__ = lambda self: False
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.get_floating_ips = mock.Mock(return_value=[fip])
agent.process_router_floating_ip_nat_rules(ri)
nat = ri.iptables_manager.ipv4['nat']
nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
rules = agent.floating_forward_rules('15.1.2.3', '192.168.0.1')
for chain, rule in rules:
nat.add_rule.assert_any_call(chain, rule, tag='floating_ip')
ri.add_floating_ip.assert_called_once_with(
floating_ips[0], mock.sentinel.interface_name, device)
def test_get_floating_agent_gw_interfaces(self):
fake_network_id = _uuid()
@ -895,7 +876,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
router = prepare_router_data(enable_snat=True)
router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = agent_gateway_port
router['distributed'] = True
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri = dvr_router.DvrRouter(
HOSTNAME, router['id'], router, **self.ri_kwargs)
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.assertEqual(
agent_gateway_port[0],
@ -925,7 +907,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = agent_gateway_port
router['distributed'] = True
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri = dvr_router.DvrRouter(
HOSTNAME, router['id'], router, **self.ri_kwargs)
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
ext_gw_port = ri.router.get('gw_port')
@ -933,7 +916,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
ri.dist_fip_count = 0
ri.fip_ns.subscribe = mock.Mock()
with contextlib.nested(mock.patch.object(agent,
with contextlib.nested(mock.patch.object(ri,
'get_floating_ips'),
mock.patch.object(
agent, 'get_floating_agent_gw_interface'),
@ -961,10 +944,11 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
router = prepare_router_data(enable_snat=True)
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
ri = legacy_router.LegacyRouter(router['id'], router, **self.ri_kwargs)
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self._test_process_router_floating_ip_addresses_add(ri, agent)
agent.get_external_device_name = mock.Mock(return_value='exgw')
self._test_process_floating_ip_addresses_add(ri, agent)
def test_process_router_dist_floating_ip_add(self):
fake_floatingips = {'floatingips': [
@ -984,11 +968,13 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
router = prepare_router_data(enable_snat=True)
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
router['distributed'] = True
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri = dvr_router.DvrRouter(HOSTNAME,
router['id'],
router,
**self.ri_kwargs)
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
ri.dist_fip_count = 0
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.host = HOSTNAME
fip_ns = agent.get_fip_ns(mock.sentinel.ext_net_id)
fip_ns.agent_gateway_port = (
{'fixed_ips': [{'ip_address': '20.0.0.30',
@ -999,131 +985,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
'mac_address': 'ca:fe:de:ad:be:ef',
'ip_cidr': '20.0.0.30/24'}
)
self._test_process_router_floating_ip_addresses_add(ri, agent)
def test_get_router_cidrs_returns_cidrs(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
ri = mock.MagicMock()
ri.is_ha = False
addresses = ['15.1.2.2/24', '15.1.2.3/32']
device = mock.MagicMock()
device.addr.list.return_value = [{'cidr': addresses[0]},
{'cidr': addresses[1]}]
self.assertEqual(set(addresses), agent._get_router_cidrs(ri, device))
def test_get_router_cidrs_returns_ha_cidrs(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
ri = mock.MagicMock()
ri.is_ha = True
device = mock.MagicMock()
device.name.return_value = 'eth2'
addresses = ['15.1.2.2/24', '15.1.2.3/32']
ri._ha_get_existing_cidrs = mock.MagicMock()
ri._ha_get_existing_cidrs.return_value = addresses
self.assertEqual(set(addresses), agent._get_router_cidrs(ri, device))
# TODO(mrsmith): refactor for DVR cases
@mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_addresses_remove(self, IPDevice):
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
ri = mock.MagicMock()
ri.router.get.return_value = []
type(ri).is_ha = mock.PropertyMock(return_value=False)
ri.router['distributed'].__nonzero__ = lambda self: False
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, {'id': _uuid()})
self.assertEqual({}, fip_statuses)
device.addr.delete.assert_called_once_with(4, '15.1.2.3/32')
self.mock_driver.delete_conntrack_state.assert_called_once_with(
namespace=ri.ns_name,
ip='15.1.2.3/32')
def test_process_router_floating_ip_nat_rules_remove(self):
ri = mock.MagicMock()
ri.router.get.return_value = []
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_nat_rules(ri)
nat = ri.iptables_manager.ipv4['nat']
nat = ri.iptables_manager.ipv4['nat`']
nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
@mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_addresses_remap(self, IPDevice):
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
ri = mock.MagicMock()
ri.router['distributed'].__nonzero__ = lambda self: False
type(ri).is_ha = mock.PropertyMock(return_value=False)
ri.router.get.return_value = [fip]
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, {'id': _uuid()})
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ACTIVE},
fip_statuses)
self.assertFalse(device.addr.add.called)
self.assertFalse(device.addr.delete.called)
@mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_with_disabled_floating_ip(self, IPDevice):
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
ri = mock.MagicMock()
ri.floating_ips = [fip]
ri.router.get.return_value = []
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, {'id': _uuid(), 'network_id': mock.sentinel.ext_net_id})
self.assertIsNone(fip_statuses.get(fip_id))
@mock.patch('neutron.agent.linux.ip_lib.IPDevice')
def test_process_router_floating_ip_with_device_add_error(self, IPDevice):
IPDevice.return_value = device = mock.Mock()
device.addr.add.side_effect = RuntimeError()
device.addr.list.return_value = []
fip_id = _uuid()
fip = {
'id': fip_id, 'port_id': _uuid(),
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.2'
}
ri = mock.MagicMock()
type(ri).is_ha = mock.PropertyMock(return_value=False)
ri.router.get.return_value = [fip]
ri.router['distributed'].__nonzero__ = lambda self: False
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, {'id': _uuid()})
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ERROR},
fip_statuses)
def test_process_router_snat_disabled(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
@ -1386,7 +1247,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
'fixed_ip_address': '7.7.7.7',
'port_id': router[l3_constants.INTERFACE_KEY][0]['id']}]
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
ri = legacy_router.LegacyRouter(router['id'],
router,
**self.ri_kwargs)
agent.external_gateway_added = mock.Mock()
agent.process_router(ri)
# Assess the call for putting the floating IP up was performed
@ -1405,8 +1268,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
def test_process_router_floatingip_exception(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_addresses = mock.Mock()
agent.process_router_floating_ip_addresses.side_effect = RuntimeError
with mock.patch.object(
agent.plugin_rpc,
'update_floatingip_statuses') as mock_update_fip_status:
@ -1419,6 +1280,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
'port_id': router[l3_constants.INTERFACE_KEY][0]['id']}]
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
ri.process_floating_ip_addresses = mock.Mock(
side_effect=RuntimeError)
agent.external_gateway_added = mock.Mock()
agent.process_router(ri)
# Assess the call for putting the floating IP into Error
@ -1429,6 +1292,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
def test_handle_router_snat_rules_distributed_without_snat_manager(self):
ri = dvr_router.DvrRouter(
HOSTNAME,
'foo_router_id',
{'distributed': True},
**self.ri_kwargs)
@ -1921,7 +1785,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
self.mock_driver.unplug.reset_mock()
external_net_id = router['gw_port']['network_id']
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri = dvr_router.DvrRouter(
HOSTNAME, router['id'], router, **self.ri_kwargs)
ri.remove_floating_ip = mock.Mock()
agent._fetch_external_net_id = mock.Mock(return_value=external_net_id)
ri.ex_gw_port = ri.router['gw_port']
del ri.router['gw_port']
@ -1958,24 +1824,11 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
ri, ri.ex_gw_port,
agent.get_external_device_name(ri.ex_gw_port['id']))
self.assertFalse(nat.add_rule.called)
nat.clear_rules_by_tag.assert_called_once_with('floating_ip')
if fip_ns:
self.mock_ip.del_veth.assert_called_once_with(
fip_ns.get_int_device_name(ri.router['id']))
self.mock_ip_dev.route.delete_gateway.assert_called_once_with(
str(fip_to_rtr.ip), table=dvr_fip_ns.FIP_RT_TBL)
self.assertEqual(ri.dist_fip_count, 0)
self.assertFalse(fip_ns.has_subscribers())
self.assertIsNone(fip_ns.agent_gateway_port)
self.assertTrue(fip_ns.destroyed)
self.mock_ip.netns.delete.assert_called_once_with(
fip_ns.get_name())
self.assertEqual(self.mock_driver.unplug.call_count, 1)
ri.remove_floating_ip.assert_called_once_with(self.mock_ip_dev,
'19.4.4.2/32')
else:
self.assertFalse(self.mock_driver.unplug.called)
self.assertFalse(ri.remove_floating_ip.called)
def test_external_gateway_removed_ext_gw_port_and_fip(self):
self._test_external_gateway_removed_ext_gw_port_and_fip(fip_ns=True)
@ -2051,41 +1904,3 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
if not skip(managed_flag):
assertFlag(managed_flag)('AdvManagedFlag on',
self.utils_replace_file.call_args[0][1])
def test__put_fips_in_error_state(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
ri = mock.Mock()
ri.router.get.return_value = [{'id': mock.sentinel.id1},
{'id': mock.sentinel.id2}]
statuses = agent._put_fips_in_error_state(ri)
expected = [{mock.sentinel.id1: l3_constants.FLOATINGIP_STATUS_ERROR,
mock.sentinel.id2: l3_constants.FLOATINGIP_STATUS_ERROR}]
self.assertNotEqual(expected, statuses)
def test__process_snat_dnat_for_fip(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_nat_rules = mock.Mock(
side_effect=Exception)
self.assertRaises(n_exc.FloatingIpSetupException,
agent._process_snat_dnat_for_fip,
mock.sentinel.ri)
agent.process_router_floating_ip_nat_rules.assert_called_with(
mock.sentinel.ri)
def test__configure_fip_addresses(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.process_router_floating_ip_addresses = mock.Mock(
side_effect=Exception)
self.assertRaises(n_exc.FloatingIpSetupException,
agent._configure_fip_addresses,
mock.sentinel.ri,
mock.sentinel.ex_gw_port)
agent.process_router_floating_ip_addresses.assert_called_with(
mock.sentinel.ri,
mock.sentinel.ex_gw_port)