From 17db307e274035fbe65e99a29eec6638e6ec1e2d Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Sun, 22 Apr 2018 02:00:27 +0000 Subject: [PATCH] Allow skip processing exposed ports The endpoints 'network_driver_program_external_connectivity' and 'network_driver_revoke_external_connectivity' will dynamically create security group and security group rules to open the ports exposed by the docker container. However, such processing invokes too much neutron API calls thus significantly slowing down the container start/stop. However, such processing is not mandatory because users can manually configure the SGs to achieve the equivalent. This patch make the processing of exposed ports configurable. As a result, it can be disabled if users want a better performance. Change-Id: I6d6d176512e6b30bb7372408aec1a7bac12335ab --- devstack/plugin.sh | 1 + devstack/settings | 1 + kuryr_libnetwork/config.py | 3 + kuryr_libnetwork/controllers.py | 6 ++ .../tests/unit/test_external_connectivity.py | 83 +++++++++++++++++++ 5 files changed, 94 insertions(+) diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 578edf6a..3e3fccc1 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -59,6 +59,7 @@ function configure_kuryr { configure_auth_token_middleware "$KURYR_CONFIG" kuryr \ "$KURYR_AUTH_CACHE_DIR" neutron iniset $KURYR_CONFIG DEFAULT capability_scope $KURYR_CAPABILITY_SCOPE + iniset $KURYR_CONFIG DEFAULT process_external_connectivity $KURYR_PROCESS_EXTERNAL_CONNECTIVITY fi if [[ "$ENABLE_PLUGINV2" == "True" ]]; then diff --git a/devstack/settings b/devstack/settings index 8004bc46..ce23e60a 100644 --- a/devstack/settings +++ b/devstack/settings @@ -20,6 +20,7 @@ KURYR_POOL_PREFIX=${KURYR_POOL_PREFIX:-10.10.0.0/16} KURYR_POOL_PREFIX_LEN=${KURYR_POOL_PREFIX_LEN:-24} KURYR_CAPABILITY_SCOPE=${KURYR_CAPABILITY_SCOPE:-local} +KURYR_PROCESS_EXTERNAL_CONNECTIVITY=${KURYR_PROCESS_EXTERNAL_CONNECTIVITY:-True} KURYR_DOCKER_ENGINE_PORT=${KURYR_DOCKER_ENGINE_PORT:-2375} DOCKER_CLUSTER_STORE=${DOCKER_CLUSTER_STORE:-etcd://$SERVICE_HOST:$ETCD_PORT} diff --git a/kuryr_libnetwork/config.py b/kuryr_libnetwork/config.py index bc6d37a2..641cd7ce 100644 --- a/kuryr_libnetwork/config.py +++ b/kuryr_libnetwork/config.py @@ -52,6 +52,9 @@ core_opts = [ cfg.ListOpt('enabled_port_drivers', default=['kuryr_libnetwork.port_driver.drivers.veth'], help=_('Available port drivers')), + cfg.BoolOpt('process_external_connectivity', + default=True, + help=_('Do processing external connectivity')), cfg.StrOpt('ssl_cert_file', default='/var/lib/kuryr/certs/cert.pem', help=_('This option allows setting absolute path' diff --git a/kuryr_libnetwork/controllers.py b/kuryr_libnetwork/controllers.py index 7bfd318d..6d23d657 100644 --- a/kuryr_libnetwork/controllers.py +++ b/kuryr_libnetwork/controllers.py @@ -1437,6 +1437,9 @@ def network_driver_program_external_connectivity(): json_data = flask.request.get_json(force=True) LOG.debug("Received JSON data %s for" " /NetworkDriver.ProgramExternalConnectivity", json_data) + if not cfg.CONF.process_external_connectivity: + return flask.jsonify(const.SCHEMA['SUCCESS']) + # TODO(banix): Add support for exposed ports port = _get_neutron_port_from_docker_endpoint(json_data['EndpointID']) if port: @@ -1459,6 +1462,9 @@ def network_driver_revoke_external_connectivity(): json_data = flask.request.get_json(force=True) LOG.debug("Received JSON data %s for" " /NetworkDriver.RevokeExternalConnectivity", json_data) + if not cfg.CONF.process_external_connectivity: + return flask.jsonify(const.SCHEMA['SUCCESS']) + # TODO(banix): Add support for removal of exposed ports port = _get_neutron_port_from_docker_endpoint(json_data['EndpointID']) if port: diff --git a/kuryr_libnetwork/tests/unit/test_external_connectivity.py b/kuryr_libnetwork/tests/unit/test_external_connectivity.py index aef3214b..f9059251 100644 --- a/kuryr_libnetwork/tests/unit/test_external_connectivity.py +++ b/kuryr_libnetwork/tests/unit/test_external_connectivity.py @@ -21,6 +21,7 @@ from oslo_utils import uuidutils from kuryr.lib import constants as lib_const from kuryr.lib import utils as lib_utils +from kuryr_libnetwork import config from kuryr_libnetwork import constants from kuryr_libnetwork.tests.unit import base from kuryr_libnetwork import utils @@ -55,6 +56,7 @@ class TestExternalConnectivityKuryr(base.TestKuryrBase): num_ports, mock_list_ports, mock_create_security_group, mock_create_security_group_rule, mock_show_port, mock_update_port): + config.CONF.set_override('process_external_connectivity', True) fake_docker_net_id = lib_utils.get_hash() fake_docker_endpoint_id = lib_utils.get_hash() @@ -142,6 +144,51 @@ class TestExternalConnectivityKuryr(base.TestKuryrBase): decoded_json = jsonutils.loads(response.data) self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) + @mock.patch('kuryr_libnetwork.controllers.app.neutron.update_port') + @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_port') + @mock.patch( + 'kuryr_libnetwork.controllers.app.neutron.create_security_group_rule') + @mock.patch( + 'kuryr_libnetwork.controllers.app.neutron.create_security_group') + @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports') + @ddt.data((False, 1), (True, 1), (False, 2), (True, 2)) + @ddt.unpack + def test_network_driver_program_external_connectivity_disabled( + self, existing_sg, + num_ports, mock_list_ports, mock_create_security_group, + mock_create_security_group_rule, mock_show_port, + mock_update_port): + config.CONF.set_override('process_external_connectivity', False) + fake_docker_net_id = lib_utils.get_hash() + fake_docker_endpoint_id = lib_utils.get_hash() + + port_opt = [] + for i in range(num_ports): + port_opt.append({u'Port': PORT + i, u'Proto': PROTOCOL_TCP}) + port_opt.append({u'Port': PORT + i, u'Proto': PROTOCOL_UDP}) + port_opt.append({u'Port': SINGLE_PORT, u'Proto': PROTOCOL_UDP}) + options = {'com.docker.network.endpoint.exposedports': + port_opt, + 'com.docker.network.portmap': + []} + data = { + 'NetworkID': fake_docker_net_id, + 'EndpointID': fake_docker_endpoint_id, + 'Options': options, + } + response = self.app.post('/NetworkDriver.ProgramExternalConnectivity', + content_type='application/json', + data=jsonutils.dumps(data)) + + self.assertEqual(200, response.status_code) + mock_update_port.assert_not_called() + mock_show_port.assert_not_called() + mock_create_security_group_rule.assert_not_called() + mock_create_security_group.assert_not_called() + mock_list_ports.assert_not_called() + decoded_json = jsonutils.loads(response.data) + self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) + @mock.patch('kuryr_libnetwork.controllers.app.neutron.update_port') @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_port') @mock.patch( @@ -155,6 +202,7 @@ class TestExternalConnectivityKuryr(base.TestKuryrBase): removing_sg, mock_list_ports, mock_list_security_groups, mock_delete_security_groups, mock_show_port, mock_update_port): + config.CONF.set_override('process_external_connectivity', True) fake_docker_net_id = lib_utils.get_hash() fake_docker_endpoint_id = lib_utils.get_hash() @@ -219,3 +267,38 @@ class TestExternalConnectivityKuryr(base.TestKuryrBase): mock_update_port.assert_not_called() decoded_json = jsonutils.loads(response.data) self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json) + + @mock.patch('kuryr_libnetwork.controllers.app.neutron.update_port') + @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_port') + @mock.patch( + 'kuryr_libnetwork.controllers.app.neutron.delete_security_group') + @mock.patch( + 'kuryr_libnetwork.controllers.app.neutron.list_security_groups') + @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports') + @ddt.data((False, False), (False, True), (True, False), (True, True)) + @ddt.unpack + def test_network_driver_revoke_external_connectivity_disabled( + self, existing_sg, + removing_sg, mock_list_ports, mock_list_security_groups, + mock_delete_security_groups, mock_show_port, + mock_update_port): + config.CONF.set_override('process_external_connectivity', False) + fake_docker_net_id = lib_utils.get_hash() + fake_docker_endpoint_id = lib_utils.get_hash() + + data = { + 'NetworkID': fake_docker_net_id, + 'EndpointID': fake_docker_endpoint_id, + } + response = self.app.post('/NetworkDriver.RevokeExternalConnectivity', + content_type='application/json', + data=jsonutils.dumps(data)) + + self.assertEqual(200, response.status_code) + mock_list_ports.assert_not_called() + mock_list_security_groups.assert_not_called() + mock_delete_security_groups.assert_not_called() + mock_show_port.assert_not_called() + mock_update_port.assert_not_called() + decoded_json = jsonutils.loads(response.data) + self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)