diff --git a/neutron/db/metering/metering_db.py b/neutron/db/metering/metering_db.py index 5e1c82e2c18..0277d5735b9 100644 --- a/neutron/db/metering/metering_db.py +++ b/neutron/db/metering/metering_db.py @@ -211,6 +211,8 @@ class MeteringDbMixin(metering.MeteringPluginBase, routers = label.routers for router in routers: + if not router['admin_state_up']: + continue router_dict = routers_dict.get( router['id'], self._make_router_dict(router)) @@ -244,15 +246,12 @@ class MeteringDbMixin(metering.MeteringPluginBase, return list(routers_dict.values()) - def get_sync_data_metering(self, context, label_id=None, router_ids=None): + def get_sync_data_metering(self, context, label_id=None): labels = context.session.query(metering_models.MeteringLabel) if label_id: labels = labels.filter( metering_models.MeteringLabel.id == label_id) - elif router_ids: - labels = (labels.join(metering_models.MeteringLabel.routers). - filter(l3_models.Router.id.in_(router_ids))) return self._process_sync_metering_data(context, labels) diff --git a/neutron/db/metering/metering_rpc.py b/neutron/db/metering/metering_rpc.py index 21f915630b0..7b34fd5cb45 100644 --- a/neutron/db/metering/metering_rpc.py +++ b/neutron/db/metering/metering_rpc.py @@ -37,10 +37,11 @@ class MeteringRpcCallbacks(object): if not l3_plugin: return + metering_data = self.meter_plugin.get_sync_data_metering(context) host = kwargs.get('host') if not utils.is_extension_supported( l3_plugin, consts.L3_AGENT_SCHEDULER_EXT_ALIAS) or not host: - return self.meter_plugin.get_sync_data_metering(context) + return metering_data else: agents = l3_plugin.get_l3_agents(context, filters={'host': [host]}) if not agents: @@ -51,6 +52,8 @@ class MeteringRpcCallbacks(object): router_ids = [router['id'] for router in routers['routers']] if not router_ids: return - - return self.meter_plugin.get_sync_data_metering(context, - router_ids=router_ids) + else: + return [ + router for router in metering_data + if router['id'] in router_ids + ] diff --git a/neutron/services/metering/agents/metering_agent.py b/neutron/services/metering/agents/metering_agent.py index f68f5211a9a..f8c5bd377db 100644 --- a/neutron/services/metering/agents/metering_agent.py +++ b/neutron/services/metering/agents/metering_agent.py @@ -176,6 +176,14 @@ class MeteringAgent(MeteringPluginRpc, manager.Manager): @periodic_task.periodic_task(run_immediately=True) def _sync_routers_task(self, context): routers = self._get_sync_data_metering(self.context) + + routers_on_agent = set(self.routers.keys()) + routers_on_server = set( + [router['id'] for router in routers] if routers else []) + for router_id in routers_on_agent - routers_on_server: + del self.routers[router_id] + self._invoke_driver(context, router_id, 'remove_router') + if not routers: return self._update_routers(context, routers) diff --git a/neutron/services/metering/drivers/iptables/iptables_driver.py b/neutron/services/metering/drivers/iptables/iptables_driver.py index 8a3df4c5246..aa9d39d8402 100644 --- a/neutron/services/metering/drivers/iptables/iptables_driver.py +++ b/neutron/services/metering/drivers/iptables/iptables_driver.py @@ -343,6 +343,7 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver): @log_helpers.log_method_call def get_traffic_counters(self, context, routers): accs = {} + routers_to_reconfigure = set() for router in routers: rm = self.routers.get(router['id']) if not rm: @@ -360,6 +361,7 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver): except RuntimeError: LOG.exception(_LE('Failed to get traffic counters, ' 'router: %s'), router) + routers_to_reconfigure.add(router['id']) continue if not chain_acc: @@ -372,4 +374,7 @@ class IptablesMeteringDriver(abstract_driver.MeteringAbstractDriver): accs[label_id] = acc + for router_id in routers_to_reconfigure: + del self.routers[router_id] + return accs diff --git a/neutron/tests/unit/extensions/test_l3.py b/neutron/tests/unit/extensions/test_l3.py index aeb9735ba82..7b8694c0d28 100644 --- a/neutron/tests/unit/extensions/test_l3.py +++ b/neutron/tests/unit/extensions/test_l3.py @@ -335,7 +335,7 @@ class L3NatTestCaseMixin(object): data = {'router': {'tenant_id': tenant_id}} if name: data['router']['name'] = name - if admin_state_up: + if admin_state_up is not None: data['router']['admin_state_up'] = admin_state_up for arg in (('admin_state_up', 'tenant_id', 'availability_zone_hints') + (arg_list or ())): diff --git a/neutron/tests/unit/services/metering/test_metering_plugin.py b/neutron/tests/unit/services/metering/test_metering_plugin.py index 7411a25212a..96ac309d95f 100644 --- a/neutron/tests/unit/services/metering/test_metering_plugin.py +++ b/neutron/tests/unit/services/metering/test_metering_plugin.py @@ -490,3 +490,53 @@ class TestMeteringPluginRpcFromL3Agent( routers = [router['name'] for router in data] self.assertEqual([], routers) + + def test_get_sync_data_metering_with_unscheduled_router(self): + with self.subnet() as subnet: + s = subnet['subnet'] + self._set_net_external(s['network_id']) + with self.router( + name='router1', tenant_id=self.tenant_id + ) as router1: + self._add_external_gateway_to_router( + router1['router']['id'], s['network_id']) + with self.router(name='router2', tenant_id=self.tenant_id): + with self.metering_label(tenant_id=self.tenant_id): + callbacks = metering_rpc.MeteringRpcCallbacks( + self.meter_plugin) + data = callbacks.get_sync_data_metering( + self.adminContext, host='agent1') + self.assertEqual( + set(['router1']), set([r['name'] for r in data])) + + self._remove_external_gateway_from_router( + router1['router']['id'], s['network_id']) + + def test_get_sync_data_metering_with_inactive_router(self): + with self.subnet() as subnet: + s = subnet['subnet'] + self._set_net_external(s['network_id']) + with self.router( + name='router1', tenant_id=self.tenant_id + ) as router1: + self._add_external_gateway_to_router( + router1['router']['id'], s['network_id']) + with self.router( + name='router2', tenant_id=self.tenant_id, + admin_state_up=False + ) as router2: + self._add_external_gateway_to_router( + router2['router']['id'], s['network_id']) + with self.metering_label(tenant_id=self.tenant_id): + callbacks = metering_rpc.MeteringRpcCallbacks( + self.meter_plugin) + data = callbacks.get_sync_data_metering( + self.adminContext, host='agent1') + self.assertEqual( + set(['router1']), set([r['name'] for r in data])) + + self._remove_external_gateway_from_router( + router2['router']['id'], s['network_id']) + + self._remove_external_gateway_from_router( + router1['router']['id'], s['network_id'])