Refactor management of namespaces in the L3 Agent
Creates classes representing the 3 types of namespaces handled by the L3 agent: router, snat and fip. The scope of this change is: - Creation and deletion methods are provided for each namespace class - Creation and deletion of router and snat namespaces are moved to the router classes. These namespaces are now members of the corresponding router class - Invocation of Fip namespace creation and deletion is left in the agent, since the agent owns it - A context manager is provided to move the namespaces (router and snat) cleanup code out of the agent A follow up patchset will add methods to create and delete interfaces in the namespaces. These methods are intended to be used by the router classes Change-Id: I54b14e593ded6b2990d57a3ae9d598a699ae133e Partially-Implements: bp restructure-l3-agent
This commit is contained in:
parent
1e93c0c5fb
commit
01a7ba19cf
|
@ -22,12 +22,14 @@ from oslo_utils import importutils
|
|||
from oslo_utils import timeutils
|
||||
|
||||
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 dvr_snat_ns
|
||||
from neutron.agent.l3 import event_observers
|
||||
from neutron.agent.l3 import ha
|
||||
from neutron.agent.l3 import ha_router
|
||||
from neutron.agent.l3 import legacy_router
|
||||
from neutron.agent.l3 import namespace_manager
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.l3 import router_processing_queue as queue
|
||||
from neutron.agent.linux import external_process
|
||||
from neutron.agent.linux import ip_lib
|
||||
|
@ -55,9 +57,10 @@ except Exception:
|
|||
from neutron.services.firewall.agents.l3reference import firewall_l3_agent
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
NS_PREFIX = 'qrouter-'
|
||||
INTERNAL_DEV_PREFIX = 'qr-'
|
||||
EXTERNAL_DEV_PREFIX = 'qg-'
|
||||
# TODO(Carl) Following constants retained to increase SNR during refactoring
|
||||
NS_PREFIX = namespaces.NS_PREFIX
|
||||
INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
|
||||
EXTERNAL_DEV_PREFIX = namespaces.EXTERNAL_DEV_PREFIX
|
||||
|
||||
|
||||
class L3PluginApi(object):
|
||||
|
@ -197,7 +200,10 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
continue
|
||||
break
|
||||
|
||||
self._clean_stale_namespaces = self.conf.use_namespaces
|
||||
self.namespaces_manager = namespace_manager.NamespaceManager(
|
||||
self.conf,
|
||||
self.driver,
|
||||
self.conf.use_namespaces)
|
||||
|
||||
self._queue = queue.RouterProcessingQueue()
|
||||
self.event_observers = event_observers.L3EventObservers()
|
||||
|
@ -226,95 +232,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
LOG.error(msg)
|
||||
raise SystemExit(1)
|
||||
|
||||
def _list_namespaces(self):
|
||||
"""Get a set of all router namespaces on host
|
||||
|
||||
The argument routers is the list of routers that are recorded in
|
||||
the database as being hosted on this node.
|
||||
"""
|
||||
try:
|
||||
root_ip = ip_lib.IPWrapper()
|
||||
|
||||
host_namespaces = root_ip.get_namespaces()
|
||||
return set(ns for ns in host_namespaces
|
||||
if (ns.startswith(NS_PREFIX)
|
||||
or ns.startswith(dvr.SNAT_NS_PREFIX)))
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('RuntimeError in obtaining router list '
|
||||
'for namespace cleanup.'))
|
||||
return set()
|
||||
|
||||
def _get_routers_namespaces(self, router_ids):
|
||||
namespaces = set(self.get_ns_name(rid) for rid in router_ids)
|
||||
namespaces.update(self.get_snat_ns_name(rid) for rid in router_ids)
|
||||
return namespaces
|
||||
|
||||
def _cleanup_namespaces(self, router_namespaces, router_ids):
|
||||
"""Destroy stale router namespaces on host when L3 agent restarts
|
||||
|
||||
This routine is called when self._clean_stale_namespaces is True.
|
||||
|
||||
The argument router_namespaces is the list of all routers namespaces
|
||||
The argument router_ids is the list of ids for known routers.
|
||||
"""
|
||||
# Don't destroy namespaces of routers this agent handles.
|
||||
ns_to_ignore = self._get_routers_namespaces(router_ids)
|
||||
|
||||
ns_to_destroy = router_namespaces - ns_to_ignore
|
||||
for ns in ns_to_destroy:
|
||||
try:
|
||||
self._destroy_namespace(ns)
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('Failed to destroy stale router namespace '
|
||||
'%s'), ns)
|
||||
self._clean_stale_namespaces = False
|
||||
|
||||
def _destroy_namespace(self, ns):
|
||||
if ns.startswith(NS_PREFIX):
|
||||
self._destroy_router_namespace(ns)
|
||||
elif ns.startswith(dvr_fip_ns.FIP_NS_PREFIX):
|
||||
self._destroy_fip_namespace(ns)
|
||||
elif ns.startswith(dvr.SNAT_NS_PREFIX):
|
||||
self._destroy_snat_namespace(ns)
|
||||
|
||||
def _delete_namespace(self, ns_ip, ns):
|
||||
try:
|
||||
ns_ip.netns.delete(ns)
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('Failed trying to delete namespace: %s'), ns)
|
||||
|
||||
def _destroy_router_namespace(self, ns):
|
||||
router_id = self.get_router_id(ns)
|
||||
if router_id in self.router_info:
|
||||
self.router_info[router_id].radvd.disable()
|
||||
ns_ip = ip_lib.IPWrapper(namespace=ns)
|
||||
for d in ns_ip.get_devices(exclude_loopback=True):
|
||||
if d.name.startswith(INTERNAL_DEV_PREFIX):
|
||||
# device is on default bridge
|
||||
self.driver.unplug(d.name, namespace=ns,
|
||||
prefix=INTERNAL_DEV_PREFIX)
|
||||
elif d.name.startswith(dvr_fip_ns.ROUTER_2_FIP_DEV_PREFIX):
|
||||
ns_ip.del_veth(d.name)
|
||||
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
|
||||
self.driver.unplug(d.name,
|
||||
bridge=self.conf.external_network_bridge,
|
||||
namespace=ns,
|
||||
prefix=EXTERNAL_DEV_PREFIX)
|
||||
|
||||
if self.conf.router_delete_namespaces:
|
||||
self._delete_namespace(ns_ip, ns)
|
||||
|
||||
def _create_namespace(self, name):
|
||||
ip_wrapper_root = ip_lib.IPWrapper()
|
||||
ip_wrapper = ip_wrapper_root.ensure_namespace(name)
|
||||
ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
|
||||
if self.use_ipv6:
|
||||
ip_wrapper.netns.execute(['sysctl', '-w',
|
||||
'net.ipv6.conf.all.forwarding=1'])
|
||||
|
||||
def _create_router_namespace(self, ri):
|
||||
self._create_namespace(ri.ns_name)
|
||||
|
||||
def _fetch_external_net_id(self, force=False):
|
||||
"""Find UUID of single external network for this agent."""
|
||||
if self.conf.gateway_external_network_id:
|
||||
|
@ -349,14 +266,11 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
if router.get('distributed') and router.get('ha'):
|
||||
raise n_exc.DvrHaRouterNotSupported(router_id=router_id)
|
||||
|
||||
ns_name = (self.get_ns_name(router_id)
|
||||
if self.conf.use_namespaces else None)
|
||||
args = []
|
||||
kwargs = {
|
||||
'router_id': router_id,
|
||||
'router': router,
|
||||
'use_ipv6': self.use_ipv6,
|
||||
'ns_name': ns_name,
|
||||
'agent_conf': self.conf,
|
||||
'interface_driver': self.driver,
|
||||
}
|
||||
|
@ -380,8 +294,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
adv_svc.AdvancedService.before_router_added, ri)
|
||||
|
||||
self.router_info[router_id] = ri
|
||||
if self.conf.use_namespaces:
|
||||
self._create_router_namespace(ri)
|
||||
ri.create()
|
||||
self.process_router_add(ri)
|
||||
|
||||
if ri.is_ha:
|
||||
|
@ -405,8 +318,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
ri.router[l3_constants.FLOATINGIP_KEY] = []
|
||||
self.process_router(ri)
|
||||
del self.router_info[router_id]
|
||||
self._destroy_router_namespace(ri.ns_name)
|
||||
|
||||
ri.delete()
|
||||
self.event_observers.notify(
|
||||
adv_svc.AdvancedService.after_router_removed, ri)
|
||||
|
||||
|
@ -656,12 +568,6 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
def get_external_device_name(self, port_id):
|
||||
return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def get_ns_name(self, router_id):
|
||||
return (NS_PREFIX + router_id)
|
||||
|
||||
def get_router_id(self, ns_name):
|
||||
return ns_name[len(NS_PREFIX):]
|
||||
|
||||
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, [])
|
||||
|
@ -711,7 +617,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
if ri.router['distributed']:
|
||||
if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT and
|
||||
self.get_gw_port_host(ri.router) == self.host):
|
||||
ns_name = self.get_snat_ns_name(ri.router['id'])
|
||||
ns_name = ri.snat_namespace.name
|
||||
else:
|
||||
# no centralized SNAT gateway for this node/agent
|
||||
LOG.debug("not hosting snat for router: %s", ri.router['id'])
|
||||
|
@ -764,7 +670,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
|
||||
if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
and self.get_gw_port_host(ri.router) == self.host):
|
||||
ns_name = self.get_snat_ns_name(ri.router['id'])
|
||||
ns_name = ri.snat_namespace.name
|
||||
else:
|
||||
# not hosting agent - no work to do
|
||||
LOG.debug('DVR: CSNAT not hosted: %s', ex_gw_port)
|
||||
|
@ -780,7 +686,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
namespace=ns_name,
|
||||
prefix=EXTERNAL_DEV_PREFIX)
|
||||
if ri.router['distributed']:
|
||||
self._destroy_snat_namespace(ns_name)
|
||||
ri.delete_snat_namespace()
|
||||
|
||||
def external_gateway_nat_rules(self, ex_gw_ip, interface_name):
|
||||
rules = [('POSTROUTING', '! -i %(interface_name)s '
|
||||
|
@ -834,7 +740,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
['ip_address'], port, interface_name)
|
||||
if (self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
and self.get_gw_port_host(ri.router) == self.host):
|
||||
ns_name = self.get_snat_ns_name(ri.router['id'])
|
||||
ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
|
||||
ri.router['id'])
|
||||
self._set_subnet_info(sn_port)
|
||||
interface_name = (
|
||||
self.get_snat_int_device_name(sn_port['id']))
|
||||
|
@ -860,7 +767,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
snat_interface = (
|
||||
self.get_snat_int_device_name(snat_port['id'])
|
||||
)
|
||||
ns_name = self.get_snat_ns_name(ri.router['id'])
|
||||
ns_name = ri.snat_namespace.name
|
||||
prefix = dvr.SNAT_INT_DEV_PREFIX
|
||||
if ip_lib.device_exists(snat_interface,
|
||||
namespace=ns_name):
|
||||
|
@ -1013,11 +920,18 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
# uncaught -- prevents setting it to False below then the next call
|
||||
# to periodic_sync_routers_task will re-enter this code and try again.
|
||||
|
||||
# Capture a picture of namespaces *before* fetching the full list from
|
||||
# the database. This is important to correctly identify stale ones.
|
||||
namespaces = set()
|
||||
if self._clean_stale_namespaces:
|
||||
namespaces = self._list_namespaces()
|
||||
# Context manager self.namespaces_manager captures a picture of
|
||||
# namespaces *before* fetch_and_sync_all_routers fetches the full list
|
||||
# of routers from the database. This is important to correctly
|
||||
# identify stale ones.
|
||||
|
||||
try:
|
||||
with self.namespaces_manager as ns_manager:
|
||||
self.fetch_and_sync_all_routers(context, ns_manager)
|
||||
except n_exc.AbortSyncRouters:
|
||||
self.fullsync = True
|
||||
|
||||
def fetch_and_sync_all_routers(self, context, ns_manager):
|
||||
prev_router_ids = set(self.router_info)
|
||||
timestamp = timeutils.utcnow()
|
||||
|
||||
|
@ -1030,9 +944,11 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
|
||||
except oslo_messaging.MessagingException:
|
||||
LOG.exception(_LE("Failed synchronizing routers due to RPC error"))
|
||||
raise n_exc.AbortSyncRouters()
|
||||
else:
|
||||
LOG.debug('Processing :%r', routers)
|
||||
for r in routers:
|
||||
ns_manager.keep_router(r['id'])
|
||||
update = queue.RouterUpdate(r['id'],
|
||||
queue.PRIORITY_SYNC_ROUTERS_TASK,
|
||||
router=r,
|
||||
|
@ -1041,24 +957,17 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
self.fullsync = False
|
||||
LOG.debug("periodic_sync_routers_task successfully completed")
|
||||
|
||||
# Resync is not necessary for the cleanup of stale namespaces
|
||||
curr_router_ids = set([r['id'] for r in routers])
|
||||
|
||||
# Two kinds of stale routers: Routers for which info is cached in
|
||||
# self.router_info and the others. First, handle the former.
|
||||
# Delete routers that have disappeared since the last sync
|
||||
for router_id in prev_router_ids - curr_router_ids:
|
||||
ns_manager.keep_router(router_id)
|
||||
update = queue.RouterUpdate(router_id,
|
||||
queue.PRIORITY_SYNC_ROUTERS_TASK,
|
||||
timestamp=timestamp,
|
||||
action=queue.DELETE_ROUTER)
|
||||
self._queue.add(update)
|
||||
|
||||
# Next, one effort to clean out namespaces for which we don't have
|
||||
# a record. (i.e. _clean_stale_namespaces=False after one pass)
|
||||
if self._clean_stale_namespaces:
|
||||
ids_to_keep = curr_router_ids | prev_router_ids
|
||||
self._cleanup_namespaces(namespaces, ids_to_keep)
|
||||
|
||||
def after_start(self):
|
||||
eventlet.spawn_n(self._process_routers_loop)
|
||||
LOG.info(_LI("L3 agent started"))
|
||||
|
|
|
@ -17,6 +17,7 @@ import netaddr
|
|||
import weakref
|
||||
|
||||
from neutron.agent.l3 import dvr_fip_ns
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import constants as l3_constants
|
||||
|
@ -25,8 +26,9 @@ from neutron.openstack.common import log as logging
|
|||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
SNAT_INT_DEV_PREFIX = 'sg-'
|
||||
SNAT_NS_PREFIX = 'snat-'
|
||||
# TODO(Carl) Following constants retained to increase SNR during refactoring
|
||||
SNAT_INT_DEV_PREFIX = dvr_snat_ns.SNAT_INT_DEV_PREFIX
|
||||
SNAT_NS_PREFIX = dvr_snat_ns.SNAT_NS_PREFIX
|
||||
# xor-folding mask used for IPv6 rule index
|
||||
MASK_30 = 0x3fffffff
|
||||
|
||||
|
@ -54,24 +56,10 @@ class AgentMixin(object):
|
|||
|
||||
return fip_ns
|
||||
|
||||
def _destroy_snat_namespace(self, ns):
|
||||
ns_ip = ip_lib.IPWrapper(namespace=ns)
|
||||
# delete internal interfaces
|
||||
for d in ns_ip.get_devices(exclude_loopback=True):
|
||||
if d.name.startswith(SNAT_INT_DEV_PREFIX):
|
||||
LOG.debug('Unplugging DVR device %s', d.name)
|
||||
self.driver.unplug(d.name, namespace=ns,
|
||||
prefix=SNAT_INT_DEV_PREFIX)
|
||||
|
||||
# TODO(mrsmith): delete ext-gw-port
|
||||
LOG.debug('DVR: destroy snat ns: %s', ns)
|
||||
if self.conf.router_delete_namespaces:
|
||||
self._delete_namespace(ns_ip, ns)
|
||||
|
||||
def _destroy_fip_namespace(self, ns):
|
||||
ex_net_id = ns[len(dvr_fip_ns.FIP_NS_PREFIX):]
|
||||
fip_ns = self.get_fip_ns(ex_net_id)
|
||||
fip_ns.destroy()
|
||||
fip_ns.delete()
|
||||
|
||||
def _set_subnet_arp_info(self, ri, port):
|
||||
"""Set ARP info retrieved from Plugin for existing ports."""
|
||||
|
@ -102,6 +90,7 @@ class AgentMixin(object):
|
|||
return (SNAT_INT_DEV_PREFIX +
|
||||
port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
# TODO(Carl) Remove this method when vpnaas no longer needs it.
|
||||
def get_snat_ns_name(self, router_id):
|
||||
return (SNAT_NS_PREFIX + router_id)
|
||||
|
||||
|
@ -150,21 +139,20 @@ class AgentMixin(object):
|
|||
def _create_dvr_gateway(self, ri, ex_gw_port, gw_interface_name,
|
||||
snat_ports):
|
||||
"""Create SNAT namespace."""
|
||||
snat_ns_name = self.get_snat_ns_name(ri.router['id'])
|
||||
self._create_namespace(snat_ns_name)
|
||||
snat_ns = ri.create_snat_namespace()
|
||||
# connect snat_ports to br_int from SNAT namespace
|
||||
for port in snat_ports:
|
||||
# create interface_name
|
||||
self._set_subnet_info(port)
|
||||
interface_name = self.get_snat_int_device_name(port['id'])
|
||||
self._internal_network_added(snat_ns_name, port['network_id'],
|
||||
self._internal_network_added(snat_ns.name, port['network_id'],
|
||||
port['id'], port['ip_cidr'],
|
||||
port['mac_address'], interface_name,
|
||||
SNAT_INT_DEV_PREFIX)
|
||||
self._external_gateway_added(ri, ex_gw_port, gw_interface_name,
|
||||
snat_ns_name, preserve_ips=[])
|
||||
snat_ns.name, preserve_ips=[])
|
||||
ri.snat_iptables_manager = iptables_manager.IptablesManager(
|
||||
namespace=snat_ns_name,
|
||||
namespace=snat_ns.name,
|
||||
use_ipv6=self.use_ipv6)
|
||||
# kicks the FW Agent to add rules for the snat namespace
|
||||
self.process_router_add(ri)
|
||||
|
|
|
@ -16,10 +16,10 @@ import netaddr
|
|||
import os
|
||||
|
||||
from neutron.agent.l3 import link_local_allocator as lla
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.i18n import _LE
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
|
|||
FIP_NS_PREFIX = 'fip-'
|
||||
FIP_EXT_DEV_PREFIX = 'fg-'
|
||||
FIP_2_ROUTER_DEV_PREFIX = 'fpr-'
|
||||
ROUTER_2_FIP_DEV_PREFIX = 'rfp-'
|
||||
ROUTER_2_FIP_DEV_PREFIX = namespaces.ROUTER_2_FIP_DEV_PREFIX
|
||||
# Route Table index for FIPs
|
||||
FIP_RT_TBL = 16
|
||||
FIP_LL_SUBNET = '169.254.30.0/23'
|
||||
|
@ -36,8 +36,13 @@ FIP_PR_START = 32768
|
|||
FIP_PR_END = FIP_PR_START + 40000
|
||||
|
||||
|
||||
class FipNamespace(object):
|
||||
class FipNamespace(namespaces.Namespace):
|
||||
|
||||
def __init__(self, ext_net_id, agent_conf, driver, use_ipv6):
|
||||
name = FIP_NS_PREFIX + ext_net_id
|
||||
super(FipNamespace, self).__init__(
|
||||
name, agent_conf, driver, use_ipv6)
|
||||
|
||||
self._ext_net_id = ext_net_id
|
||||
self.agent_conf = agent_conf
|
||||
self.driver = driver
|
||||
|
@ -128,12 +133,9 @@ class FipNamespace(object):
|
|||
'-j CT --notrack')
|
||||
self._iptables_manager.apply()
|
||||
|
||||
def destroy(self):
|
||||
def delete(self):
|
||||
self.destroyed = True
|
||||
ns = self.get_name()
|
||||
# TODO(carl) Reconcile this with mlavelle's namespace work
|
||||
# TODO(carl) mlavelle's work has self.ip_wrapper
|
||||
ip_wrapper = ip_lib.IPWrapper(namespace=ns)
|
||||
ip_wrapper = ip_lib.IPWrapper(namespace=self.name)
|
||||
for d in ip_wrapper.get_devices(exclude_loopback=True):
|
||||
if d.name.startswith(FIP_2_ROUTER_DEV_PREFIX):
|
||||
# internal link between IRs and FIP NS
|
||||
|
@ -145,18 +147,14 @@ class FipNamespace(object):
|
|||
ext_net_bridge = self.agent_conf.external_network_bridge
|
||||
self.driver.unplug(d.name,
|
||||
bridge=ext_net_bridge,
|
||||
namespace=ns,
|
||||
namespace=self.name,
|
||||
prefix=FIP_EXT_DEV_PREFIX)
|
||||
LOG.debug('DVR: destroy fip ns: %s', ns)
|
||||
# TODO(mrsmith): add LOG warn if fip count != 0
|
||||
if self.agent_conf.router_delete_namespaces:
|
||||
try:
|
||||
ip_wrapper.netns.delete(ns)
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('Failed trying to delete namespace: %s'), ns)
|
||||
|
||||
self.agent_gateway_port = None
|
||||
|
||||
# TODO(mrsmith): add LOG warn if fip count != 0
|
||||
LOG.debug('DVR: destroy fip ns: %s', self.name)
|
||||
super(FipNamespace, self).delete()
|
||||
|
||||
def create_gateway_port(self, agent_gateway_port):
|
||||
"""Create Floating IP gateway port.
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
from neutron.agent.l3 import dvr_fip_ns
|
||||
from neutron.agent.l3 import dvr_snat_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
|
||||
|
@ -30,6 +31,7 @@ class DvrRouter(router.RouterInfo):
|
|||
# Linklocal subnet for router and floating IP namespace link
|
||||
self.rtr_fip_subnet = None
|
||||
self.dist_fip_count = None
|
||||
self.snat_namespace = None
|
||||
|
||||
def get_floating_ips(self):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
|
@ -121,7 +123,7 @@ class DvrRouter(router.RouterInfo):
|
|||
# destroying it. The two could end up conflicting on
|
||||
# creating/destroying interfaces and such. I think I'd like a
|
||||
# semaphore to sync creation/deletion of this namespace.
|
||||
self.fip_ns.destroy()
|
||||
self.fip_ns.delete()
|
||||
self.fip_ns = None
|
||||
|
||||
def add_floating_ip(self, fip, interface_name, device):
|
||||
|
@ -137,3 +139,21 @@ class DvrRouter(router.RouterInfo):
|
|||
def remove_floating_ip(self, device, ip_cidr):
|
||||
super(DvrRouter, self).remove_floating_ip(device, ip_cidr)
|
||||
self.floating_ip_removed_dist(ip_cidr)
|
||||
|
||||
def create_snat_namespace(self):
|
||||
# TODO(mlavalle): in the near future, this method should contain the
|
||||
# code in the L3 agent that creates a gateway for a dvr. The first step
|
||||
# is to move the creation of the snat namespace here
|
||||
self.snat_namespace = dvr_snat_ns.SnatNamespace(self.router['id'],
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
self.use_ipv6)
|
||||
self.snat_namespace.create()
|
||||
return self.snat_namespace
|
||||
|
||||
def delete_snat_namespace(self):
|
||||
# TODO(mlavalle): in the near future, this method should contain the
|
||||
# code in the L3 agent that removes an external gateway for a dvr. The
|
||||
# first step is to move the deletion of the snat namespace here
|
||||
self.snat_namespace.delete()
|
||||
self.snat_namespace = None
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# 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.
|
||||
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
SNAT_NS_PREFIX = 'snat-'
|
||||
SNAT_INT_DEV_PREFIX = 'sg-'
|
||||
|
||||
|
||||
class SnatNamespace(namespaces.Namespace):
|
||||
|
||||
def __init__(self, router_id, agent_conf, driver, use_ipv6):
|
||||
self.router_id = router_id
|
||||
name = self.get_snat_ns_name(router_id)
|
||||
super(SnatNamespace, self).__init__(
|
||||
name, agent_conf, driver, use_ipv6)
|
||||
|
||||
@classmethod
|
||||
def get_snat_ns_name(cls, router_id):
|
||||
return (SNAT_NS_PREFIX + router_id)
|
||||
|
||||
def delete(self):
|
||||
ns_ip = ip_lib.IPWrapper(namespace=self.name)
|
||||
for d in ns_ip.get_devices(exclude_loopback=True):
|
||||
if d.name.startswith(SNAT_INT_DEV_PREFIX):
|
||||
LOG.debug('Unplugging DVR device %s', d.name)
|
||||
self.driver.unplug(d.name, namespace=self.name,
|
||||
prefix=SNAT_INT_DEV_PREFIX)
|
||||
|
||||
# TODO(mrsmith): delete ext-gw-port
|
||||
LOG.debug('DVR: destroy snat ns: %s', self.name)
|
||||
super(SnatNamespace, self).delete()
|
|
@ -0,0 +1,120 @@
|
|||
# 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.
|
||||
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.i18n import _LE
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NamespaceManager(object):
|
||||
|
||||
"""Keeps track of namespaces that need to be cleaned up.
|
||||
|
||||
This is a context manager that looks to clean up stale namespaces that
|
||||
have not been touched by the end of the "with" statement it is called
|
||||
in. This formalizes the pattern used in the L3 agent which enumerated
|
||||
all of the namespaces known to the system before a full sync. Then,
|
||||
after the full sync completed, it cleaned up any that were not touched
|
||||
during the sync. The agent and this context manager use method keep_router
|
||||
to communicate. In the "with" statement, the agent calls keep_router to
|
||||
record the id's of the routers whose namespaces should be preserved.
|
||||
Any other router and snat namespace present in the system will be deleted
|
||||
by the __exit__ method of this context manager
|
||||
|
||||
This pattern can be more generally applicable to other resources
|
||||
besides namespaces in the future because it is idempotent and, as such,
|
||||
does not rely on state recorded at runtime in the agent so it handles
|
||||
agent restarts gracefully.
|
||||
"""
|
||||
|
||||
def __init__(self, agent_conf, driver, clean_stale):
|
||||
"""Initialize the NamespaceManager.
|
||||
|
||||
:param agent_conf: configuration from l3 agent
|
||||
:param driver: to perform operations on devices
|
||||
:param clean_stale: Whether to try to clean stale namespaces
|
||||
"""
|
||||
self.agent_conf = agent_conf
|
||||
self.driver = driver
|
||||
self._clean_stale = clean_stale
|
||||
|
||||
def __enter__(self):
|
||||
self._all_namespaces = set()
|
||||
self._ids_to_keep = set()
|
||||
if self._clean_stale:
|
||||
self._all_namespaces = self.list_all()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, value, traceback):
|
||||
# TODO(carl) Preserves old behavior of L3 agent where cleaning
|
||||
# namespaces was only done once after restart. Still a good idea?
|
||||
if exc_type:
|
||||
# An exception occured in the caller's with statement
|
||||
return False
|
||||
if not self._clean_stale:
|
||||
# No need to cleanup
|
||||
return True
|
||||
self._clean_stale = False
|
||||
|
||||
for ns in self._all_namespaces:
|
||||
_ns_prefix, ns_id = self.get_prefix_and_id(ns)
|
||||
if ns_id in self._ids_to_keep:
|
||||
continue
|
||||
if _ns_prefix == namespaces.NS_PREFIX:
|
||||
ns = namespaces.RouterNamespace(ns_id,
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
use_ipv6=False)
|
||||
else:
|
||||
ns = dvr_snat_ns.SnatNamespace(ns_id,
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
use_ipv6=False)
|
||||
try:
|
||||
ns.delete()
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('Failed to destroy stale namespace %s'), ns)
|
||||
|
||||
return True
|
||||
|
||||
def keep_router(self, router_id):
|
||||
self._ids_to_keep.add(router_id)
|
||||
|
||||
def get_prefix_and_id(self, ns_name):
|
||||
"""Get the prefix and id from the namespace name.
|
||||
|
||||
:param ns_name: The name of the namespace
|
||||
:returns: tuple with prefix and id or None if no prefix matches
|
||||
"""
|
||||
for prefix in [namespaces.NS_PREFIX, dvr_snat_ns.SNAT_NS_PREFIX]:
|
||||
if ns_name.startswith(prefix):
|
||||
return (prefix, ns_name[len(prefix):])
|
||||
|
||||
def is_managed(self, ns_name):
|
||||
"""Return True if the namespace name passed belongs to this manager."""
|
||||
return self.get_prefix_and_id(ns_name) is not None
|
||||
|
||||
def list_all(self):
|
||||
"""Get a set of all namespaces on host managed by this manager."""
|
||||
try:
|
||||
root_ip = ip_lib.IPWrapper()
|
||||
|
||||
namespaces = root_ip.get_namespaces()
|
||||
return set(ns for ns in namespaces if self.is_managed(ns))
|
||||
except RuntimeError:
|
||||
LOG.exception(_LE('RuntimeError in obtaining namespace list for '
|
||||
'namespace cleanup.'))
|
||||
return set()
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.i18n import _LE
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
NS_PREFIX = 'qrouter-'
|
||||
INTERNAL_DEV_PREFIX = 'qr-'
|
||||
EXTERNAL_DEV_PREFIX = 'qg-'
|
||||
# TODO(Carl) It is odd that this file needs this. It is a dvr detail.
|
||||
ROUTER_2_FIP_DEV_PREFIX = 'rfp-'
|
||||
|
||||
|
||||
class Namespace(object):
|
||||
|
||||
def __init__(self, name, agent_conf, driver, use_ipv6):
|
||||
self.name = name
|
||||
self.ip_wrapper_root = ip_lib.IPWrapper()
|
||||
self.agent_conf = agent_conf
|
||||
self.driver = driver
|
||||
self.use_ipv6 = use_ipv6
|
||||
|
||||
def create(self):
|
||||
ip_wrapper = self.ip_wrapper_root.ensure_namespace(self.name)
|
||||
cmd = ['sysctl', '-w', 'net.ipv4.ip_forward=1']
|
||||
ip_wrapper.netns.execute(cmd)
|
||||
if self.use_ipv6:
|
||||
cmd = ['sysctl', '-w', 'net.ipv6.conf.all.forwarding=1']
|
||||
ip_wrapper.netns.execute(cmd)
|
||||
|
||||
def delete(self):
|
||||
if self.agent_conf.router_delete_namespaces:
|
||||
try:
|
||||
self.ip_wrapper_root.netns.delete(self.name)
|
||||
except RuntimeError:
|
||||
msg = _LE('Failed trying to delete namespace: %s')
|
||||
LOG.exception(msg, self.name)
|
||||
|
||||
|
||||
class RouterNamespace(Namespace):
|
||||
|
||||
def __init__(self, router_id, agent_conf, driver, use_ipv6):
|
||||
self.router_id = router_id
|
||||
name = self._get_ns_name(router_id)
|
||||
super(RouterNamespace, self).__init__(
|
||||
name, agent_conf, driver, use_ipv6)
|
||||
|
||||
@staticmethod
|
||||
def _get_ns_name(router_id):
|
||||
return (NS_PREFIX + router_id)
|
||||
|
||||
def delete(self):
|
||||
ns_ip = ip_lib.IPWrapper(namespace=self.name)
|
||||
for d in ns_ip.get_devices(exclude_loopback=True):
|
||||
if d.name.startswith(INTERNAL_DEV_PREFIX):
|
||||
# device is on default bridge
|
||||
self.driver.unplug(d.name, namespace=self.name,
|
||||
prefix=INTERNAL_DEV_PREFIX)
|
||||
elif d.name.startswith(ROUTER_2_FIP_DEV_PREFIX):
|
||||
ns_ip.del_veth(d.name)
|
||||
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
|
||||
self.driver.unplug(
|
||||
d.name,
|
||||
bridge=self.agent_conf.external_network_bridge,
|
||||
namespace=self.name,
|
||||
prefix=EXTERNAL_DEV_PREFIX)
|
||||
|
||||
super(RouterNamespace, self).delete()
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import netaddr
|
||||
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import constants as l3_constants
|
||||
|
@ -32,8 +33,7 @@ class RouterInfo(object):
|
|||
router,
|
||||
agent_conf,
|
||||
interface_driver,
|
||||
use_ipv6=False,
|
||||
ns_name=None):
|
||||
use_ipv6=False):
|
||||
self.router_id = router_id
|
||||
self.ex_gw_port = None
|
||||
self._snat_enabled = None
|
||||
|
@ -42,7 +42,14 @@ class RouterInfo(object):
|
|||
self.floating_ips = set()
|
||||
# Invoke the setter for establishing initial SNAT action
|
||||
self.router = router
|
||||
self.ns_name = ns_name
|
||||
self.use_ipv6 = use_ipv6
|
||||
self.ns_name = None
|
||||
self.router_namespace = None
|
||||
if agent_conf.use_namespaces:
|
||||
ns = namespaces.RouterNamespace(
|
||||
router_id, agent_conf, interface_driver, use_ipv6)
|
||||
self.router_namespace = ns
|
||||
self.ns_name = ns.name
|
||||
self.iptables_manager = iptables_manager.IptablesManager(
|
||||
use_ipv6=use_ipv6,
|
||||
namespace=self.ns_name)
|
||||
|
@ -225,3 +232,12 @@ class RouterInfo(object):
|
|||
for fip in self.router.get(l3_constants.FLOATINGIP_KEY, []):
|
||||
fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ERROR
|
||||
return fip_statuses
|
||||
|
||||
def create(self):
|
||||
if self.router_namespace:
|
||||
self.router_namespace.create()
|
||||
|
||||
def delete(self):
|
||||
self.radvd.disable()
|
||||
if self.router_namespace:
|
||||
self.router_namespace.delete()
|
||||
|
|
|
@ -373,6 +373,10 @@ class NetworkIdOrRouterIdRequiredError(NeutronException):
|
|||
message = _('network_id and router_id are None. One must be provided.')
|
||||
|
||||
|
||||
class AbortSyncRouters(NeutronException):
|
||||
message = _("Aborting periodic_sync_routers_task due to an error")
|
||||
|
||||
|
||||
# Shared *aas exceptions, pending them being refactored out of Neutron
|
||||
# proper.
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
from neutron.agent.l3 import agent
|
||||
|
||||
|
||||
class TestL3NATAgent(agent.L3NATAgentWithStateReport):
|
||||
NESTED_NAMESPACE_SEPARATOR = '@'
|
||||
|
||||
def get_ns_name(self, router_id):
|
||||
ns_name = super(TestL3NATAgent, self).get_ns_name(router_id)
|
||||
return "%s%s%s" % (ns_name, self.NESTED_NAMESPACE_SEPARATOR, self.host)
|
||||
|
||||
def get_router_id(self, ns_name):
|
||||
# 'ns_name' should be in the format of: 'qrouter-<id>@<host>'.
|
||||
return super(TestL3NATAgent, self).get_router_id(
|
||||
ns_name.split(self.NESTED_NAMESPACE_SEPARATOR)[0])
|
|
@ -26,6 +26,8 @@ import webob.exc
|
|||
|
||||
from neutron.agent.common import config as agent_config
|
||||
from neutron.agent.l3 import agent as neutron_l3_agent
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent import l3_agent as l3_agent_main
|
||||
from neutron.agent.linux import dhcp
|
||||
from neutron.agent.linux import external_process
|
||||
|
@ -39,7 +41,6 @@ from neutron.common import utils as common_utils
|
|||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.services import advanced_service as adv_svc
|
||||
from neutron.tests.common.agents import l3_agent as l3_test_agent
|
||||
from neutron.tests.functional.agent.linux import base
|
||||
from neutron.tests.functional.agent.linux import helpers
|
||||
from neutron.tests.unit import test_l3_agent
|
||||
|
@ -93,7 +94,7 @@ class L3AgentTestFramework(base.BaseOVSLinuxTestCase):
|
|||
conf.set_override('external_pids',
|
||||
get_temp_file_path('external/pids'))
|
||||
conf.set_override('host', host)
|
||||
agent = l3_test_agent.TestL3NATAgent(host, conf)
|
||||
agent = neutron_l3_agent.L3NATAgentWithStateReport(host, conf)
|
||||
mock.patch.object(ip_lib, 'send_gratuitous_arp').start()
|
||||
|
||||
return agent
|
||||
|
@ -475,13 +476,16 @@ class L3AgentTestCase(L3AgentTestFramework):
|
|||
router_info = self.generate_router_info(enable_ha=True)
|
||||
router1 = self._create_router(self.agent, router_info)
|
||||
self._add_fip(router1, '192.168.111.12')
|
||||
restarted_agent = l3_test_agent.TestL3NATAgent(self.agent.host,
|
||||
self.agent.conf)
|
||||
restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
|
||||
self.agent.host, self.agent.conf)
|
||||
self._create_router(restarted_agent, router1.router)
|
||||
utils.wait_until_true(lambda: self._floating_ips_configured(router1))
|
||||
|
||||
|
||||
class L3HATestFramework(L3AgentTestFramework):
|
||||
|
||||
NESTED_NAMESPACE_SEPARATOR = '@'
|
||||
|
||||
def setUp(self):
|
||||
super(L3HATestFramework, self).setUp()
|
||||
self.failover_agent = self._configure_agent('agent2')
|
||||
|
@ -497,6 +501,11 @@ class L3HATestFramework(L3AgentTestFramework):
|
|||
|
||||
def test_ha_router_failover(self):
|
||||
router_info = self.generate_router_info(enable_ha=True)
|
||||
ns_name = "%s%s%s" % (
|
||||
namespaces.RouterNamespace._get_ns_name(router_info['id']),
|
||||
self.NESTED_NAMESPACE_SEPARATOR, self.agent.host)
|
||||
mock.patch.object(namespaces.RouterNamespace, '_get_ns_name',
|
||||
return_value=ns_name).start()
|
||||
router1 = self.manage_router(self.agent, router_info)
|
||||
|
||||
router_info_2 = copy.deepcopy(router_info)
|
||||
|
@ -504,6 +513,11 @@ class L3HATestFramework(L3AgentTestFramework):
|
|||
test_l3_agent.get_ha_interface(ip='169.254.192.2',
|
||||
mac='22:22:22:22:22:22'))
|
||||
|
||||
ns_name = "%s%s%s" % (
|
||||
namespaces.RouterNamespace._get_ns_name(router_info_2['id']),
|
||||
self.NESTED_NAMESPACE_SEPARATOR, self.failover_agent.host)
|
||||
mock.patch.object(namespaces.RouterNamespace, '_get_ns_name',
|
||||
return_value=ns_name).start()
|
||||
router2 = self.manage_router(self.failover_agent, router_info_2)
|
||||
|
||||
utils.wait_until_true(lambda: router1.ha_state == 'master')
|
||||
|
@ -719,7 +733,8 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
|
||||
def _assert_dvr_external_device(self, router):
|
||||
external_port = router.get_ex_gw_port()
|
||||
snat_ns_name = self.agent.get_snat_ns_name(router.router_id)
|
||||
snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
|
||||
router.router_id)
|
||||
|
||||
# if the agent is in dvr_snat mode, then we have to check
|
||||
# that the correct ports and ip addresses exist in the
|
||||
|
@ -755,7 +770,8 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
self._assert_snat_namespace_does_not_exist(router)
|
||||
|
||||
def _assert_dvr_snat_gateway(self, router):
|
||||
namespace = self.agent.get_snat_ns_name(router.router_id)
|
||||
namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
|
||||
router.router_id)
|
||||
external_port = router.get_ex_gw_port()
|
||||
external_device_name = self.agent.get_external_device_name(
|
||||
external_port['id'])
|
||||
|
@ -767,7 +783,8 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
self.assertEqual(expected_gateway, existing_gateway)
|
||||
|
||||
def _assert_snat_namespace_does_not_exist(self, router):
|
||||
namespace = self.agent.get_snat_ns_name(router.router_id)
|
||||
namespace = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
|
||||
router.router_id)
|
||||
self.assertFalse(self._namespace_exists(namespace))
|
||||
|
||||
def _assert_dvr_floating_ips(self, router):
|
||||
|
|
|
@ -35,8 +35,9 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
|||
|
||||
def _create_router(self, router, **kwargs):
|
||||
agent_conf = mock.Mock()
|
||||
self.router_id = _uuid()
|
||||
return dvr_router.DvrRouter(mock.sentinel.myhost,
|
||||
mock.sentinel.router_id,
|
||||
self.router_id,
|
||||
router,
|
||||
agent_conf,
|
||||
mock.sentinel.interface_driver,
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
import mock
|
||||
|
||||
from neutron.agent.l3 import ha_router
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.tests import base
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
|
||||
|
||||
class TestBasicRouterOperations(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
|
@ -25,11 +28,14 @@ class TestBasicRouterOperations(base.BaseTestCase):
|
|||
def _create_router(self, router=None, **kwargs):
|
||||
if not router:
|
||||
router = mock.MagicMock()
|
||||
return ha_router.HaRouter(mock.sentinel.router_id,
|
||||
self.agent_conf = mock.Mock()
|
||||
# NOTE The use_namespaces config will soon be deprecated
|
||||
self.agent_conf.use_namespaces = True
|
||||
self.router_id = _uuid()
|
||||
return ha_router.HaRouter(self.router_id,
|
||||
router,
|
||||
mock.sentinel.agent_conf,
|
||||
self.agent_conf,
|
||||
mock.sentinel.driver,
|
||||
ns_name=mock.sentinel.namespace,
|
||||
**kwargs)
|
||||
|
||||
def test_get_router_cidrs_returns_ha_cidrs(self):
|
||||
|
|
|
@ -28,9 +28,13 @@ 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,
|
||||
self.agent_conf = mock.Mock()
|
||||
# NOTE The use_namespaces config will soon be deprecated
|
||||
self.agent_conf.use_namespaces = True
|
||||
self.router_id = _uuid()
|
||||
return router_info.RouterInfo(self.router_id,
|
||||
router,
|
||||
mock.sentinel.agent_conf,
|
||||
self.agent_conf,
|
||||
mock.sentinel.interface_driver,
|
||||
**kwargs)
|
||||
|
||||
|
|
|
@ -17,8 +17,11 @@ 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.openstack.common import uuidutils
|
||||
from neutron.tests import base
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
|
||||
|
||||
class BasicRouterTestCaseFramework(base.BaseTestCase):
|
||||
def _create_router(self, router=None, **kwargs):
|
||||
|
@ -26,11 +29,11 @@ class BasicRouterTestCaseFramework(base.BaseTestCase):
|
|||
router = mock.MagicMock()
|
||||
self.agent_conf = mock.Mock()
|
||||
self.driver = mock.Mock()
|
||||
return legacy_router.LegacyRouter(mock.sentinel.router_id,
|
||||
self.router_id = _uuid()
|
||||
return legacy_router.LegacyRouter(self.router_id,
|
||||
router,
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
ns_name=mock.sentinel.namespace,
|
||||
**kwargs)
|
||||
|
||||
|
||||
|
@ -46,7 +49,7 @@ class TestBasicRouterOperations(BasicRouterTestCaseFramework):
|
|||
device.addr.delete.assert_called_once_with(4, cidr)
|
||||
self.driver.delete_conntrack_state.assert_called_once_with(
|
||||
ip=cidr,
|
||||
namespace=mock.sentinel.namespace)
|
||||
namespace=ri.ns_name)
|
||||
|
||||
|
||||
@mock.patch.object(ip_lib, 'send_gratuitous_arp')
|
||||
|
@ -55,13 +58,12 @@ class TestAddFloatingIpWithMockGarp(BasicRouterTestCaseFramework):
|
|||
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,
|
||||
ri.ns_name,
|
||||
mock.sentinel.interface_name,
|
||||
ip,
|
||||
mock.sentinel.arp_count)
|
||||
|
|
|
@ -26,6 +26,7 @@ class TestRouterInfo(base.BaseTestCase):
|
|||
super(TestRouterInfo, self).setUp()
|
||||
|
||||
conf = agent_config.setup_conf()
|
||||
conf.use_namespaces = True
|
||||
|
||||
self.ip_cls_p = mock.patch('neutron.agent.linux.ip_lib.IPWrapper')
|
||||
ip_cls = self.ip_cls_p.start()
|
||||
|
@ -40,8 +41,7 @@ class TestRouterInfo(base.BaseTestCase):
|
|||
any_order=True)
|
||||
|
||||
def test_routing_table_update(self):
|
||||
ri = router_info.RouterInfo(_uuid(), {}, ns_name=_uuid(),
|
||||
**self.ri_kwargs)
|
||||
ri = router_info.RouterInfo(_uuid(), {}, **self.ri_kwargs)
|
||||
ri.router = {}
|
||||
|
||||
fake_route1 = {'destination': '135.207.0.0/16',
|
||||
|
@ -70,8 +70,7 @@ class TestRouterInfo(base.BaseTestCase):
|
|||
self._check_agent_method_called(expected)
|
||||
|
||||
def test_routes_updated(self):
|
||||
ri = router_info.RouterInfo(_uuid(), {}, ns_name=_uuid(),
|
||||
**self.ri_kwargs)
|
||||
ri = router_info.RouterInfo(_uuid(), {}, **self.ri_kwargs)
|
||||
ri.router = {}
|
||||
|
||||
fake_old_routes = []
|
||||
|
|
|
@ -97,7 +97,9 @@ class TestDvrFipNs(base.BaseTestCase):
|
|||
dev2.name = 'fg-aaaa'
|
||||
ip_wrapper.get_devices.return_value = [dev1, dev2]
|
||||
|
||||
self.fip_ns.destroy()
|
||||
self.conf.router_delete_namespaces = False
|
||||
|
||||
self.fip_ns.delete()
|
||||
|
||||
ext_net_bridge = self.conf.external_network_bridge
|
||||
ns_name = self.fip_ns.get_name()
|
||||
|
|
|
@ -25,11 +25,12 @@ from testtools import matchers
|
|||
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_router
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
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 namespaces
|
||||
from neutron.agent.l3 import router_info as l3router
|
||||
from neutron.agent.linux import external_process
|
||||
from neutron.agent.linux import interface
|
||||
|
@ -282,8 +283,9 @@ class BasicRouterOperationsFramework(base.BaseTestCase):
|
|||
network_id = _uuid()
|
||||
router = prepare_router_data(num_internal_ports=2)
|
||||
router_id = router['id']
|
||||
ri = l3router.RouterInfo(router_id, router, **self.ri_kwargs)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(router_id, router,
|
||||
**self.ri_kwargs)
|
||||
cidr = '99.0.1.9/24'
|
||||
mac = 'ca:fe:de:ad:be:ef'
|
||||
port = {'network_id': network_id,
|
||||
|
@ -305,12 +307,11 @@ class BasicRouterOperationsFramework(base.BaseTestCase):
|
|||
class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
def test_periodic_sync_routers_task_raise_exception(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
self.plugin_api.get_routers.side_effect = ValueError()
|
||||
with mock.patch.object(agent, '_cleanup_namespaces') as f:
|
||||
self.assertRaises(ValueError, agent.periodic_sync_routers_task,
|
||||
agent.context)
|
||||
self.assertTrue(agent.fullsync)
|
||||
self.assertFalse(f.called)
|
||||
self.plugin_api.get_routers.side_effect = ValueError
|
||||
self.assertRaises(ValueError,
|
||||
agent.periodic_sync_routers_task,
|
||||
agent.context)
|
||||
self.assertTrue(agent.fullsync)
|
||||
|
||||
def test_l3_initial_full_sync_done(self):
|
||||
with mock.patch.object(l3_agent.L3NATAgent,
|
||||
|
@ -323,14 +324,12 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
def test_periodic_sync_routers_task_call_clean_stale_namespaces(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
self.plugin_api.get_routers.return_value = []
|
||||
with mock.patch.object(agent, '_cleanup_namespaces') as f:
|
||||
agent.periodic_sync_routers_task(agent.context)
|
||||
self.assertTrue(f.called)
|
||||
agent.periodic_sync_routers_task(agent.context)
|
||||
self.assertFalse(agent.namespaces_manager._clean_stale)
|
||||
|
||||
def test_router_info_create(self):
|
||||
id = _uuid()
|
||||
ns = "ns-" + id
|
||||
ri = l3router.RouterInfo(id, {}, ns_name=ns, **self.ri_kwargs)
|
||||
ri = l3router.RouterInfo(id, {}, **self.ri_kwargs)
|
||||
|
||||
self.assertTrue(ri.ns_name.endswith(id))
|
||||
|
||||
|
@ -347,8 +346,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
'enable_snat': True,
|
||||
'routes': [],
|
||||
'gw_port': ex_gw_port}
|
||||
ns = "ns-" + id
|
||||
ri = l3router.RouterInfo(id, router, ns_name=ns, **self.ri_kwargs)
|
||||
ri = l3router.RouterInfo(id, router, **self.ri_kwargs)
|
||||
self.assertTrue(ri.ns_name.endswith(id))
|
||||
self.assertEqual(ri.router, router)
|
||||
|
||||
|
@ -400,13 +398,13 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
self.assertEqual(agent._set_subnet_info.call_count, 1)
|
||||
self.assertEqual(agent._internal_network_added.call_count, 2)
|
||||
agent._internal_network_added.assert_called_with(
|
||||
agent.get_snat_ns_name(ri.router['id']),
|
||||
dvr_snat_ns.SnatNamespace.get_snat_ns_name(ri.router['id']),
|
||||
sn_port['network_id'],
|
||||
sn_port['id'],
|
||||
sn_port['ip_cidr'],
|
||||
sn_port['mac_address'],
|
||||
agent.get_snat_int_device_name(sn_port['id']),
|
||||
dvr.SNAT_INT_DEV_PREFIX)
|
||||
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
|
||||
|
||||
def test_agent_add_internal_network(self):
|
||||
self._test_internal_network_action('add')
|
||||
|
@ -419,9 +417,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
def _test_external_gateway_action(self, action, router):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(router['id'], router,
|
||||
ns_name=agent.get_ns_name(router['id']),
|
||||
**self.ri_kwargs)
|
||||
ex_net_id = _uuid()
|
||||
# Special setup for dvr routers
|
||||
if router.get('distributed'):
|
||||
|
@ -429,7 +424,16 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
agent.host = HOSTNAME
|
||||
agent._create_dvr_gateway = mock.Mock()
|
||||
agent.get_snat_interfaces = mock.Mock(return_value=self.snat_ports)
|
||||
ri = dvr_router.DvrRouter(HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
**self.ri_kwargs)
|
||||
ri.create_snat_namespace()
|
||||
ri.fip_ns = agent.get_fip_ns(ex_net_id)
|
||||
else:
|
||||
ri = l3router.RouterInfo(
|
||||
router['id'], router,
|
||||
**self.ri_kwargs)
|
||||
|
||||
ex_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
|
||||
'subnet_id': _uuid()}],
|
||||
|
@ -496,9 +500,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
def test_external_gateway_updated(self):
|
||||
router = prepare_router_data(num_internal_ports=2)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(router['id'], router,
|
||||
ns_name=agent.get_ns_name(router['id']),
|
||||
**self.ri_kwargs)
|
||||
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
|
||||
interface_name, ex_gw_port = self._prepare_ext_gw_test(agent)
|
||||
|
||||
fake_fip = {'floatingips': [{'id': _uuid(),
|
||||
|
@ -523,8 +525,12 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
def _test_ext_gw_updated_dvr_agent_mode(self, host,
|
||||
agent_mode, expected_call_count):
|
||||
router = prepare_router_data(num_internal_ports=2)
|
||||
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = dvr_router.DvrRouter(HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
**self.ri_kwargs)
|
||||
ri.create_snat_namespace()
|
||||
interface_name, ex_gw_port = self._prepare_ext_gw_test(agent)
|
||||
agent._external_gateway_added = mock.Mock()
|
||||
|
||||
|
@ -722,7 +728,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(
|
||||
'foo_router_id',
|
||||
{'distributed': True, 'gw_port_host': HOSTNAME}, **self.ri_kwargs)
|
||||
{'distributed': True, 'gw_port_host': HOSTNAME},
|
||||
**self.ri_kwargs)
|
||||
with mock.patch.object(l3_agent.ip_lib, 'IPDevice') as f:
|
||||
agent._update_arp_entry(ri, mock.ANY, mock.ANY,
|
||||
'foo_subnet_id', 'add')
|
||||
|
@ -748,11 +755,13 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
def test_process_cent_router(self):
|
||||
router = prepare_router_data()
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
|
||||
self._test_process_router(ri)
|
||||
self._test_process_router(ri, agent)
|
||||
|
||||
def test_process_dist_router(self):
|
||||
router = prepare_router_data()
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = dvr_router.DvrRouter(HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
|
@ -763,11 +772,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
'fixed_ips': [{'subnet_id': subnet_id,
|
||||
'ip_address': '1.2.3.4'}]}]
|
||||
ri.router['gw_port_host'] = None
|
||||
self._test_process_router(ri)
|
||||
self._test_process_router(ri, agent)
|
||||
|
||||
def _test_process_router(self, ri):
|
||||
def _test_process_router(self, ri, agent):
|
||||
router = ri.router
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
agent.host = HOSTNAME
|
||||
fake_fip_id = 'fake_fip_id'
|
||||
agent.create_dvr_fip_interfaces = mock.Mock()
|
||||
|
@ -944,9 +952,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
router = prepare_router_data(enable_snat=True)
|
||||
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
|
||||
ri = legacy_router.LegacyRouter(router['id'], router, **self.ri_kwargs)
|
||||
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
|
||||
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
|
||||
agent.get_external_device_name = mock.Mock(return_value='exgw')
|
||||
self._test_process_floating_ip_addresses_add(ri, agent)
|
||||
|
||||
|
@ -1443,7 +1451,11 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
||||
agent._destroy_namespace(namespace)
|
||||
ns = namespaces.RouterNamespace(
|
||||
'bar', self.conf, agent.driver, agent.use_ipv6)
|
||||
ns.create()
|
||||
|
||||
ns.delete()
|
||||
self.mock_driver.unplug.assert_called_once_with('qr-aaaa',
|
||||
prefix='qr-',
|
||||
namespace='qrouter'
|
||||
|
@ -1452,14 +1464,20 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
def test_destroy_router_namespace_skips_ns_removal(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
agent._destroy_router_namespace("fakens")
|
||||
ns = namespaces.Namespace(
|
||||
'qrouter-bar', self.conf, agent.driver, agent.use_ipv6)
|
||||
ns.create()
|
||||
ns.delete()
|
||||
self.assertEqual(self.mock_ip.netns.delete.call_count, 0)
|
||||
|
||||
def test_destroy_router_namespace_removes_ns(self):
|
||||
self.conf.set_override('router_delete_namespaces', True)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
agent._destroy_router_namespace("fakens")
|
||||
self.mock_ip.netns.delete.assert_called_once_with("fakens")
|
||||
ns = namespaces.Namespace(
|
||||
'qrouter-bar', self.conf, agent.driver, agent.use_ipv6)
|
||||
ns.create()
|
||||
ns.delete()
|
||||
self.mock_ip.netns.delete.assert_called_once_with("qrouter-bar")
|
||||
|
||||
def _configure_metadata_proxy(self, enableflag=True):
|
||||
if not enableflag:
|
||||
|
@ -1509,7 +1527,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
self.conf.set_override('router_id', '1234')
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
self.assertEqual('1234', agent.conf.router_id)
|
||||
self.assertFalse(agent._clean_stale_namespaces)
|
||||
self.assertFalse(agent.namespaces_manager._clean_stale)
|
||||
|
||||
def test_process_routers_update_rpc_timeout_on_get_routers(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
@ -1644,15 +1662,19 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
msg = _LE("Error importing interface driver '%s'")
|
||||
log.error.assert_called_once_with(msg, 'wrong_driver')
|
||||
|
||||
@mock.patch.object(namespaces.RouterNamespace, 'delete')
|
||||
@mock.patch.object(dvr_snat_ns.SnatNamespace, 'delete')
|
||||
def _cleanup_namespace_test(self,
|
||||
stale_namespace_list,
|
||||
router_list,
|
||||
other_namespaces):
|
||||
other_namespaces,
|
||||
mock_snat_ns,
|
||||
mock_router_ns):
|
||||
self.conf.set_override('router_delete_namespaces', True)
|
||||
|
||||
good_namespace_list = [l3_agent.NS_PREFIX + r['id']
|
||||
good_namespace_list = [namespaces.NS_PREFIX + r['id']
|
||||
for r in router_list]
|
||||
good_namespace_list += [dvr.SNAT_NS_PREFIX + r['id']
|
||||
good_namespace_list += [dvr_snat_ns.SNAT_NS_PREFIX + r['id']
|
||||
for r in router_list]
|
||||
self.mock_ip.get_namespaces.return_value = (stale_namespace_list +
|
||||
good_namespace_list +
|
||||
|
@ -1660,34 +1682,27 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
||||
self.assertTrue(agent._clean_stale_namespaces)
|
||||
self.assertTrue(agent.namespaces_manager._clean_stale)
|
||||
|
||||
pm = self.external_process.return_value
|
||||
pm.reset_mock()
|
||||
|
||||
agent._destroy_router_namespace = mock.MagicMock()
|
||||
agent._destroy_snat_namespace = mock.MagicMock()
|
||||
ns_list = agent._list_namespaces()
|
||||
agent._cleanup_namespaces(ns_list, [r['id'] for r in router_list])
|
||||
|
||||
# Expect process manager to disable metadata proxy per qrouter ns
|
||||
with agent.namespaces_manager as ns_manager:
|
||||
for r in router_list:
|
||||
ns_manager.keep_router(r['id'])
|
||||
qrouters = [n for n in stale_namespace_list
|
||||
if n.startswith(l3_agent.NS_PREFIX)]
|
||||
if n.startswith(namespaces.NS_PREFIX)]
|
||||
self.assertEqual(mock_router_ns.call_count, len(qrouters))
|
||||
self.assertEqual(mock_snat_ns.call_count,
|
||||
len(stale_namespace_list) - len(qrouters))
|
||||
|
||||
self.assertEqual(agent._destroy_router_namespace.call_count,
|
||||
len(qrouters))
|
||||
self.assertEqual(agent._destroy_snat_namespace.call_count,
|
||||
len(stale_namespace_list) - len(qrouters))
|
||||
expected_args = [mock.call(ns) for ns in qrouters]
|
||||
agent._destroy_router_namespace.assert_has_calls(expected_args,
|
||||
any_order=True)
|
||||
self.assertFalse(agent._clean_stale_namespaces)
|
||||
self.assertFalse(agent.namespaces_manager._clean_stale)
|
||||
|
||||
def test_cleanup_namespace(self):
|
||||
self.conf.set_override('router_id', None)
|
||||
stale_namespaces = [l3_agent.NS_PREFIX + 'foo',
|
||||
l3_agent.NS_PREFIX + 'bar',
|
||||
dvr.SNAT_NS_PREFIX + 'foo']
|
||||
stale_namespaces = [namespaces.NS_PREFIX + 'foo',
|
||||
namespaces.NS_PREFIX + 'bar',
|
||||
dvr_snat_ns.SNAT_NS_PREFIX + 'foo']
|
||||
other_namespaces = ['unknown']
|
||||
|
||||
self._cleanup_namespace_test(stale_namespaces,
|
||||
|
@ -1696,9 +1711,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
def test_cleanup_namespace_with_registered_router_ids(self):
|
||||
self.conf.set_override('router_id', None)
|
||||
stale_namespaces = [l3_agent.NS_PREFIX + 'cccc',
|
||||
l3_agent.NS_PREFIX + 'eeeee',
|
||||
dvr.SNAT_NS_PREFIX + 'fffff']
|
||||
stale_namespaces = [namespaces.NS_PREFIX + 'cccc',
|
||||
namespaces.NS_PREFIX + 'eeeee',
|
||||
dvr_snat_ns.SNAT_NS_PREFIX + 'fffff']
|
||||
router_list = [{'id': 'foo', 'distributed': False},
|
||||
{'id': 'aaaa', 'distributed': False}]
|
||||
other_namespaces = ['qdhcp-aabbcc', 'unknown']
|
||||
|
@ -1709,9 +1724,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
|
||||
def test_cleanup_namespace_with_conf_router_id(self):
|
||||
self.conf.set_override('router_id', 'bbbbb')
|
||||
stale_namespaces = [l3_agent.NS_PREFIX + 'cccc',
|
||||
l3_agent.NS_PREFIX + 'eeeee',
|
||||
l3_agent.NS_PREFIX + self.conf.router_id]
|
||||
stale_namespaces = [namespaces.NS_PREFIX + 'cccc',
|
||||
namespaces.NS_PREFIX + 'eeeee',
|
||||
namespaces.NS_PREFIX + self.conf.router_id]
|
||||
router_list = [{'id': 'foo', 'distributed': False},
|
||||
{'id': 'aaaa', 'distributed': False}]
|
||||
other_namespaces = ['qdhcp-aabbcc', 'unknown']
|
||||
|
@ -1723,7 +1738,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
def test_create_dvr_gateway(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router = prepare_router_data()
|
||||
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
|
||||
ri = dvr_router.DvrRouter(HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
**self.ri_kwargs)
|
||||
|
||||
port_id = _uuid()
|
||||
dvr_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
|
||||
|
@ -1865,10 +1883,11 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
|||
mock.patch(ensure_dir).start()
|
||||
execute = mock.patch(utils_execute).start()
|
||||
|
||||
radvd = ra.DaemonMonitor(router['id'],
|
||||
agent.get_ns_name(router['id']),
|
||||
agent.process_monitor,
|
||||
FakeDev)
|
||||
radvd = ra.DaemonMonitor(
|
||||
router['id'],
|
||||
namespaces.RouterNamespace._get_ns_name(router['id']),
|
||||
agent.process_monitor,
|
||||
FakeDev)
|
||||
radvd.enable(router['_interfaces'])
|
||||
|
||||
cmd = execute.call_args[0][0]
|
||||
|
|
Loading…
Reference in New Issue