From 422d4bbee75c85a192f3e6edcf6bf4ae300430d9 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Thu, 23 May 2013 11:09:19 +0200 Subject: [PATCH] Nicira plugin: List ports on network gateways Bug 1183277 This patch adds a read-only attribute to the network gateway API extension. This attribute will return the list of ports connected to a gateway, including their segmentation types and ids. This patch now adds joined load for a gateway's connections, thus avoiding extra queries to the db. Change-Id: I2b22c94eed5bc02be16771660008d31c74a8628e --- .../nicira/extensions/nvp_networkgw.py | 3 ++ quantum/plugins/nicira/nicira_networkgw_db.py | 19 ++++++--- quantum/tests/unit/nicira/test_networkgw.py | 39 +++++++++++++++++++ .../tests/unit/nicira/test_nicira_plugin.py | 4 ++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/quantum/plugins/nicira/extensions/nvp_networkgw.py b/quantum/plugins/nicira/extensions/nvp_networkgw.py index 2887fda2968..0bc6cf2e98d 100644 --- a/quantum/plugins/nicira/extensions/nvp_networkgw.py +++ b/quantum/plugins/nicira/extensions/nvp_networkgw.py @@ -48,6 +48,9 @@ RESOURCE_ATTRIBUTE_MAP = { 'devices': {'allow_post': True, 'allow_put': False, 'validate': {'type:device_list': None}, 'is_visible': True}, + 'ports': {'allow_post': False, 'allow_put': False, + 'default': [], + 'is_visible': True}, 'tenant_id': {'allow_post': True, 'allow_put': False, 'validate': {'type:string': None}, 'required_by_policy': True, diff --git a/quantum/plugins/nicira/nicira_networkgw_db.py b/quantum/plugins/nicira/nicira_networkgw_db.py index f50a0759dc1..9a89e8b9349 100644 --- a/quantum/plugins/nicira/nicira_networkgw_db.py +++ b/quantum/plugins/nicira/nicira_networkgw_db.py @@ -122,7 +122,7 @@ class NetworkGateway(model_base.BASEV2, models_v2.HasId, devices = orm.relationship(NetworkGatewayDevice, backref='networkgateways', cascade='all,delete') - network_connections = orm.relationship(NetworkConnection) + network_connections = orm.relationship(NetworkConnection, lazy='joined') class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase): @@ -132,6 +132,11 @@ class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase): def _get_network_gateway(self, context, gw_id): return self._get_by_id(context, NetworkGateway, gw_id) + def _make_gw_connection_dict(self, gw_conn): + return {'port_id': gw_conn['port_id'], + 'segmentation_type': gw_conn['segmentation_type'], + 'segmentation_id': gw_conn['segmentation_id']} + def _make_network_gateway_dict(self, network_gateway, fields=None): device_list = [] for d in network_gateway['devices']: @@ -142,7 +147,10 @@ class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase): 'default': network_gateway['default'], 'devices': device_list, 'tenant_id': network_gateway['tenant_id']} - # NOTE(salvatore-orlando):perhaps return list of connected networks + # Query gateway connections only if needed + if (fields and 'ports' in fields) or not fields: + res['ports'] = [self._make_gw_connection_dict(conn) + for conn in network_gateway.network_connections] return self._fields(res, fields) def _validate_network_mapping_info(self, network_mapping_info): @@ -170,8 +178,8 @@ class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase): raise exceptions.InvalidInput(error_message=msg) return network_id - def _retrieve_gateway_connections(self, context, gateway_id, mapping_info, - only_one=False): + def _retrieve_gateway_connections(self, context, gateway_id, + mapping_info={}, only_one=False): filters = {'network_gateway_id': [gateway_id]} for k, v in mapping_info.iteritems(): if v and k != NETWORK_ID: @@ -224,8 +232,7 @@ class NetworkGatewayMixin(nvp_networkgw.NetworkGatewayPluginBase): if gw_db.default: raise NetworkGatewayUnchangeable(gateway_id=id) # Ensure there is something to update before doing it - db_values_set = set([v for (k, v) in gw_db.iteritems()]) - if not set(gw_data.values()).issubset(db_values_set): + if any([gw_db[k] != gw_data[k] for k in gw_data]): gw_db.update(gw_data) LOG.debug(_("Updated network gateway with id:%s"), id) return self._make_network_gateway_dict(gw_db) diff --git a/quantum/tests/unit/nicira/test_networkgw.py b/quantum/tests/unit/nicira/test_networkgw.py index c1fd33c9220..35a3a05dc2b 100644 --- a/quantum/tests/unit/nicira/test_networkgw.py +++ b/quantum/tests/unit/nicira/test_networkgw.py @@ -380,6 +380,45 @@ class NetworkGatewayDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase): self.assertEqual(res[key][1]['name'], gw2[self.resource]['name']) + def _test_list_network_gateway_with_multiple_connections( + self, expected_gateways=1): + with self._network_gateway() as gw: + with self.network() as net_1: + self._gateway_action('connect', + gw[self.resource]['id'], + net_1['network']['id'], + 'vlan', 555) + self._gateway_action('connect', + gw[self.resource]['id'], + net_1['network']['id'], + 'vlan', 777) + req = self.new_list_request(networkgw.COLLECTION_NAME) + res = self.deserialize('json', req.get_response(self.ext_api)) + key = self.resource + 's' + self.assertEqual(len(res[key]), expected_gateways) + for item in res[key]: + self.assertIn('ports', item) + if item['id'] == gw[self.resource]['id']: + gw_ports = item['ports'] + self.assertEqual(len(gw_ports), 2) + segmentation_ids = [555, 777] + for gw_port in gw_ports: + self.assertEqual('vlan', gw_port['segmentation_type']) + self.assertIn(gw_port['segmentation_id'], segmentation_ids) + segmentation_ids.remove(gw_port['segmentation_id']) + # Required cleanup + self._gateway_action('disconnect', + gw[self.resource]['id'], + net_1['network']['id'], + 'vlan', 555) + self._gateway_action('disconnect', + gw[self.resource]['id'], + net_1['network']['id'], + 'vlan', 777) + + def test_list_network_gateway_with_multiple_connections(self): + self._test_list_network_gateway_with_multiple_connections() + def test_connect_and_disconnect_network(self): self._test_connect_and_disconnect_network('flat') diff --git a/quantum/tests/unit/nicira/test_nicira_plugin.py b/quantum/tests/unit/nicira/test_nicira_plugin.py index e98ebbd4e95..f52978f376c 100644 --- a/quantum/tests/unit/nicira/test_nicira_plugin.py +++ b/quantum/tests/unit/nicira/test_nicira_plugin.py @@ -929,6 +929,10 @@ class TestNiciraNetworkGateway(test_l2_gw.NetworkGatewayDbTestCase, self.assertEqual(res[key][2]['name'], gw2[self.resource]['name']) + def test_list_network_gateway_with_multiple_connections(self): + self._test_list_network_gateway_with_multiple_connections( + expected_gateways=2) + def test_delete_network_gateway(self): # The default gateway must still be there self._test_delete_network_gateway(1)