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
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):
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()
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:
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,
}
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:
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)
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, [])
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'])
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)
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 '
['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']))
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):
# 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()
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,
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"))
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
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
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."""
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)
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)
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__)
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'
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
'-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
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.
# 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
# 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."""
# 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):
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
--- /dev/null
+# 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()
--- /dev/null
+# 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()
--- /dev/null
+# 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()
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
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
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)
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()
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.
+++ /dev/null
-# 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])
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
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
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
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')
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)
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')
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
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'])
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):
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,
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):
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):
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)
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):
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)
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')
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)
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()
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',
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 = []
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()
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
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,
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,
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))
'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)
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')
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'):
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()}],
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(),
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()
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')
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,
'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()
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)
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'
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:
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)
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 +
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,
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']
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']
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',
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]