Merge "Add neutron-linuxbridge-cleanup util"

This commit is contained in:
Jenkins 2015-10-06 11:27:27 +00:00 committed by Gerrit Code Review
commit 2842ee8474
6 changed files with 192 additions and 1 deletions

View File

@ -0,0 +1,76 @@
# 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 sys
from oslo_config import cfg
from oslo_log import log as logging
from neutron.common import config
from neutron.common import utils as n_utils
from neutron.i18n import _LE, _LI
from neutron.plugins.ml2.drivers.linuxbridge.agent \
import linuxbridge_neutron_agent
LOG = logging.getLogger(__name__)
def remove_empty_bridges():
try:
interface_mappings = n_utils.parse_mappings(
cfg.CONF.LINUX_BRIDGE.physical_interface_mappings)
except ValueError as e:
LOG.error(_LE("Parsing physical_interface_mappings failed: %s."), e)
sys.exit(1)
LOG.info(_LI("Interface mappings: %s."), interface_mappings)
try:
bridge_mappings = n_utils.parse_mappings(
cfg.CONF.LINUX_BRIDGE.bridge_mappings)
except ValueError as e:
LOG.error(_LE("Parsing bridge_mappings failed: %s."), e)
sys.exit(1)
LOG.info(_LI("Bridge mappings: %s."), bridge_mappings)
lb_manager = linuxbridge_neutron_agent.LinuxBridgeManager(
bridge_mappings, interface_mappings)
# NOTE(mgagne) Don't remove pre-existing user-defined bridges
bridge_names = set(lb_manager.get_all_neutron_bridges())
bridge_names -= set(bridge_mappings.values())
for bridge_name in bridge_names:
if lb_manager.get_tap_devices_count(bridge_name):
continue
try:
lb_manager.delete_bridge(bridge_name)
LOG.info(_LI("Linux bridge %s deleted"), bridge_name)
except RuntimeError:
LOG.exception(_LE("Linux bridge %s delete failed"), bridge_name)
LOG.info(_LI("Linux bridge cleanup completed successfully"))
def main():
"""Main method for cleaning up empty linux bridges.
This tool deletes every empty linux bridge managed by linuxbridge agent
(brq.* linux bridges) except thes ones defined using bridge_mappings option
in section LINUX_BRIDGE (created by deployers).
This tool should not be called during an instance create, migrate, etc. as
it can delete a linux bridge about to be used by nova.
"""
cfg.CONF(sys.argv[1:])
config.setup_logging()
remove_empty_bridges()

View File

@ -526,10 +526,14 @@ class LinuxBridgeFixture(fixtures.Fixture):
:type namespace: str
"""
def __init__(self, prefix=BR_PREFIX):
super(LinuxBridgeFixture, self).__init__()
self.prefix = prefix
def _setUp(self):
self.namespace = self.useFixture(NamespaceFixture()).name
self.bridge = common_base.create_resource(
BR_PREFIX,
self.prefix,
bridge_lib.BridgeDevice.addbr,
namespace=self.namespace)
self.addCleanup(self.bridge.delbr)

View File

@ -16,3 +16,6 @@ nc_kill: KillFilter, root, nc, -9
ncbsd_kill: KillFilter, root, nc.openbsd, -9
ncat_kill: KillFilter, root, ncat, -9
ss_filter: CommandFilter, ss, root
# enable neutron-linuxbridge-cleanup from namespace
lb_cleanup_filter: RegExpFilter, neutron-linuxbridge-cleanup, root, neutron-linuxbridge-cleanup, --config-file, .*

View File

@ -0,0 +1,89 @@
# Copyright (c) 2015 Thales Services SAS
# 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 fixtures
import mock
from neutron.agent.linux import ip_lib
from neutron.common import constants
from neutron.plugins.ml2.drivers.linuxbridge.agent import \
linuxbridge_neutron_agent as lb_agent
from neutron.tests.common import config_fixtures
from neutron.tests.common import net_helpers
from neutron.tests.functional import base
from neutron.tests import tools
class LinuxbridgeCleanupTest(base.BaseSudoTestCase):
def _test_linuxbridge_cleanup(self, bridge_exists, callback):
br_fixture = self.useFixture(
tools.SafeCleanupFixture(
net_helpers.LinuxBridgeFixture(
prefix=lb_agent.BRIDGE_NAME_PREFIX))).fixture
config = callback(br_fixture)
temp_dir = self.useFixture(fixtures.TempDir()).path
conf = self.useFixture(config_fixtures.ConfigFileFixture(
base_filename='neutron.conf',
config=config,
temp_dir=temp_dir))
cmd = 'neutron-linuxbridge-cleanup', '--config-file', conf.filename
ip_wrapper = ip_lib.IPWrapper(br_fixture.namespace)
ip_wrapper.netns.execute(cmd)
self.assertEqual(bridge_exists, ip_lib.device_exists(
br_fixture.bridge.name, br_fixture.namespace))
def test_cleanup_empty_bridge(self):
def callback(br_fixture):
return config_fixtures.ConfigDict()
self._test_linuxbridge_cleanup(False, callback)
def test_no_cleanup_bridge_with_tap(self):
def callback(br_fixture):
# TODO(cbrandily): refactor net_helpers to avoid mocking it
mock.patch.object(
net_helpers, 'VETH0_PREFIX',
new_callable=mock.PropertyMock(
return_value=constants.TAP_DEVICE_PREFIX + '0')).start()
mock.patch.object(
net_helpers, 'VETH1_PREFIX',
new_callable=mock.PropertyMock(
return_value=constants.TAP_DEVICE_PREFIX + '1')).start()
self.useFixture(
tools.SafeCleanupFixture(
net_helpers.LinuxBridgePortFixture(
br_fixture.bridge, br_fixture.namespace)))
return config_fixtures.ConfigDict()
self._test_linuxbridge_cleanup(True, callback)
def test_no_cleanup_bridge_in_bridge_mappings(self):
def callback(br_fixture):
br_name = br_fixture.bridge.name
conf = config_fixtures.ConfigDict()
conf.update(
{'LINUX_BRIDGE': {'bridge_mappings': 'physnet:%s' % br_name}})
return conf
self._test_linuxbridge_cleanup(True, callback)

View File

@ -67,6 +67,24 @@ class WarningsFixture(fixtures.Fixture):
"always", category=wtype, module='^neutron\\.')
class SafeCleanupFixture(fixtures.Fixture):
"""Catch errors in daughter fixture cleanup."""
def __init__(self, fixture):
self.fixture = fixture
def _setUp(self):
def cleanUp():
try:
self.fixture.cleanUp()
except Exception:
pass
self.fixture.setUp()
self.addCleanup(cleanUp)
"""setup_mock_calls and verify_mock_calls are convenient methods
to setup a sequence of mock calls.

View File

@ -81,6 +81,7 @@ console_scripts =
neutron-ipset-cleanup = neutron.cmd.ipset_cleanup:main
neutron-l3-agent = neutron.cmd.eventlet.agents.l3:main
neutron-linuxbridge-agent = neutron.plugins.ml2.drivers.linuxbridge.agent.linuxbridge_neutron_agent:main
neutron-linuxbridge-cleanup = neutron.cmd.linuxbridge_cleanup:main
neutron-metadata-agent = neutron.cmd.eventlet.agents.metadata:main
neutron-mlnx-agent = neutron.cmd.eventlet.plugins.mlnx_neutron_agent:main
neutron-netns-cleanup = neutron.cmd.netns_cleanup:main