diff --git a/neutron/agent/common/polling.py b/neutron/agent/common/polling.py index 037b962b91e..2eef660568a 100644 --- a/neutron/agent/common/polling.py +++ b/neutron/agent/common/polling.py @@ -13,13 +13,63 @@ # License for the specific language governing permissions and limitations # under the License. -import os +import contextlib + +import eventlet +from oslo_config import cfg +from oslo_log import log as logging + +from neutron.agent.common import async_process +from neutron.agent.common import base_polling +from neutron.agent.common import ovsdb_monitor +from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants + +LOG = logging.getLogger(__name__) -if os.name == 'nt': - from neutron.agent.windows import polling -else: - from neutron.agent.linux import polling +@contextlib.contextmanager +def get_polling_manager(minimize_polling=False, + ovsdb_monitor_respawn_interval=( + constants.DEFAULT_OVSDBMON_RESPAWN)): + if minimize_polling: + pm = InterfacePollingMinimizer( + ovsdb_monitor_respawn_interval=ovsdb_monitor_respawn_interval) + pm.start() + else: + pm = base_polling.AlwaysPoll() + try: + yield pm + finally: + if minimize_polling: + pm.stop() -get_polling_manager = polling.get_polling_manager -InterfacePollingMinimizer = polling.InterfacePollingMinimizer + +class InterfacePollingMinimizer(base_polling.BasePollingManager): + """Monitors ovsdb to determine when polling is required.""" + + def __init__( + self, + ovsdb_monitor_respawn_interval=constants.DEFAULT_OVSDBMON_RESPAWN): + + super(InterfacePollingMinimizer, self).__init__() + self._monitor = ovsdb_monitor.SimpleInterfaceMonitor( + respawn_interval=ovsdb_monitor_respawn_interval, + ovsdb_connection=cfg.CONF.OVS.ovsdb_connection) + + def start(self): + self._monitor.start(block=True) + + def stop(self): + try: + self._monitor.stop() + except async_process.AsyncProcessException: + LOG.debug("InterfacePollingMinimizer was not running when stopped") + + def _is_polling_required(self): + # Maximize the chances of update detection having a chance to + # collect output. + eventlet.sleep() + return self._monitor.has_updates + + def get_events(self): + return self._monitor.get_events() diff --git a/neutron/agent/linux/polling.py b/neutron/agent/linux/polling.py deleted file mode 100644 index 91475f899ca..00000000000 --- a/neutron/agent/linux/polling.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2013 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. - -import contextlib - -import eventlet -from oslo_config import cfg -from oslo_log import log as logging - -from neutron.agent.common import async_process -from neutron.agent.common import base_polling -from neutron.agent.common import ovsdb_monitor -from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants - -LOG = logging.getLogger(__name__) - - -@contextlib.contextmanager -def get_polling_manager(minimize_polling=False, - ovsdb_monitor_respawn_interval=( - constants.DEFAULT_OVSDBMON_RESPAWN)): - if minimize_polling: - pm = InterfacePollingMinimizer( - ovsdb_monitor_respawn_interval=ovsdb_monitor_respawn_interval) - pm.start() - else: - pm = base_polling.AlwaysPoll() - try: - yield pm - finally: - if minimize_polling: - pm.stop() - - -class InterfacePollingMinimizer(base_polling.BasePollingManager): - """Monitors ovsdb to determine when polling is required.""" - - def __init__( - self, - ovsdb_monitor_respawn_interval=constants.DEFAULT_OVSDBMON_RESPAWN): - - super(InterfacePollingMinimizer, self).__init__() - self._monitor = ovsdb_monitor.SimpleInterfaceMonitor( - respawn_interval=ovsdb_monitor_respawn_interval, - ovsdb_connection=cfg.CONF.OVS.ovsdb_connection) - - def start(self): - self._monitor.start(block=True) - - def stop(self): - try: - self._monitor.stop() - except async_process.AsyncProcessException: - LOG.debug("InterfacePollingMinimizer was not running when stopped") - - def _is_polling_required(self): - # Maximize the chances of update detection having a chance to - # collect output. - eventlet.sleep() - return self._monitor.has_updates - - def get_events(self): - return self._monitor.get_events() diff --git a/neutron/agent/windows/polling.py b/neutron/agent/windows/polling.py deleted file mode 100644 index 719870de8ff..00000000000 --- a/neutron/agent/windows/polling.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2015 Cloudbase Solutions. -# All Rights Reserved. -# -# 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. - -import contextlib - -from neutron.agent.common import base_polling - - -@contextlib.contextmanager -def get_polling_manager(minimize_polling, ovsdb_monitor_respawn_interval): - pm = base_polling.AlwaysPoll() - yield pm - - -# TODO(atuvenie): make this manager inherit from -# that fully fledged polling manager interface -class InterfacePollingMinimizer(object): - pass diff --git a/neutron/tests/functional/agent/l2/base.py b/neutron/tests/functional/agent/l2/base.py index 5686a5c5a3d..827a516a816 100644 --- a/neutron/tests/functional/agent/l2/base.py +++ b/neutron/tests/functional/agent/l2/base.py @@ -24,9 +24,9 @@ from oslo_config import cfg from oslo_utils import uuidutils from neutron.agent.common import ovs_lib +from neutron.agent.common import polling from neutron.agent.l2 import l2_agent_extensions_manager as ext_manager from neutron.agent.linux import interface -from neutron.agent.linux import polling from neutron.common import utils from neutron.conf.agent import common as agent_config from neutron.conf import common as common_config diff --git a/neutron/tests/unit/agent/common/test_polling.py b/neutron/tests/unit/agent/common/test_polling.py index 738dc877b7a..e34b1569005 100644 --- a/neutron/tests/unit/agent/common/test_polling.py +++ b/neutron/tests/unit/agent/common/test_polling.py @@ -14,7 +14,9 @@ import mock -from neutron.agent.common import base_polling as polling +from neutron.agent.common import base_polling +from neutron.agent.common import polling +from neutron.agent.ovsdb.native import helpers from neutron.tests import base @@ -22,7 +24,7 @@ class TestBasePollingManager(base.BaseTestCase): def setUp(self): super(TestBasePollingManager, self).setUp() - self.pm = polling.BasePollingManager() + self.pm = base_polling.BasePollingManager() def test__is_polling_required_should_not_be_implemented(self): self.assertRaises(NotImplementedError, self.pm._is_polling_required) @@ -65,5 +67,56 @@ class TestBasePollingManager(base.BaseTestCase): class TestAlwaysPoll(base.BaseTestCase): def test_is_polling_required_always_returns_true(self): - pm = polling.AlwaysPoll() + pm = base_polling.AlwaysPoll() self.assertTrue(pm.is_polling_required) + + +class TestGetPollingManager(base.BaseTestCase): + + def setUp(self): + super(TestGetPollingManager, self).setUp() + mock.patch.object(helpers, 'enable_connection_uri').start() + + def test_return_always_poll_by_default(self): + with polling.get_polling_manager() as pm: + self.assertEqual(pm.__class__, base_polling.AlwaysPoll) + + def test_manage_polling_minimizer(self): + mock_target = 'neutron.agent.common.polling.InterfacePollingMinimizer' + with mock.patch('%s.start' % mock_target) as mock_start: + with mock.patch('%s.stop' % mock_target) as mock_stop: + with polling.get_polling_manager(minimize_polling=True) as pm: + self.assertEqual(pm.__class__, + polling.InterfacePollingMinimizer) + mock_stop.assert_has_calls([mock.call()]) + mock_start.assert_has_calls([mock.call()]) + + +class TestInterfacePollingMinimizer(base.BaseTestCase): + + def setUp(self): + super(TestInterfacePollingMinimizer, self).setUp() + mock.patch.object(helpers, 'enable_connection_uri').start() + self.pm = polling.InterfacePollingMinimizer() + + def test_start_calls_monitor_start(self): + with mock.patch.object(self.pm._monitor, 'start') as mock_start: + self.pm.start() + mock_start.assert_called_with(block=True) + + def test_stop_calls_monitor_stop(self): + with mock.patch.object(self.pm._monitor, 'stop') as mock_stop: + self.pm.stop() + mock_stop.assert_called_with() + + def mock_has_updates(self, return_value): + target = ('neutron.agent.common.ovsdb_monitor.SimpleInterfaceMonitor' + '.has_updates') + return mock.patch( + target, + new_callable=mock.PropertyMock(return_value=return_value), + ) + + def test__is_polling_required_returns_when_updates_are_present(self): + with self.mock_has_updates(True): + self.assertTrue(self.pm._is_polling_required()) diff --git a/neutron/tests/unit/agent/linux/test_polling.py b/neutron/tests/unit/agent/linux/test_polling.py deleted file mode 100644 index ef9f44f12ae..00000000000 --- a/neutron/tests/unit/agent/linux/test_polling.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2013 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. - -import mock - -from neutron.agent.common import base_polling -from neutron.agent.linux import polling -from neutron.agent.ovsdb.native import helpers -from neutron.tests import base - - -class TestGetPollingManager(base.BaseTestCase): - - def setUp(self): - super(TestGetPollingManager, self).setUp() - mock.patch.object(helpers, 'enable_connection_uri').start() - - def test_return_always_poll_by_default(self): - with polling.get_polling_manager() as pm: - self.assertEqual(pm.__class__, base_polling.AlwaysPoll) - - def test_manage_polling_minimizer(self): - mock_target = 'neutron.agent.linux.polling.InterfacePollingMinimizer' - with mock.patch('%s.start' % mock_target) as mock_start: - with mock.patch('%s.stop' % mock_target) as mock_stop: - with polling.get_polling_manager(minimize_polling=True) as pm: - self.assertEqual(pm.__class__, - polling.InterfacePollingMinimizer) - mock_stop.assert_has_calls([mock.call()]) - mock_start.assert_has_calls([mock.call()]) - - -class TestInterfacePollingMinimizer(base.BaseTestCase): - - def setUp(self): - super(TestInterfacePollingMinimizer, self).setUp() - mock.patch.object(helpers, 'enable_connection_uri').start() - self.pm = polling.InterfacePollingMinimizer() - - def test_start_calls_monitor_start(self): - with mock.patch.object(self.pm._monitor, 'start') as mock_start: - self.pm.start() - mock_start.assert_called_with(block=True) - - def test_stop_calls_monitor_stop(self): - with mock.patch.object(self.pm._monitor, 'stop') as mock_stop: - self.pm.stop() - mock_stop.assert_called_with() - - def mock_has_updates(self, return_value): - target = ('neutron.agent.common.ovsdb_monitor.SimpleInterfaceMonitor' - '.has_updates') - return mock.patch( - target, - new_callable=mock.PropertyMock(return_value=return_value), - ) - - def test__is_polling_required_returns_when_updates_are_present(self): - with self.mock_has_updates(True): - self.assertTrue(self.pm._is_polling_required())