9d9fc01dd3
This change adds the ability to monitor the local ovsdb for interface changes so that the l2 agent can avoid unnecessary polling. Minimal changes are made to the agent so the risk of breakage should be low. Future efforts to make the agent entirely event-based may be able to use OvsdbMonitor as a starting point. By default polling minimization is not done, and can only be enabled by setting 'minimize_polling = True' in the ovs section of the l2 agent's config file. Closes-Bug: #1177973 Change-Id: I26c035b48a74df2148696869c5a9affae5ab3d27
117 lines
4.4 KiB
Python
117 lines
4.4 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# 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.linux import polling
|
|
from neutron.tests import base
|
|
|
|
|
|
class TestGetPollingManager(base.BaseTestCase):
|
|
|
|
def test_return_always_poll_by_default(self):
|
|
with polling.get_polling_manager() as pm:
|
|
self.assertEqual(pm.__class__, 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,
|
|
root_helper='test') as pm:
|
|
self.assertEqual(pm._monitor.root_helper, 'test')
|
|
self.assertEqual(pm.__class__,
|
|
polling.InterfacePollingMinimizer)
|
|
mock_stop.assert_has_calls(mock.call())
|
|
mock_start.assert_has_calls(mock.call())
|
|
|
|
|
|
class TestBasePollingManager(base.BaseTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestBasePollingManager, self).setUp()
|
|
self.pm = polling.BasePollingManager()
|
|
|
|
def test_force_polling_sets_interval_attribute(self):
|
|
self.assertFalse(self.pm._force_polling)
|
|
self.pm.force_polling()
|
|
self.assertTrue(self.pm._force_polling)
|
|
|
|
def test_polling_completed_sets_interval_attribute(self):
|
|
self.pm._polling_completed = False
|
|
self.pm.polling_completed()
|
|
self.assertTrue(self.pm._polling_completed)
|
|
|
|
def mock_is_polling_required(self, return_value):
|
|
return mock.patch.object(self.pm, '_is_polling_required',
|
|
return_value=return_value)
|
|
|
|
def test_is_polling_required_returns_true_when_forced(self):
|
|
with self.mock_is_polling_required(False):
|
|
self.pm.force_polling()
|
|
self.assertTrue(self.pm.is_polling_required)
|
|
self.assertFalse(self.pm._force_polling)
|
|
|
|
def test_is_polling_required_returns_true_when_polling_not_completed(self):
|
|
with self.mock_is_polling_required(False):
|
|
self.pm._polling_completed = False
|
|
self.assertTrue(self.pm.is_polling_required)
|
|
|
|
def test_is_polling_required_returns_true_when_updates_are_present(self):
|
|
with self.mock_is_polling_required(True):
|
|
self.assertTrue(self.pm.is_polling_required)
|
|
self.assertFalse(self.pm._polling_completed)
|
|
|
|
def test_is_polling_required_returns_false_for_no_updates(self):
|
|
with self.mock_is_polling_required(False):
|
|
self.assertFalse(self.pm.is_polling_required)
|
|
|
|
|
|
class TestAlwaysPoll(base.BaseTestCase):
|
|
|
|
def test_is_polling_required_always_returns_true(self):
|
|
pm = polling.AlwaysPoll()
|
|
self.assertTrue(pm.is_polling_required)
|
|
|
|
|
|
class TestInterfacePollingMinimizer(base.BaseTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestInterfacePollingMinimizer, self).setUp()
|
|
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()
|
|
|
|
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.linux.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())
|