diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 7c7b0cdf..c101b011 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -70,6 +70,10 @@ from charmhelpers.core.host import ( init_is_systemd, group_exists, user_exists, + is_container, +) +from charmhelpers.core.kernel import ( + modprobe, ) from charmhelpers.fetch import ( @@ -257,6 +261,20 @@ def install_packages(): if use_dpdk(): enable_ovs_dpdk() + # NOTE(tpsilva): if we're using openvswitch driver, we need to explicitly + # load the nf_conntrack_ipv4/6 module, since it won't be + # loaded automatically in some cases. LP#1834213 + if not is_container() and config('firewall-driver') == 'openvswitch': + try: + modprobe('nf_conntrack_ipv4', True) + modprobe('nf_conntrack_ipv6', True) + except subprocess.CalledProcessError: + # Newer kernel versions (4.19+) don't have two modules for that, so + # only load nf_conntrack + log("This kernel does not have nf_conntrack_ipv4/6. " + "Loading nf_conntrack only.") + modprobe('nf_conntrack', True) + def install_l3ha_packages(): apt_update() diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index 45fc6bec..a0defe67 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -13,6 +13,7 @@ # limitations under the License. import hashlib +import subprocess from mock import MagicMock, patch, call from collections import OrderedDict @@ -68,6 +69,8 @@ TO_PATCH = [ 'user_exists', 'group_exists', 'init_is_systemd', + 'modprobe', + 'is_container', ] head_pkg = 'linux-headers-3.15.0-5-generic' @@ -120,6 +123,46 @@ class TestNeutronOVSUtils(CharmTestCase): self.apt_update.assert_called_with() self.apt_install.assert_called_with(self.filter_installed_packages(), fatal=True) + self.modprobe.assert_not_called() + + @patch.object(nutils, 'determine_packages') + def test_install_packages_container(self, _determine_packages): + self.os_release.return_value = 'mitaka' + self.is_container.return_value = True + _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) + self.modprobe.assert_not_called() + + @patch.object(nutils, 'determine_packages') + def test_install_packages_ovs_firewall(self, _determine_packages): + self.os_release.return_value = 'mitaka' + _determine_packages.return_value = 'randompkg' + self.is_container.return_value = False + self.test_config.set('firewall-driver', 'openvswitch') + nutils.install_packages() + self.apt_update.assert_called_with() + self.apt_install.assert_called_with(self.filter_installed_packages(), + fatal=True) + self.modprobe.assert_has_calls([call('nf_conntrack_ipv4', True), + call('nf_conntrack_ipv6', True)]) + + @patch.object(nutils, 'determine_packages') + def test_install_packages_ovs_fw_newer_kernel(self, _determine_packages): + self.os_release.return_value = 'mitaka' + _determine_packages.return_value = 'randompkg' + self.is_container.return_value = False + self.test_config.set('firewall-driver', 'openvswitch') + self.modprobe.side_effect = [subprocess.CalledProcessError(0, ""), + None] + nutils.install_packages() + self.apt_update.assert_called_with() + self.apt_install.assert_called_with(self.filter_installed_packages(), + fatal=True) + self.modprobe.assert_has_calls([call('nf_conntrack_ipv4', True), + call('nf_conntrack', True)]) @patch.object(nutils, 'determine_packages') def test_install_packages_dkms_needed(self, _determine_packages):