DVR: Fix IPtables driver for metering with DVR routers
IPTables driver for metering was not handling the DVR router
namespaces properly for configuring the metering forward rules.
This patch addresses the issue by configuring the iptables
manager based on the availability of the namespace and selecting
the respective namespaces such as router namespace and snat
namespace with the right external device.
Closes-Bug: #1506567
(cherry picked from commit ec6ed98cfa
)
Conflicts:
neutron/db/metering/metering_db.py
neutron/services/metering/drivers/iptables/iptables_driver.py
Change-Id: I6790d6ff42d9f8fa220e1a231ae94cbf8b60506c
This commit is contained in:
parent
f346db1871
commit
ffcd24a3a8
@ -23,6 +23,7 @@ from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import constants
|
||||
from neutron.db import common_db_mixin as base_db
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import l3_dvr_db
|
||||
from neutron.db import model_base
|
||||
from neutron.extensions import metering
|
||||
|
||||
@ -194,12 +195,14 @@ class MeteringDbMixin(metering.MeteringPluginBase,
|
||||
return rules
|
||||
|
||||
def _make_router_dict(self, router):
|
||||
distributed = l3_dvr_db.is_distributed_router(router)
|
||||
res = {'id': router['id'],
|
||||
'name': router['name'],
|
||||
'tenant_id': router['tenant_id'],
|
||||
'admin_state_up': router['admin_state_up'],
|
||||
'status': router['status'],
|
||||
'gw_port_id': router['gw_port_id'],
|
||||
'distributed': distributed,
|
||||
constants.METERING_LABEL_KEY: []}
|
||||
|
||||
return res
|
||||
|
@ -20,7 +20,10 @@ import six
|
||||
|
||||
from neutron._i18n import _, _LE, _LI
|
||||
from neutron.agent.common import config
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.linux import interface
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import constants as constants
|
||||
from neutron.common import ipv6_utils
|
||||
@ -31,6 +34,7 @@ LOG = logging.getLogger(__name__)
|
||||
NS_PREFIX = 'qrouter-'
|
||||
WRAP_NAME = 'neutron-meter'
|
||||
EXTERNAL_DEV_PREFIX = 'qg-'
|
||||
ROUTER_2_FIP_DEV_PREFIX = namespaces.ROUTER_2_FIP_DEV_PREFIX
|
||||
TOP_CHAIN = WRAP_NAME + "-FORWARD"
|
||||
RULE = '-r-'
|
||||
LABEL = '-l-'
|
||||
@ -70,6 +74,27 @@ class RouterWithMetering(object):
|
||||
self.router = router
|
||||
# TODO(cbrandily): deduplicate ns_name generation in metering/l3
|
||||
self.ns_name = NS_PREFIX + self.id
|
||||
self.iptables_manager = None
|
||||
self.snat_iptables_manager = None
|
||||
if self.router['distributed']:
|
||||
# If distributed routers then we need to apply the
|
||||
# metering agent label rules in the snat namespace as well.
|
||||
snat_ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
|
||||
self.id)
|
||||
# Check for namespace existence before we assign the
|
||||
# snat_iptables_manager
|
||||
if ip_lib.IPWrapper().netns.exists(snat_ns_name):
|
||||
self.snat_iptables_manager = iptables_manager.IptablesManager(
|
||||
namespace=snat_ns_name,
|
||||
binary_name=WRAP_NAME,
|
||||
state_less=True,
|
||||
use_ipv6=ipv6_utils.is_enabled())
|
||||
# Check of namespace existence before we assign the iptables_manager
|
||||
# NOTE(Swami): If distributed routers, all external traffic on a
|
||||
# compute node will flow through the rfp interface in the router
|
||||
# namespace.
|
||||
ip_wrapper = ip_lib.IPWrapper(namespace=self.ns_name)
|
||||
if ip_wrapper.netns.exists(self.ns_name):
|
||||
self.iptables_manager = iptables_manager.IptablesManager(
|
||||
namespace=self.ns_name,
|
||||
binary_name=WRAP_NAME,
|
||||
@ -117,7 +142,12 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
|
||||
|
||||
if gw_port_id != old_gw_port_id:
|
||||
if old_rm:
|
||||
with IptablesManagerTransaction(old_rm.iptables_manager):
|
||||
if router.get('distributed'):
|
||||
old_rm_im = old_rm.snat_iptables_manager
|
||||
else:
|
||||
old_rm_im = old_rm.iptables_manager
|
||||
|
||||
with IptablesManagerTransaction(old_rm_im):
|
||||
self._process_disassociate_metering_label(router)
|
||||
if gw_port_id:
|
||||
self._process_associate_metering_label(router)
|
||||
@ -129,32 +159,34 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
|
||||
if router_id in self.routers:
|
||||
del self.routers[router_id]
|
||||
|
||||
def get_external_device_name(self, port_id):
|
||||
return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
def get_external_device_names(self, rm):
|
||||
gw_port_id = rm.router.get('gw_port_id')
|
||||
if not gw_port_id:
|
||||
return None, None
|
||||
|
||||
def _process_metering_label_rules(self, rm, rules, label_chain,
|
||||
rules_chain):
|
||||
im = rm.iptables_manager
|
||||
ex_gw_port = rm.router.get('gw_port_id')
|
||||
if not ex_gw_port:
|
||||
return
|
||||
# NOTE (Swami): External device 'qg' should be used on the
|
||||
# Router namespace if the router is legacy and should be used on
|
||||
# SNAT namespace if the router is distributed.
|
||||
ext_dev = (EXTERNAL_DEV_PREFIX +
|
||||
gw_port_id)[:self.driver.DEV_NAME_LEN]
|
||||
ext_snat_dev = (ROUTER_2_FIP_DEV_PREFIX +
|
||||
rm.id)[:self.driver.DEV_NAME_LEN]
|
||||
return ext_dev, ext_snat_dev
|
||||
|
||||
ext_dev = self.get_external_device_name(ex_gw_port)
|
||||
def _process_metering_label_rules(self, rules, label_chain,
|
||||
rules_chain, ext_dev, im):
|
||||
if not ext_dev:
|
||||
return
|
||||
|
||||
for rule in rules:
|
||||
self._add_rule_to_chain(ext_dev, rule, im,
|
||||
label_chain, rules_chain)
|
||||
|
||||
def _process_metering_label_rule_add(self, rm, rule, ext_dev,
|
||||
label_chain, rules_chain):
|
||||
im = rm.iptables_manager
|
||||
def _process_metering_label_rule_add(self, rule, ext_dev,
|
||||
label_chain, rules_chain, im):
|
||||
self._add_rule_to_chain(ext_dev, rule, im, label_chain, rules_chain)
|
||||
|
||||
def _process_metering_label_rule_delete(self, rm, rule, ext_dev,
|
||||
label_chain, rules_chain):
|
||||
im = rm.iptables_manager
|
||||
def _process_metering_label_rule_delete(self, rule, ext_dev,
|
||||
label_chain, rules_chain, im):
|
||||
self._remove_rule_from_chain(ext_dev, rule, im,
|
||||
label_chain, rules_chain)
|
||||
|
||||
@ -191,66 +223,74 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
|
||||
ipt_rule = '%s -j %s' % (dir_opt, label_chain)
|
||||
return ipt_rule
|
||||
|
||||
def _process_associate_metering_label(self, router):
|
||||
self._update_router(router)
|
||||
def _process_ns_specific_metering_label(self, router, ext_dev, im):
|
||||
'''Process metering label based on the associated namespaces.'''
|
||||
rm = self.routers.get(router['id'])
|
||||
|
||||
with IptablesManagerTransaction(rm.iptables_manager):
|
||||
with IptablesManagerTransaction(im):
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
|
||||
label_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
LABEL + label_id,
|
||||
wrap=False)
|
||||
rm.iptables_manager.ipv4['filter'].add_chain(label_chain,
|
||||
wrap=False)
|
||||
label_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + LABEL + label_id, wrap=False)
|
||||
im.ipv4['filter'].add_chain(label_chain, wrap=False)
|
||||
|
||||
rules_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
RULE + label_id,
|
||||
wrap=False)
|
||||
rm.iptables_manager.ipv4['filter'].add_chain(rules_chain,
|
||||
wrap=False)
|
||||
rm.iptables_manager.ipv4['filter'].add_rule(TOP_CHAIN, '-j ' +
|
||||
rules_chain,
|
||||
wrap=False)
|
||||
rules_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + RULE + label_id, wrap=False)
|
||||
im.ipv4['filter'].add_chain(rules_chain, wrap=False)
|
||||
im.ipv4['filter'].add_rule(
|
||||
TOP_CHAIN, '-j ' + rules_chain, wrap=False)
|
||||
|
||||
rm.iptables_manager.ipv4['filter'].add_rule(label_chain,
|
||||
'',
|
||||
wrap=False)
|
||||
im.ipv4['filter'].add_rule(
|
||||
label_chain, '', wrap=False)
|
||||
|
||||
rules = label.get('rules')
|
||||
if rules:
|
||||
self._process_metering_label_rules(rm, rules,
|
||||
label_chain,
|
||||
rules_chain)
|
||||
self._process_metering_label_rules(
|
||||
rules, label_chain, rules_chain, ext_dev, im)
|
||||
|
||||
rm.metering_labels[label_id] = label
|
||||
|
||||
def _process_disassociate_metering_label(self, router):
|
||||
def _process_associate_metering_label(self, router):
|
||||
self._update_router(router)
|
||||
rm = self.routers.get(router['id'])
|
||||
if not rm:
|
||||
return
|
||||
|
||||
with IptablesManagerTransaction(rm.iptables_manager):
|
||||
ext_dev, ext_snat_dev = self.get_external_device_names(rm)
|
||||
for (im, dev) in [(rm.iptables_manager, ext_dev),
|
||||
(rm.snat_iptables_manager, ext_snat_dev)]:
|
||||
if im:
|
||||
self._process_ns_specific_metering_label(router, dev, im)
|
||||
|
||||
def _process_ns_specific_disassociate_metering_label(self, router, im):
|
||||
'''Disassociate metering label based on specific namespaces.'''
|
||||
rm = self.routers.get(router['id'])
|
||||
with IptablesManagerTransaction(im):
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
if label_id not in rm.metering_labels:
|
||||
continue
|
||||
|
||||
label_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
LABEL + label_id,
|
||||
wrap=False)
|
||||
rules_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
RULE + label_id,
|
||||
wrap=False)
|
||||
label_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + LABEL + label_id, wrap=False)
|
||||
rules_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + RULE + label_id, wrap=False)
|
||||
im.ipv4['filter'].remove_chain(label_chain, wrap=False)
|
||||
im.ipv4['filter'].remove_chain(rules_chain, wrap=False)
|
||||
|
||||
rm.iptables_manager.ipv4['filter'].remove_chain(label_chain,
|
||||
wrap=False)
|
||||
rm.iptables_manager.ipv4['filter'].remove_chain(rules_chain,
|
||||
wrap=False)
|
||||
def _process_disassociate_metering_label(self, router):
|
||||
rm = self.routers.get(router['id'])
|
||||
if not rm:
|
||||
return
|
||||
|
||||
for im in [rm.iptables_manager, rm.snat_iptables_manager]:
|
||||
if im:
|
||||
self._process_ns_specific_disassociate_metering_label(
|
||||
router, im)
|
||||
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
del rm.metering_labels[label_id]
|
||||
|
||||
@log_helpers.log_method_call
|
||||
@ -279,61 +319,67 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver):
|
||||
def _remove_metering_label_rule(self, router):
|
||||
self._process_metering_rule_action(router, 'delete')
|
||||
|
||||
def _process_metering_rule_action_based_on_ns(
|
||||
self, router, action, ext_dev, im):
|
||||
'''Process metering rule actions based specific namespaces.'''
|
||||
with IptablesManagerTransaction(im):
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
label_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + LABEL + label_id, wrap=False)
|
||||
|
||||
rules_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + RULE + label_id, wrap=False)
|
||||
rule = label.get('rule')
|
||||
if rule:
|
||||
if action == 'create':
|
||||
self._process_metering_label_rule_add(
|
||||
rule, ext_dev, label_chain, rules_chain, im)
|
||||
elif action == 'delete':
|
||||
self._process_metering_label_rule_delete(
|
||||
rule, ext_dev, label_chain, rules_chain, im)
|
||||
|
||||
def _process_metering_rule_action(self, router, action):
|
||||
rm = self.routers.get(router['id'])
|
||||
if not rm:
|
||||
return
|
||||
ext_dev = self.get_external_device_name(rm.router['gw_port_id'])
|
||||
if not ext_dev:
|
||||
return
|
||||
with IptablesManagerTransaction(rm.iptables_manager):
|
||||
|
||||
ext_dev, ext_snat_dev = self.get_external_device_names(rm)
|
||||
for (im, dev) in [(rm.iptables_manager, ext_dev),
|
||||
(rm.snat_iptables_manager, ext_snat_dev)]:
|
||||
if im and dev:
|
||||
self._process_metering_rule_action_based_on_ns(
|
||||
router, action, dev, im)
|
||||
|
||||
def _update_metering_label_rules_based_on_ns(self, router, ext_dev, im):
|
||||
'''Update metering lable rules based on namespace.'''
|
||||
with IptablesManagerTransaction(im):
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
label_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
LABEL + label_id,
|
||||
wrap=False)
|
||||
|
||||
rules_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
RULE + label_id,
|
||||
wrap=False)
|
||||
rule = label.get('rule')
|
||||
if rule:
|
||||
if action == 'create':
|
||||
self._process_metering_label_rule_add(rm, rule,
|
||||
ext_dev,
|
||||
label_chain,
|
||||
rules_chain)
|
||||
elif action == 'delete':
|
||||
self._process_metering_label_rule_delete(rm, rule,
|
||||
ext_dev,
|
||||
label_chain,
|
||||
rules_chain)
|
||||
label_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + LABEL + label_id, wrap=False)
|
||||
rules_chain = iptables_manager.get_chain_name(
|
||||
WRAP_NAME + RULE + label_id, wrap=False)
|
||||
im.ipv4['filter'].empty_chain(rules_chain, wrap=False)
|
||||
|
||||
rules = label.get('rules')
|
||||
if rules:
|
||||
self._process_metering_label_rules(
|
||||
rules, label_chain, rules_chain, ext_dev, im)
|
||||
|
||||
def _update_metering_label_rules(self, router):
|
||||
rm = self.routers.get(router['id'])
|
||||
if not rm:
|
||||
return
|
||||
|
||||
with IptablesManagerTransaction(rm.iptables_manager):
|
||||
labels = router.get(constants.METERING_LABEL_KEY, [])
|
||||
for label in labels:
|
||||
label_id = label['id']
|
||||
|
||||
label_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
LABEL + label_id,
|
||||
wrap=False)
|
||||
rules_chain = iptables_manager.get_chain_name(WRAP_NAME +
|
||||
RULE + label_id,
|
||||
wrap=False)
|
||||
rm.iptables_manager.ipv4['filter'].empty_chain(rules_chain,
|
||||
wrap=False)
|
||||
|
||||
rules = label.get('rules')
|
||||
if rules:
|
||||
self._process_metering_label_rules(rm, rules,
|
||||
label_chain,
|
||||
rules_chain)
|
||||
ext_dev, ext_snat_dev = self.get_external_device_names(rm)
|
||||
for (im, dev) in [(rm.iptables_manager, ext_dev),
|
||||
(rm.snat_iptables_manager, ext_snat_dev)]:
|
||||
if im and dev:
|
||||
self._update_metering_label_rules_based_on_ns(router, dev, im)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def remove_metering_label(self, context, routers):
|
||||
|
@ -34,6 +34,7 @@ TEST_ROUTERS = [
|
||||
'gw_port_id': '6d411f48-ecc7-45e0-9ece-3b5bdb54fcee',
|
||||
'id': '473ec392-1711-44e3-b008-3251ccfc5099',
|
||||
'name': 'router1',
|
||||
'distributed': False,
|
||||
'status': 'ACTIVE',
|
||||
'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'},
|
||||
{'_metering_labels': [
|
||||
@ -49,9 +50,27 @@ TEST_ROUTERS = [
|
||||
'id': '373ec392-1711-44e3-b008-3251ccfc5099',
|
||||
'name': 'router2',
|
||||
'status': 'ACTIVE',
|
||||
'distributed': False,
|
||||
'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'},
|
||||
]
|
||||
|
||||
TEST_DVR_ROUTER = [
|
||||
{'_metering_labels': [
|
||||
{'id': 'c5df2fe5-c610-4a2a-b2f4-c0fb6df73c83',
|
||||
'rules': [{
|
||||
'direction': 'ingress',
|
||||
'excluded': False,
|
||||
'id': '7f1a261f-2600-4ed1-870c-a62754501379',
|
||||
'metering_label_id': 'c5df2fe5-c700-4a2a-b2f4-c0fb6df73c83',
|
||||
'remote_ip_prefix': '10.0.0.0/24'}]}],
|
||||
'admin_state_up': True,
|
||||
'gw_port_id': '6d411f48-ecc7-45e0-9ece-3b5bdb54fcee',
|
||||
'id': '473ec392-2711-44e3-b008-3251ccfc5099',
|
||||
'name': 'router-test',
|
||||
'distributed': True,
|
||||
'status': 'ACTIVE',
|
||||
'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'}]
|
||||
|
||||
TEST_ROUTERS_WITH_ONE_RULE = [
|
||||
{'_metering_labels': [
|
||||
{'id': 'c5df2fe5-c600-4a2a-b2f4-c0fb6df73c83',
|
||||
@ -66,6 +85,7 @@ TEST_ROUTERS_WITH_ONE_RULE = [
|
||||
'id': '473ec392-1711-44e3-b008-3251ccfc5099',
|
||||
'name': 'router1',
|
||||
'status': 'ACTIVE',
|
||||
'distributed': False,
|
||||
'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'},
|
||||
{'_metering_labels': [
|
||||
{'id': 'eeef45da-c600-4a2a-b2f4-c0fb6df73c83',
|
||||
@ -79,6 +99,7 @@ TEST_ROUTERS_WITH_ONE_RULE = [
|
||||
'gw_port_id': '7d411f48-ecc7-45e0-9ece-3b5bdb54fcee',
|
||||
'id': '373ec392-1711-44e3-b008-3251ccfc5099',
|
||||
'name': 'router2',
|
||||
'distributed': False,
|
||||
'status': 'ACTIVE',
|
||||
'tenant_id': '6c5f5d2a1fa2441e88e35422926f48e8'},
|
||||
]
|
||||
@ -96,6 +117,12 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
self.iptables_inst = mock.Mock()
|
||||
self.v4filter_inst = mock.Mock()
|
||||
self.v6filter_inst = mock.Mock()
|
||||
self.namespace_exists_p = mock.patch(
|
||||
'neutron.agent.linux.ip_lib.IpNetnsCommand.exists')
|
||||
self.namespace_exists = self.namespace_exists_p.start()
|
||||
self.snat_ns_name_p = mock.patch(
|
||||
'neutron.agent.l3.dvr_snat_ns.SnatNamespace.get_snat_ns_name')
|
||||
self.snat_ns_name = self.snat_ns_name_p.start()
|
||||
self.v4filter_inst.chains = []
|
||||
self.v6filter_inst.chains = []
|
||||
self.iptables_inst.ipv4 = {'filter': self.v4filter_inst}
|
||||
@ -108,16 +135,42 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
|
||||
def test_create_stateless_iptables_manager(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
self.assertEqual(1, self.iptables_cls.call_count)
|
||||
self.iptables_cls.assert_called_with(
|
||||
binary_name=mock.ANY,
|
||||
namespace=mock.ANY,
|
||||
state_less=True,
|
||||
use_ipv6=mock.ANY)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
self.assertTrue(rm.iptables_manager)
|
||||
self.assertIsNone(rm.snat_iptables_manager)
|
||||
|
||||
def test_iptables_manager_never_create_with_no_valid_namespace(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
self.namespace_exists.return_value = False
|
||||
self.metering.add_metering_label(None, routers)
|
||||
self.assertFalse(self.iptables_cls.called)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
self.assertIsNone(rm.iptables_manager)
|
||||
self.assertIsNone(rm.snat_iptables_manager)
|
||||
|
||||
def test_create_iptables_manager_for_distributed_routers(self):
|
||||
routers = TEST_DVR_ROUTER[:1]
|
||||
self.namespace_exists.return_value = True
|
||||
snat_ns_name = 'snat-' + routers[0]['id']
|
||||
self.snat_ns_name.return_value = snat_ns_name
|
||||
self.metering.add_metering_label(None, routers)
|
||||
self.assertEqual(2, self.iptables_cls.call_count)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
self.assertTrue(rm.iptables_manager)
|
||||
self.assertTrue(rm.snat_iptables_manager)
|
||||
|
||||
def test_add_metering_label(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
calls = [mock.call.add_chain('neutron-meter-l-c5df2fe5-c60',
|
||||
wrap=False),
|
||||
@ -132,7 +185,52 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
|
||||
self.v4filter_inst.assert_has_calls(calls)
|
||||
|
||||
def test_add_metering_label_dvr_routers(self):
|
||||
routers = TEST_DVR_ROUTER[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
snat_ns_name = 'snat-' + routers[0]['id']
|
||||
self.snat_ns_name.return_value = snat_ns_name
|
||||
self.metering._process_ns_specific_metering_label = mock.Mock()
|
||||
self.metering.add_metering_label(None, routers)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
ext_dev, ext_snat_dev = self.metering.get_external_device_names(rm)
|
||||
self.assertEqual(
|
||||
2, self.metering._process_ns_specific_metering_label.call_count)
|
||||
# check and validate the right device being passed based on the
|
||||
# namespace.
|
||||
self.assertEqual(
|
||||
self.metering._process_ns_specific_metering_label.mock_calls,
|
||||
[mock.call(
|
||||
routers[0], ext_dev, rm.iptables_manager),
|
||||
mock.call(
|
||||
routers[0], ext_snat_dev, rm.snat_iptables_manager)])
|
||||
|
||||
def test_add_metering_label_legacy_routers(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering._process_ns_specific_metering_label = mock.Mock()
|
||||
self.metering.add_metering_label(None, routers)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
ext_dev, _ = self.metering.get_external_device_names(rm)
|
||||
self.assertEqual(
|
||||
self.metering._process_ns_specific_metering_label.mock_calls,
|
||||
[mock.call(routers[0], ext_dev, rm.iptables_manager)])
|
||||
|
||||
def test_add_metering_label_when_no_namespace(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
|
||||
self.namespace_exists.return_value = False
|
||||
self.metering._process_metering_label = mock.Mock()
|
||||
self.metering.add_metering_label(None, routers)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
self.assertIsNone(rm.iptables_manager)
|
||||
self.assertIsNone(rm.snat_iptables_manager)
|
||||
self.assertFalse(self.metering._process_metering_label.called)
|
||||
|
||||
def test_process_metering_label_rules(self):
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, TEST_ROUTERS)
|
||||
|
||||
calls = [mock.call.add_chain('neutron-meter-l-c5df2fe5-c60',
|
||||
@ -171,6 +269,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
for router in routers:
|
||||
router['gw_port_id'] = None
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
|
||||
calls = [mock.call.add_chain('neutron-meter-l-c5df2fe5-c60',
|
||||
@ -203,6 +302,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
'excluded': True,
|
||||
})
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
calls = [mock.call.add_chain('neutron-meter-l-c5df2fe5-c60',
|
||||
wrap=False),
|
||||
@ -238,6 +338,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
def test_update_metering_label_rules(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
|
||||
updates = copy.deepcopy(routers)
|
||||
@ -292,6 +393,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
'remote_ip_prefix': '20.0.0.0/24',
|
||||
})
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
|
||||
del routers[0]['_metering_labels'][0]['rules'][1]
|
||||
@ -327,6 +429,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
def test_add_metering_label_rule(self):
|
||||
new_routers_rules = TEST_ROUTERS_WITH_ONE_RULE
|
||||
self.metering.update_routers(None, TEST_ROUTERS)
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label_rule(None, new_routers_rules)
|
||||
calls = [
|
||||
mock.call.add_rule('neutron-meter-r-c5df2fe5-c60',
|
||||
@ -341,9 +444,53 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
]
|
||||
self.v4filter_inst.assert_has_calls(calls)
|
||||
|
||||
def test_add_metering_label_rule_dvr_router(self):
|
||||
routers = TEST_DVR_ROUTER
|
||||
self.metering.update_routers(None, TEST_DVR_ROUTER)
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering._process_metering_rule_action_based_on_ns = mock.Mock()
|
||||
self.metering.add_metering_label_rule(None, routers)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
ext_dev, ext_snat_dev = self.metering.get_external_device_names(rm)
|
||||
self.assertEqual(
|
||||
2,
|
||||
self.metering._process_metering_rule_action_based_on_ns.call_count)
|
||||
# check and validate the right device being passed based on the
|
||||
# namespace.
|
||||
self.assertEqual(
|
||||
self.metering._process_metering_rule_action_based_on_ns.mock_calls,
|
||||
[mock.call(
|
||||
routers[0], 'create', ext_dev, rm.iptables_manager),
|
||||
mock.call(
|
||||
routers[0], 'create', ext_snat_dev,
|
||||
rm.snat_iptables_manager)])
|
||||
|
||||
def test_remove_metering_label_rule_dvr_router(self):
|
||||
routers = TEST_DVR_ROUTER
|
||||
self.metering.update_routers(None, TEST_DVR_ROUTER)
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label_rule(None, routers)
|
||||
self.metering._process_metering_rule_action_based_on_ns = mock.Mock()
|
||||
self.metering.remove_metering_label_rule(None, routers)
|
||||
rm = iptables_driver.RouterWithMetering(self.metering.conf, routers[0])
|
||||
ext_dev, ext_snat_dev = self.metering.get_external_device_names(rm)
|
||||
self.assertEqual(
|
||||
2,
|
||||
self.metering._process_metering_rule_action_based_on_ns.call_count)
|
||||
# check and validate the right device being passed based on the
|
||||
# namespace.
|
||||
self.assertEqual(
|
||||
self.metering._process_metering_rule_action_based_on_ns.mock_calls,
|
||||
[mock.call(
|
||||
routers[0], 'delete', ext_dev, rm.iptables_manager),
|
||||
mock.call(
|
||||
routers[0], 'delete', ext_snat_dev,
|
||||
rm.snat_iptables_manager)])
|
||||
|
||||
def test_remove_metering_label_rule(self):
|
||||
new_routers_rules = TEST_ROUTERS_WITH_ONE_RULE
|
||||
self.metering.update_routers(None, TEST_ROUTERS)
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label_rule(None, new_routers_rules)
|
||||
self.metering.remove_metering_label_rule(None, new_routers_rules)
|
||||
calls = [
|
||||
@ -361,6 +508,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
def test_remove_metering_label(self):
|
||||
routers = TEST_ROUTERS[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
self.metering.remove_metering_label(None, routers)
|
||||
calls = [mock.call.add_chain('neutron-meter-l-c5df2fe5-c60',
|
||||
@ -384,6 +532,18 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
|
||||
self.v4filter_inst.assert_has_calls(calls)
|
||||
|
||||
def test_remove_metering_label_with_dvr_routers(self):
|
||||
routers = TEST_DVR_ROUTER[:1]
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
self.metering._process_ns_specific_disassociate_metering_label = (
|
||||
mock.Mock())
|
||||
self.metering.remove_metering_label(None, routers)
|
||||
self.assertEqual(
|
||||
2, (self.metering.
|
||||
_process_ns_specific_disassociate_metering_label.call_count))
|
||||
|
||||
def test_update_routers(self):
|
||||
routers = copy.deepcopy(TEST_ROUTERS)
|
||||
routers[1]['_metering_labels'][0]['rules'][0].update({
|
||||
@ -391,6 +551,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
'excluded': True,
|
||||
})
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
|
||||
updates = copy.deepcopy(routers)
|
||||
@ -449,6 +610,7 @@ class IptablesDriverTestCase(base.BaseTestCase):
|
||||
def test_update_routers_removal(self):
|
||||
routers = TEST_ROUTERS
|
||||
|
||||
self.namespace_exists.return_value = True
|
||||
self.metering.add_metering_label(None, routers)
|
||||
|
||||
# Remove router id '373ec392-1711-44e3-b008-3251ccfc5099'
|
||||
|
@ -124,6 +124,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -147,6 +148,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -170,6 +172,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -190,6 +193,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -201,6 +205,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -224,6 +229,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rule': {
|
||||
@ -239,6 +245,7 @@ class TestMeteringPlugin(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rule': {
|
||||
@ -338,6 +345,7 @@ class TestMeteringPluginL3AgentScheduler(
|
||||
'name': 'router1',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
@ -347,6 +355,7 @@ class TestMeteringPluginL3AgentScheduler(
|
||||
'name': 'router2',
|
||||
'gw_port_id': None,
|
||||
'admin_state_up': True,
|
||||
'distributed': False,
|
||||
'tenant_id': self.tenant_id,
|
||||
'_metering_labels': [
|
||||
{'rules': [],
|
||||
|
Loading…
Reference in New Issue
Block a user