ri.perform_snat_action(self._handle_router_snat_rules,
interface_name)
- def _process_snat_dnat_for_fip(self, ri):
- ex_gw_port = self._get_ex_gw_port(ri)
- if not ex_gw_port:
- return
+ 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:
- existing_floating_ips = ri.floating_ips
self.process_router_floating_ip_nat_rules(ri)
- ri.iptables_manager.defer_apply_off()
- # Once NAT rules for floating IPs are safely in place
- # configure their addresses on the external gateway port
- fip_statuses = self.process_router_floating_ip_addresses(
+ 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, ex_gw_port):
+ try:
+ return self.process_router_floating_ip_addresses(
ri, ex_gw_port)
except Exception:
# TODO(salv-orlando): Less broad catching
- # All floating IPs must be put in error state
- for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
- fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
+ 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())
for fip_id in existing_floating_ips - ri.floating_ips:
else:
ri.disable_keepalived()
+ def _process_external(self, ri):
+ try:
+ with ri.iptables_manager.defer_apply():
+ self._process_external_gateway(ri)
+ ex_gw_port = self._get_ex_gw_port(ri)
+ # TODO(Carl) Return after setting existing_floating_ips and
+ # still call _update_fip_statuses?
+ if not ex_gw_port:
+ return
+
+ # Process SNAT/DNAT rules and addresses for floating IPs
+ existing_floating_ips = ri.floating_ips
+ self._process_snat_dnat_for_fip(ri)
+
+ # Once NAT rules for floating IPs are safely in place
+ # configure their addresses on the external gateway port
+ fip_statuses = self._configure_fip_addresses(ri, ex_gw_port)
+
+ except (n_exc.FloatingIpSetupException, n_exc.IpTablesApplyException):
+ # All floating IPs must be put in error state
+ fip_statuses = self._put_fips_in_error_state(ri)
+
+ self._update_fip_statuses(ri, existing_floating_ips, fip_statuses)
+
@common_utils.exception_logger()
def process_router(self, ri):
# TODO(mrsmith) - we shouldn't need to check here
if 'distributed' not in ri.router:
ri.router['distributed'] = False
-
- ri.iptables_manager.defer_apply_on()
self._process_internal_ports(ri)
- self._process_external_gateway(ri)
-
+ self._process_external(ri)
# Process static routes for router
self.routes_updated(ri)
- # Process SNAT/DNAT rules for floating IPs
- self._process_snat_dnat_for_fip(ri)
-
# Enable or disable keepalived for ha routers
self._process_ha_router(ri)
"""Implements iptables rules using linux utilities."""
+import contextlib
import os
import re
import sys
from neutron.agent.common import config
from neutron.agent.linux import iptables_comments as ic
from neutron.agent.linux import utils as linux_utils
+from neutron.common import exceptions as n_exc
from neutron.common import utils
from neutron.i18n import _LE, _LW
from neutron.openstack.common import lockutils
def is_chain_empty(self, table, chain, ip_version=4, wrap=True):
return not self.get_chain(table, chain, ip_version, wrap)
+ @contextlib.contextmanager
+ def defer_apply(self):
+ """Defer apply context."""
+ self.defer_apply_on()
+ try:
+ yield
+ finally:
+ try:
+ self.defer_apply_off()
+ except Exception:
+ raise n_exc.IpTablesApplyException('Failure applying ip '
+ 'tables rules')
+
def defer_apply_on(self):
self.iptables_apply_deferred = True
asserter = self.assertIn if flag_set else self.assertNotIn
asserter('AdvOtherConfigFlag 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)