charm-neutron-openvswitch/unit_tests/test_neutron_ovs_utils.py
Pete Vander Giessen 00ca87fec3 Added gc_threshold overrides to sysctl.conf
When clouds have a large number of hosts, the default size of the ARP
cache is too small. The cache can overflow, which means that the
system has no way to reach some ip addresses.

Setting the threshold limits higher addresses the situation, in a
reasonably safe way (the maximum impact is 5MB or so of additional RAM
used). Docs on ARP at http://man7.org/linux/man-pages/man7/arp.7.html,
and more discussion of the issue in the bug.

Change-Id: I329ec51eff85a2a99a929c67ff0c68b3b36d7273
Closes-Bug: 1780348
2019-02-28 11:55:05 +01:00

976 lines
39 KiB
Python

# Copyright 2016 Canonical Ltd
#
# 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 hashlib
from mock import MagicMock, patch, call
from collections import OrderedDict
import charmhelpers.contrib.openstack.templating as templating
templating.OSConfigRenderer = MagicMock()
import neutron_ovs_utils as nutils
import neutron_ovs_context
from test_utils import (
CharmTestCase,
)
import charmhelpers
import charmhelpers.core.hookenv as hookenv
TO_PATCH = [
'add_bridge',
'add_bridge_port',
'add_ovsbridge_linuxbridge',
'is_linuxbridge_interface',
'dpdk_add_bridge_port',
'dpdk_add_bridge_bond',
'dpdk_set_bond_config',
'apt_install',
'apt_update',
'config',
'os_release',
'filter_installed_packages',
'filter_missing_packages',
'lsb_release',
'neutron_plugin_attribute',
'full_restart',
'service',
'service_restart',
'service_running',
'ExternalPortContext',
'determine_dkms_package',
'headers_package',
'status_set',
'use_dpdk',
'os_application_version_set',
'remote_restart',
'PCINetDevices',
'enable_ipfix',
'disable_ipfix',
'ovs_has_late_dpdk_init',
'parse_data_port_mappings',
'user_exists',
'group_exists',
'init_is_systemd',
]
head_pkg = 'linux-headers-3.15.0-5-generic'
def _mock_npa(plugin, attr, net_manager=None):
plugins = {
'ovs': {
'config': '/etc/neutron/plugins/ml2/ml2_conf.ini',
'driver': 'neutron.plugins.ml2.plugin.Ml2Plugin',
'contexts': [],
'services': ['neutron-plugin-openvswitch-agent'],
'packages': [[head_pkg], ['neutron-plugin-openvswitch-agent']],
'server_packages': ['neutron-server',
'neutron-plugin-ml2'],
'server_services': ['neutron-server']
},
}
return plugins[plugin][attr]
class DummyContext():
def __init__(self, return_value):
self.return_value = return_value
def __call__(self):
return self.return_value
class TestNeutronOVSUtils(CharmTestCase):
def setUp(self):
super(TestNeutronOVSUtils, self).setUp(nutils, TO_PATCH)
self.neutron_plugin_attribute.side_effect = _mock_npa
self.config.side_effect = self.test_config.get
self.use_dpdk.return_value = False
self.ovs_has_late_dpdk_init.return_value = False
def tearDown(self):
# Reset cached cache
hookenv.cache = {}
@patch.object(nutils, 'determine_packages')
def test_install_packages(self, _determine_packages):
self.os_release.return_value = 'mitaka'
_determine_packages.return_value = 'randompkg'
nutils.install_packages()
self.apt_update.assert_called_with()
self.apt_install.assert_called_with(self.filter_installed_packages(),
fatal=True)
@patch.object(nutils, 'determine_packages')
def test_install_packages_dkms_needed(self, _determine_packages):
self.os_release.return_value = 'mitaka'
_determine_packages.return_value = 'randompkg'
self.determine_dkms_package.return_value = \
['openvswitch-datapath-dkms']
self.headers_package.return_value = 'linux-headers-foobar'
nutils.install_packages()
self.apt_update.assert_called_with()
self.apt_install.assert_has_calls([
call(['linux-headers-foobar',
'openvswitch-datapath-dkms'], fatal=True),
call(self.filter_installed_packages(), fatal=True),
])
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
_use_dvr.return_value = False
_use_l3ha.return_value = False
_os_rel.return_value = 'icehouse'
self.os_release.return_value = 'icehouse'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-plugin-openvswitch-agent'
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_mitaka(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
_use_dvr.return_value = False
_use_l3ha.return_value = False
_os_rel.return_value = 'mitaka'
self.os_release.return_value = 'mitaka'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-openvswitch-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_metadata(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', True)
_use_dvr.return_value = False
_use_l3ha.return_value = False
_os_rel.return_value = 'icehouse'
self.os_release.return_value = 'icehouse'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-plugin-openvswitch-agent',
'neutron-dhcp-agent',
'neutron-metadata-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_dvr(self, _head_pkgs, _os_rel, _use_dvr,
_use_l3ha):
_use_dvr.return_value = True
_use_l3ha.return_value = False
_os_rel.return_value = 'icehouse'
self.os_release.return_value = 'icehouse'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-plugin-openvswitch-agent',
'neutron-l3-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_dvr_rocky(self, _head_pkgs, _os_rel, _use_dvr,
_use_l3ha):
_use_dvr.return_value = True
_use_l3ha.return_value = False
_os_rel.return_value = 'rocky'
self.os_release.return_value = 'rocky'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-l3-agent',
'neutron-openvswitch-agent',
'python3-neutron',
'python3-neutron-fwaas',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_newton_dvr_l3ha(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
_use_dvr.return_value = True
_use_l3ha.return_value = True
_os_rel.return_value = 'newton'
self.os_release.return_value = 'newton'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-l3-agent',
'keepalived',
'neutron-openvswitch-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_newton_dvr_no_l3ha(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
_use_dvr.return_value = True
_use_l3ha.return_value = False
_os_rel.return_value = 'newton'
self.os_release.return_value = 'newton'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-l3-agent',
'neutron-openvswitch-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_packages_mitaka_dvr_l3ha(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
_use_dvr.return_value = True
_use_l3ha.return_value = True
_os_rel.return_value = 'mitaka'
self.os_release.return_value = 'mitaka'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-l3-agent',
'neutron-openvswitch-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_pkgs_sriov(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
self.test_config.set('enable-sriov', True)
_use_dvr.return_value = False
_use_l3ha.return_value = False
_os_rel.return_value = 'kilo'
self.os_release.return_value = 'kilo'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-plugin-openvswitch-agent',
'neutron-plugin-sriov-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dvr')
@patch.object(charmhelpers.contrib.openstack.neutron, 'os_release')
@patch.object(charmhelpers.contrib.openstack.neutron, 'headers_package')
def test_determine_pkgs_sriov_mitaka(self, _head_pkgs, _os_rel,
_use_dvr, _use_l3ha):
self.test_config.set('enable-local-dhcp-and-metadata', False)
self.test_config.set('enable-sriov', True)
_use_dvr.return_value = False
_use_l3ha.return_value = False
_os_rel.return_value = 'mitaka'
self.os_release.return_value = 'mitaka'
_head_pkgs.return_value = head_pkg
pkg_list = nutils.determine_packages()
expect = [
head_pkg,
'neutron-openvswitch-agent',
'neutron-sriov-agent',
]
self.assertEqual(pkg_list, expect)
@patch.object(nutils, 'use_dvr')
def test_register_configs(self, _use_dvr):
class _mock_OSConfigRenderer():
def __init__(self, templates_dir=None, openstack_release=None):
self.configs = []
self.ctxts = []
def register(self, config, ctxt):
self.configs.append(config)
self.ctxts.append(ctxt)
_use_dvr.return_value = False
self.os_release.return_value = 'icehouse'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
_regconfs = nutils.register_configs()
confs = ['/etc/neutron/neutron.conf',
'/etc/neutron/plugins/ml2/ml2_conf.ini',
'/etc/default/openvswitch-switch',
'/etc/init/os-charm-phy-nic-mtu.conf']
self.assertEqual(_regconfs.configs, confs)
@patch.object(nutils, 'use_dvr')
def test_register_configs_mitaka(self, _use_dvr):
class _mock_OSConfigRenderer():
def __init__(self, templates_dir=None, openstack_release=None):
self.configs = []
self.ctxts = []
def register(self, config, ctxt):
self.configs.append(config)
self.ctxts.append(ctxt)
_use_dvr.return_value = False
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'trusty'}
templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer
_regconfs = nutils.register_configs()
confs = ['/etc/neutron/neutron.conf',
'/etc/neutron/plugins/ml2/openvswitch_agent.ini',
'/etc/init/os-charm-phy-nic-mtu.conf']
self.assertEqual(_regconfs.configs, confs)
@patch.object(nutils, 'use_dvr')
def test_resource_map(self, _use_dvr):
_use_dvr.return_value = False
self.os_release.return_value = 'icehouse'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
_map = nutils.resource_map()
svcs = ['neutron-plugin-openvswitch-agent']
confs = [nutils.NEUTRON_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
@patch.object(nutils, 'enable_sriov')
@patch.object(nutils, 'use_dvr')
def test_resource_map_kilo_sriov(self, _use_dvr, _enable_sriov):
_use_dvr.return_value = False
_enable_sriov.return_value = True
self.os_release.return_value = 'kilo'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'trusty'}
_map = nutils.resource_map()
svcs = ['neutron-plugin-openvswitch-agent',
'neutron-plugin-sriov-agent']
confs = [nutils.NEUTRON_CONF, nutils.NEUTRON_SRIOV_AGENT_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
self.assertEqual(_map[nutils.NEUTRON_SRIOV_AGENT_CONF]['services'],
['neutron-plugin-sriov-agent'])
@patch.object(nutils, 'use_dvr')
def test_resource_map_mitaka(self, _use_dvr):
_use_dvr.return_value = False
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
_map = nutils.resource_map()
svcs = ['neutron-openvswitch-agent']
confs = [nutils.NEUTRON_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
@patch.object(nutils, 'enable_sriov')
@patch.object(nutils, 'use_dvr')
def test_resource_map_mitaka_sriov(self, _use_dvr, _enable_sriov):
_use_dvr.return_value = False
_enable_sriov.return_value = True
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
_map = nutils.resource_map()
svcs = ['neutron-openvswitch-agent',
'neutron-sriov-agent']
confs = [nutils.NEUTRON_CONF, nutils.NEUTRON_SRIOV_AGENT_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
self.assertEqual(_map[nutils.NEUTRON_SRIOV_AGENT_CONF]['services'],
['neutron-sriov-agent'])
@patch.object(nutils, 'use_dvr')
def test_resource_map_dvr(self, _use_dvr):
_use_dvr.return_value = True
self.os_release.return_value = 'icehouse'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
_map = nutils.resource_map()
svcs = ['neutron-plugin-openvswitch-agent', 'neutron-metadata-agent',
'neutron-l3-agent']
confs = [nutils.NEUTRON_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
@patch.object(nutils, 'enable_local_dhcp')
@patch.object(nutils, 'use_dvr')
def test_resource_map_dhcp(self, _use_dvr, _enable_local_dhcp):
_enable_local_dhcp.return_value = True
_use_dvr.return_value = False
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
_map = nutils.resource_map()
svcs = ['neutron-metadata-agent', 'neutron-dhcp-agent',
'neutron-openvswitch-agent']
confs = [nutils.NEUTRON_CONF, nutils.NEUTRON_METADATA_AGENT_CONF,
nutils.NEUTRON_DHCP_AGENT_CONF]
[self.assertIn(q_conf, _map.keys()) for q_conf in confs]
self.assertEqual(_map[nutils.NEUTRON_CONF]['services'], svcs)
@patch.object(nutils, 'use_dvr')
def test_resource_map_mtu_trusty(self, _use_dvr):
_use_dvr.return_value = False
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'trusty'}
_map = nutils.resource_map()
self.assertTrue(nutils.NEUTRON_CONF in _map.keys())
self.assertTrue(nutils.PHY_NIC_MTU_CONF in _map.keys())
self.assertFalse(nutils.EXT_PORT_CONF in _map.keys())
_use_dvr.return_value = True
_map = nutils.resource_map()
self.assertTrue(nutils.EXT_PORT_CONF in _map.keys())
@patch.object(nutils, 'use_dvr')
def test_resource_map_mtu_xenial(self, _use_dvr):
_use_dvr.return_value = False
self.os_release.return_value = 'mitaka'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
_map = nutils.resource_map()
self.assertTrue(nutils.NEUTRON_CONF in _map.keys())
self.assertFalse(nutils.PHY_NIC_MTU_CONF in _map.keys())
self.assertFalse(nutils.EXT_PORT_CONF in _map.keys())
_use_dvr.return_value = True
_map = nutils.resource_map()
self.assertFalse(nutils.EXT_PORT_CONF in _map.keys())
@patch.object(nutils, 'use_l3ha')
@patch.object(nutils, 'use_dpdk')
@patch.object(nutils, 'use_dvr')
def test_restart_map(self, mock_use_dvr, mock_use_dpdk, mock_use_l3ha):
mock_use_dvr.return_value = False
mock_use_l3ha.return_value = False
mock_use_dpdk.return_value = False
self.os_release.return_value = "mitaka"
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'xenial'}
ML2CONF = "/etc/neutron/plugins/ml2/openvswitch_agent.ini"
_restart_map = nutils.restart_map()
expect = OrderedDict([
(nutils.NEUTRON_CONF, ['neutron-openvswitch-agent']),
(ML2CONF, ['neutron-openvswitch-agent']),
])
for item in _restart_map:
self.assertTrue(item in _restart_map)
self.assertTrue(expect[item] == _restart_map[item])
self.assertEqual(len(_restart_map.keys()), 2)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_ovs_data_port(self, mock_config, _use_dvr):
_use_dvr.return_value = False
self.is_linuxbridge_interface.return_value = False
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.ExternalPortContext.return_value = \
DummyContext(return_value=None)
# Test back-compatibility i.e. port but no bridge (so br-data is
# assumed)
self.test_config.set('data-port', 'eth0')
nutils.configure_ovs()
self.add_bridge.assert_has_calls([
call('br-int', 'system'),
call('br-ex', 'system'),
call('br-data', 'system')
])
self.assertTrue(self.add_bridge_port.called)
# Now test with bridge:port format
self.test_config.set('data-port', 'br-foo:eth0')
self.add_bridge.reset_mock()
self.add_bridge_port.reset_mock()
nutils.configure_ovs()
self.add_bridge.assert_has_calls([
call('br-int', 'system'),
call('br-ex', 'system'),
call('br-data', 'system')
])
# Not called since we have a bogus bridge in data-ports
self.assertFalse(self.add_bridge_port.called)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_data_port_with_bridge(self, mock_config, _use_dvr):
_use_dvr.return_value = False
self.is_linuxbridge_interface.return_value = True
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.ExternalPortContext.return_value = \
DummyContext(return_value=None)
# Now test with bridge:bridge format
self.test_config.set('bridge-mappings', 'physnet1:br-foo')
self.test_config.set('data-port', 'br-foo:br-juju')
self.add_bridge.reset_mock()
self.add_bridge_port.reset_mock()
nutils.configure_ovs()
self.assertTrue(self.add_ovsbridge_linuxbridge.called)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_starts_service_if_required(self, mock_config,
_use_dvr):
_use_dvr.return_value = False
mock_config.side_effect = self.test_config.get
self.config.return_value = 'ovs'
self.service_running.return_value = False
nutils.configure_ovs()
self.assertTrue(self.full_restart.called)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_doesnt_restart_service(self, mock_config, _use_dvr):
_use_dvr.return_value = False
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.service_running.return_value = True
nutils.configure_ovs()
self.assertFalse(self.full_restart.called)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_ovs_ext_port(self, mock_config, _use_dvr):
_use_dvr.return_value = True
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.test_config.set('ext-port', 'eth0')
self.ExternalPortContext.return_value = \
DummyContext(return_value={'ext_port': 'eth0'})
nutils.configure_ovs()
self.add_bridge.assert_has_calls([
call('br-int', 'system'),
call('br-ex', 'system'),
call('br-data', 'system')
])
self.add_bridge_port.assert_called_with('br-ex', 'eth0')
def _run_configure_ovs_dpdk(self, mock_config, _use_dvr,
_resolve_dpdk_bridges, _resolve_dpdk_bonds,
_late_init, _test_bonds):
def _resolve_port_name(pci_address, device_index, late_init):
if late_init:
return 'dpdk-{}'.format(
hashlib.sha1(pci_address.encode('UTF-8')).hexdigest()[:7]
)
else:
return 'dpdk{}'.format(device_index)
if _test_bonds:
_resolve_dpdk_bridges.return_value = OrderedDict()
_resolve_dpdk_bonds.return_value = OrderedDict([
('0000:001c.01', 'bond0'),
('0000:001c.02', 'bond1'),
('0000:001c.03', 'bond2'),
])
self.parse_data_port_mappings.return_value = OrderedDict([
('bond0', 'br-phynet1'),
('bond1', 'br-phynet2'),
('bond2', 'br-phynet3'),
])
else:
_resolve_dpdk_bridges.return_value = OrderedDict([
('0000:001c.01', 'br-phynet1'),
('0000:001c.02', 'br-phynet2'),
('0000:001c.03', 'br-phynet3'),
])
_resolve_dpdk_bonds.return_value = OrderedDict()
_use_dvr.return_value = True
self.use_dpdk.return_value = True
self.ovs_has_late_dpdk_init.return_value = _late_init
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.test_config.set('enable-dpdk', True)
nutils.configure_ovs()
self.add_bridge.assert_has_calls([
call('br-int', 'netdev'),
call('br-ex', 'netdev'),
call('br-phynet1', 'netdev'),
call('br-phynet2', 'netdev'),
call('br-phynet3', 'netdev')],
any_order=True
)
if _test_bonds:
self.dpdk_add_bridge_bond.assert_has_calls([
call('br-phynet1', 'bond0',
{_resolve_port_name('0000:001c.01',
0, _late_init): '0000:001c.01'}),
call('br-phynet2', 'bond1',
{_resolve_port_name('0000:001c.02',
1, _late_init): '0000:001c.02'}),
call('br-phynet3', 'bond2',
{_resolve_port_name('0000:001c.03',
2, _late_init): '0000:001c.03'})],
any_order=True
)
self.dpdk_set_bond_config.assert_has_calls([
call('bond0',
{'mode': 'balance-tcp',
'lacp': 'active',
'lacp-time': 'fast'}),
call('bond1',
{'mode': 'balance-tcp',
'lacp': 'active',
'lacp-time': 'fast'}),
call('bond2',
{'mode': 'balance-tcp',
'lacp': 'active',
'lacp-time': 'fast'})],
any_order=True
)
else:
self.dpdk_add_bridge_port.assert_has_calls([
call('br-phynet1',
_resolve_port_name('0000:001c.01',
0, _late_init),
'0000:001c.01'),
call('br-phynet2',
_resolve_port_name('0000:001c.02',
1, _late_init),
'0000:001c.02'),
call('br-phynet3',
_resolve_port_name('0000:001c.03',
2, _late_init),
'0000:001c.03')],
any_order=True
)
@patch.object(neutron_ovs_context, 'resolve_dpdk_bonds')
@patch.object(neutron_ovs_context, 'resolve_dpdk_bridges')
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_dpdk(self, mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds):
return self._run_configure_ovs_dpdk(mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds,
_late_init=False,
_test_bonds=False)
@patch.object(neutron_ovs_context, 'resolve_dpdk_bonds')
@patch.object(neutron_ovs_context, 'resolve_dpdk_bridges')
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_dpdk_late_init(self, mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds):
return self._run_configure_ovs_dpdk(mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds,
_late_init=True,
_test_bonds=False)
@patch.object(neutron_ovs_context, 'resolve_dpdk_bonds')
@patch.object(neutron_ovs_context, 'resolve_dpdk_bridges')
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_dpdk_late_init_bonds(self, mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds):
return self._run_configure_ovs_dpdk(mock_config, _use_dvr,
_resolve_dpdk_bridges,
_resolve_dpdk_bonds,
_late_init=True,
_test_bonds=True)
@patch.object(nutils, 'use_dvr')
@patch('charmhelpers.contrib.openstack.context.config')
def test_configure_ovs_enable_ipfix(self, mock_config, mock_use_dvr):
mock_use_dvr.return_value = False
mock_config.side_effect = self.test_config.get
self.config.side_effect = self.test_config.get
self.test_config.set('ipfix-target', '127.0.0.1:80')
nutils.configure_ovs()
self.enable_ipfix.assert_has_calls([
call('br-int', '127.0.0.1:80'),
call('br-ex', '127.0.0.1:80'),
])
@patch.object(neutron_ovs_context, 'SharedSecretContext')
def test_get_shared_secret(self, _dvr_secret_ctxt):
_dvr_secret_ctxt.return_value = \
DummyContext(return_value={'shared_secret': 'supersecret'})
self.assertEqual(nutils.get_shared_secret(), 'supersecret')
def test_assess_status(self):
with patch.object(nutils, 'assess_status_func') as asf:
callee = MagicMock()
asf.return_value = callee
nutils.assess_status('test-config')
asf.assert_called_once_with('test-config')
callee.assert_called_once_with()
self.os_application_version_set.assert_called_with(
nutils.VERSION_PACKAGE
)
@patch.object(nutils, 'REQUIRED_INTERFACES')
@patch.object(nutils, 'services')
@patch.object(nutils, 'determine_ports')
@patch.object(nutils, 'make_assess_status_func')
@patch.object(nutils, 'enable_nova_metadata')
def test_assess_status_func(self,
enable_nova_metadata,
make_assess_status_func,
determine_ports,
services,
REQUIRED_INTERFACES):
services.return_value = 's1'
determine_ports.return_value = 'p1'
enable_nova_metadata.return_value = False
REQUIRED_INTERFACES.copy.return_value = {'Test': True}
nutils.assess_status_func('test-config')
# ports=None whilst port checks are disabled.
make_assess_status_func.assert_called_once_with(
'test-config',
{'Test': True},
services='s1',
ports=None)
def test_pause_unit_helper(self):
with patch.object(nutils, '_pause_resume_helper') as prh:
nutils.pause_unit_helper('random-config')
prh.assert_called_once_with(nutils.pause_unit, 'random-config')
with patch.object(nutils, '_pause_resume_helper') as prh:
nutils.resume_unit_helper('random-config')
prh.assert_called_once_with(nutils.resume_unit, 'random-config')
@patch.object(nutils, 'services')
@patch.object(nutils, 'determine_ports')
def test_pause_resume_helper(self, determine_ports, services):
f = MagicMock()
services.return_value = 's1'
determine_ports.return_value = 'p1'
with patch.object(nutils, 'assess_status_func') as asf:
asf.return_value = 'assessor'
nutils._pause_resume_helper(f, 'some-config')
asf.assert_called_once_with('some-config')
# ports=None whilst port checks are disabled.
f.assert_called_once_with('assessor', services='s1', ports=None)
def _configure_sriov_base(self, config,
changed=False):
self.mock_config = MagicMock()
self.config.side_effect = None
self.config.return_value = self.mock_config
self.mock_config.get.side_effect = lambda x: config.get(x)
self.mock_config.changed.return_value = changed
self.mock_eth_device = MagicMock()
self.mock_eth_device.sriov = False
self.mock_eth_device.interface_name = 'eth0'
self.mock_eth_device.sriov_totalvfs = 0
self.mock_sriov_device = MagicMock()
self.mock_sriov_device.sriov = True
self.mock_sriov_device.interface_name = 'ens0'
self.mock_sriov_device.sriov_totalvfs = 64
self.mock_sriov_device2 = MagicMock()
self.mock_sriov_device2.sriov = True
self.mock_sriov_device2.interface_name = 'ens49'
self.mock_sriov_device2.sriov_totalvfs = 64
self.pci_devices = {
'eth0': self.mock_eth_device,
'ens0': self.mock_sriov_device,
'ens49': self.mock_sriov_device2,
}
mock_pci_devices = MagicMock()
mock_pci_devices.pci_devices = [
self.mock_eth_device,
self.mock_sriov_device,
self.mock_sriov_device2
]
self.PCINetDevices.return_value = mock_pci_devices
mock_pci_devices.get_device_from_interface_name.side_effect = \
lambda x: self.pci_devices.get(x)
@patch('os.chmod')
def test_configure_sriov_no_changes(self, _os_chmod):
self.os_release.return_value = 'kilo'
_config = {
'enable-sriov': True,
'sriov-numvfs': 'auto'
}
self._configure_sriov_base(_config, False)
nutils.configure_sriov()
self.assertFalse(self.remote_restart.called)
@patch('os.chmod')
def test_configure_sriov_auto(self, _os_chmod):
self.os_release.return_value = 'mitaka'
_config = {
'enable-sriov': True,
'sriov-numvfs': 'auto'
}
self._configure_sriov_base(_config, True)
nutils.configure_sriov()
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(
self.mock_sriov_device.sriov_totalvfs
)
self.mock_sriov_device2.set_sriov_numvfs.assert_called_with(
self.mock_sriov_device2.sriov_totalvfs
)
self.assertTrue(self.remote_restart.called)
@patch('os.chmod')
def test_configure_sriov_numvfs(self, _os_chmod):
self.os_release.return_value = 'mitaka'
_config = {
'enable-sriov': True,
'sriov-numvfs': '32',
}
self._configure_sriov_base(_config, True)
nutils.configure_sriov()
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(32)
self.mock_sriov_device2.set_sriov_numvfs.assert_called_with(32)
self.assertTrue(self.remote_restart.called)
@patch('os.chmod')
def test_configure_sriov_numvfs_per_device(self, _os_chmod):
self.os_release.return_value = 'kilo'
_config = {
'enable-sriov': True,
'sriov-numvfs': 'ens0:32 sriov23:64'
}
self._configure_sriov_base(_config, True)
nutils.configure_sriov()
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(32)
self.mock_sriov_device2.set_sriov_numvfs.assert_not_called()
self.assertTrue(self.remote_restart.called)
@patch.object(nutils, 'subprocess')
@patch.object(nutils, 'shutil')
def test_install_tmpfilesd_lxd(self, mock_shutil, mock_subprocess):
self.init_is_systemd.return_value = True
self.group_exists.return_value = False
self.user_exists.return_value = False
nutils.install_tmpfilesd()
mock_shutil.copy.assert_not_called()
mock_subprocess.check_call.assert_not_called()
@patch.object(nutils, 'subprocess')
@patch.object(nutils, 'shutil')
def test_install_tmpfilesd_libvirt(self, mock_shutil, mock_subprocess):
self.init_is_systemd.return_value = True
self.group_exists.return_value = True
self.user_exists.return_value = True
nutils.install_tmpfilesd()
mock_shutil.copy.assert_called_once()
mock_subprocess.check_call.assert_called_once_with(
['systemd-tmpfiles', '--create']
)
class TestDPDKBridgeBondMap(CharmTestCase):
def setUp(self):
super(TestDPDKBridgeBondMap, self).setUp(nutils,
TO_PATCH)
self.config.side_effect = self.test_config.get
def test_add_port(self):
ctx = nutils.DPDKBridgeBondMap()
ctx.add_port("br1", "bond1", "port1", "00:00:00:00:00:01")
ctx.add_port("br1", "bond1", "port2", "00:00:00:00:00:02")
ctx.add_port("br1", "bond2", "port3", "00:00:00:00:00:03")
ctx.add_port("br1", "bond2", "port4", "00:00:00:00:00:04")
expected = [(
'br1', {
'bond1': {
'port1': '00:00:00:00:00:01',
'port2': '00:00:00:00:00:02'
},
'bond2': {
'port3': '00:00:00:00:00:03',
'port4': '00:00:00:00:00:04',
},
},
)]
self.assertEqual(ctx.items(), expected)
class TestDPDKBondsConfig(CharmTestCase):
def setUp(self):
super(TestDPDKBondsConfig, self).setUp(nutils, TO_PATCH)
self.config.side_effect = self.test_config.get
def test_get_bond_config(self):
self.test_config.set('dpdk-bond-config',
':active-backup bond1:balance-slb:off')
bonds_config = nutils.DPDKBondsConfig()
self.assertEqual(bonds_config.get_bond_config('bond0'),
{'mode': 'active-backup',
'lacp': 'active',
'lacp-time': 'fast'
})
self.assertEqual(bonds_config.get_bond_config('bond1'),
{'mode': 'balance-slb',
'lacp': 'off',
'lacp-time': 'fast'
})