Load nf_conntrack at boot time

Sysctl rules fined in charm config fails to be
applied in ovn enviroments because the rules are
applied before nf_conntrack is loaded.

By adding nf_conntrack to the /etc/modules file
it guarantees that it will be loaded before the
rules are applied.

Closes-Bug: #1922778
Change-Id: I51dae65cdc06e35230160bcaedda99710a72617d
This commit is contained in:
Rodrigo Barbieri 2024-04-15 13:45:45 -03:00
parent 31df8c6bf2
commit 389d2b7cb1
2 changed files with 110 additions and 0 deletions

View File

@ -24,9 +24,12 @@ import os
import subprocess
import grp
import shutil
import yaml
import charmhelpers.core.unitdata as unitdata
from charmhelpers.core.kernel import modprobe
from charmhelpers.core.hookenv import (
Hooks,
config,
@ -250,6 +253,7 @@ def config_changed():
send_remote_restart = True
sysctl_settings = config('sysctl')
ensure_nf_conntrack_module_loaded(sysctl_settings)
if sysctl_settings and not is_container():
create_sysctl(
sysctl_settings,
@ -330,6 +334,29 @@ def config_changed():
check_and_start_iscsid()
def ensure_nf_conntrack_module_loaded(sysctl_str):
"""Loads and writes nf_conntrack to /etc/modules if present in sysctls."""
# abort if empty or container
if not sysctl_str or is_container():
return
try:
sysctl_dict = yaml.safe_load(sysctl_str)
except yaml.YAMLError:
log("Error parsing YAML sysctl_dict: {}".format(sysctl_str),
level=ERROR)
return
if any("nf_conntrack" in key for key in sysctl_dict.keys()):
try:
# this call loads the module and writes an entry in /etc/modules
# for automatic loading at early boot
modprobe("nf_conntrack")
except Exception as e:
log("Failed to load or persist nf_conntrack"
" kernel module: {}".format(e), level=WARNING)
def update_all_configs():
CONFIGS.write_all()

View File

@ -453,6 +453,89 @@ class NovaComputeRelationsTests(CharmTestCase):
user='nova'
)
@patch.object(hooks, 'is_container')
@patch('yaml.safe_load')
def test_ensure_nf_conntrack_module_loaded_empty(
self, safe_load, is_container):
is_container.return_value = False
hooks.ensure_nf_conntrack_module_loaded("")
safe_load.assert_not_called()
@patch.object(hooks, 'is_container')
@patch('yaml.safe_load')
def test_ensure_nf_conntrack_module_loaded_container(
self, safe_load, is_container):
is_container.return_value = True
hooks.ensure_nf_conntrack_module_loaded("foo")
safe_load.assert_not_called()
@patch.object(hooks, 'modprobe')
@patch.object(hooks, 'is_container')
@patch('yaml.safe_load')
def test_ensure_nf_conntrack_module_loaded_failed_yaml(
self, safe_load, is_container, modprobe):
is_container.return_value = False
hooks.ensure_nf_conntrack_module_loaded("foo")
safe_load.assert_called_once_with("foo")
modprobe.assert_not_called()
@patch.object(hooks, 'log')
@patch.object(hooks, 'modprobe')
@patch.object(hooks, 'is_container')
def test_ensure_nf_conntrack_module_loaded_failed_mobprobe(
self, is_container, modprobe, log):
is_container.return_value = False
modprobe.side_effect = Exception("FOO")
data = ("{ net.ipv4.neigh.default.gc_thresh1 : 128,"
"net.ipv4.neigh.default.gc_thresh2 : 28672,"
"net.ipv4.neigh.default.gc_thresh3 : 32768,"
"net.ipv6.neigh.default.gc_thresh1 : 128,"
"net.ipv6.neigh.default.gc_thresh2 : 28672,"
"net.ipv6.neigh.default.gc_thresh3 : 32768,"
"net.nf_conntrack_max : 1000000,"
"net.netfilter.nf_conntrack_buckets : 204800,"
"net.netfilter.nf_conntrack_max : 1000000 }")
hooks.ensure_nf_conntrack_module_loaded(data)
log.assert_called_once_with(
"Failed to load or persist nf_conntrack kernel module: FOO",
level="WARNING")
modprobe.assert_called_once_with("nf_conntrack")
@patch.object(hooks, 'log')
@patch.object(hooks, 'modprobe')
@patch.object(hooks, 'is_container')
def test_ensure_nf_conntrack_module_loaded(
self, is_container, modprobe, log):
is_container.return_value = False
data = ("{ net.ipv4.neigh.default.gc_thresh1 : 128,"
"net.ipv4.neigh.default.gc_thresh2 : 28672,"
"net.ipv4.neigh.default.gc_thresh3 : 32768,"
"net.ipv6.neigh.default.gc_thresh1 : 128,"
"net.ipv6.neigh.default.gc_thresh2 : 28672,"
"net.ipv6.neigh.default.gc_thresh3 : 32768,"
"net.nf_conntrack_max : 1000000,"
"net.netfilter.nf_conntrack_buckets : 204800,"
"net.netfilter.nf_conntrack_max : 1000000 }")
hooks.ensure_nf_conntrack_module_loaded(data)
log.assert_not_called()
modprobe.assert_called_once_with("nf_conntrack")
@patch.object(hooks, 'log')
@patch.object(hooks, 'modprobe')
@patch.object(hooks, 'is_container')
def test_ensure_nf_conntrack_module_loaded_no_sysctl(
self, is_container, modprobe, log):
is_container.return_value = False
data = ("{ net.ipv4.neigh.default.gc_thresh1 : 128,"
"net.ipv4.neigh.default.gc_thresh2 : 28672,"
"net.ipv4.neigh.default.gc_thresh3 : 32768,"
"net.ipv6.neigh.default.gc_thresh1 : 128,"
"net.ipv6.neigh.default.gc_thresh2 : 28672,"
"net.ipv6.neigh.default.gc_thresh3 : 32768 }")
hooks.ensure_nf_conntrack_module_loaded(data)
modprobe.assert_not_called()
log.assert_not_called()
def test_amqp_joined(self):
hooks.amqp_joined()
self.relation_set.assert_called_with(