Merge "Move Floating IP processing to Router classes"
This commit is contained in:
commit
f7a00bcd79
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
|
@ -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))
|
|
@ -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')
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue