File clear-network-interface-cache-when-grains-are-reques.patch of Package salt
From 32b31c7b897b48a427336e1a16776a71e66960e2 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Thu, 3 Mar 2022 19:11:39 +0300
Subject: [PATCH] Clear network interface cache when grains are
requested or refreshed (#60130) (#494)
* test patch
* pre commit
* Add tests for network interfaces cache
* Document test better
* pre commit and changes
Co-authored-by: Joe Eacott <jeacott@vmware.com>
Co-authored-by: Daniel A. Wozniak <dwozniak@saltstack.com>
Co-authored-by: Joe Eacott <31625359+xeacott@users.noreply.github.com>
Co-authored-by: Joe Eacott <jeacott@vmware.com>
Co-authored-by: Daniel A. Wozniak <dwozniak@saltstack.com>
---
changelog/59490.fixed | 1 +
salt/grains/core.py | 6 ++-
salt/utils/network.py | 25 ++++++----
tests/unit/grains/test_core.py | 90 ++++++++++++++++++++++++++++++++++
4 files changed, 112 insertions(+), 10 deletions(-)
create mode 100644 changelog/59490.fixed
diff --git a/changelog/59490.fixed b/changelog/59490.fixed
new file mode 100644
index 0000000000..a523fff36d
--- /dev/null
+++ b/changelog/59490.fixed
@@ -0,0 +1 @@
+Clear the cached network interface grains during minion init and grains refresh
diff --git a/salt/grains/core.py b/salt/grains/core.py
index 875d6f6b50..202a8e61f1 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -43,7 +43,7 @@ import salt.utils.platform
import salt.utils.stringutils
import salt.utils.versions
from salt.ext.six.moves import range
-from salt.utils.network import _get_interfaces
+from salt.utils.network import _clear_interfaces, _get_interfaces
# pylint: disable=import-error
try:
@@ -111,6 +111,10 @@ HOST_NOT_FOUND = 1
NO_DATA = 4
+def __init__(opts):
+ _clear_interfaces()
+
+
def _windows_cpudata():
"""
Return some CPU information on Windows minions
diff --git a/salt/utils/network.py b/salt/utils/network.py
index 1705a5809d..47883f3d0d 100644
--- a/salt/utils/network.py
+++ b/salt/utils/network.py
@@ -46,18 +46,25 @@ except (ImportError, OSError, AttributeError, TypeError):
pass
-_INTERFACES = {}
+class Interfaces:
+ __slots__ = ("interfaces",)
+ def __init__(self, interfaces=None):
+ if interfaces is None:
+ interfaces = {}
+ self.interfaces = interfaces
+
+ def __call__(self, *args, **kwargs):
+ if not self.interfaces:
+ self.interfaces = interfaces()
+ return self.interfaces
+
+ def clear(self):
+ self.interfaces = {}
-def _get_interfaces(): #! function
- """
- Provide a dict of the connected interfaces and their ip addresses
- """
- global _INTERFACES
- if not _INTERFACES:
- _INTERFACES = interfaces()
- return _INTERFACES
+_get_interfaces = Interfaces()
+_clear_interfaces = _get_interfaces.clear
def sanitize_host(host):
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
index e73fc0730d..4773ef3b4d 100644
--- a/tests/unit/grains/test_core.py
+++ b/tests/unit/grains/test_core.py
@@ -6,6 +6,7 @@ import logging
import os
import platform
import socket
+import tempfile
import textwrap
import salt.grains.core as core
@@ -21,6 +22,7 @@ from salt._compat import ipaddress
from salt.ext import six
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, Mock, mock_open, patch
+from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase, skipIf
try:
@@ -2336,3 +2338,91 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(core.__opts__, {"id": "otherid"}):
assert core.get_server_id() != expected
+
+ def test_network_grains_cache(self):
+ """
+ Network interfaces are cache is cleared by the loader
+ """
+ call_1 = {
+ "lo": {
+ "up": True,
+ "hwaddr": "00:00:00:00:00:00",
+ "inet": [
+ {
+ "address": "127.0.0.1",
+ "netmask": "255.0.0.0",
+ "broadcast": None,
+ "label": "lo",
+ }
+ ],
+ "inet6": [],
+ },
+ "wlo1": {
+ "up": True,
+ "hwaddr": "29:9f:9f:e9:67:f4",
+ "inet": [
+ {
+ "address": "172.16.13.85",
+ "netmask": "255.255.248.0",
+ "broadcast": "172.16.15.255",
+ "label": "wlo1",
+ }
+ ],
+ "inet6": [],
+ },
+ }
+ call_2 = {
+ "lo": {
+ "up": True,
+ "hwaddr": "00:00:00:00:00:00",
+ "inet": [
+ {
+ "address": "127.0.0.1",
+ "netmask": "255.0.0.0",
+ "broadcast": None,
+ "label": "lo",
+ }
+ ],
+ "inet6": [],
+ },
+ "wlo1": {
+ "up": True,
+ "hwaddr": "29:9f:9f:e9:67:f4",
+ "inet": [
+ {
+ "address": "172.16.13.86",
+ "netmask": "255.255.248.0",
+ "broadcast": "172.16.15.255",
+ "label": "wlo1",
+ }
+ ],
+ "inet6": [],
+ },
+ }
+ tmp_path = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
+ cache_dir = os.path.join(tmp_path, "cache")
+ extmods = os.path.join(tmp_path, "extmods")
+ opts = {
+ "cachedir": str(cache_dir),
+ "extension_modules": str(extmods),
+ "optimization_order": [0],
+ }
+ with patch(
+ "salt.utils.network.interfaces", side_effect=[call_1, call_2]
+ ) as interfaces:
+ grains = salt.loader.grain_funcs(opts)
+ assert interfaces.call_count == 0
+ ret = grains["core.ip_interfaces"]()
+ # interfaces has been called
+ assert interfaces.call_count == 1
+ assert ret["ip_interfaces"]["wlo1"] == ["172.16.13.85"]
+ # interfaces has been cached
+ ret = grains["core.ip_interfaces"]()
+ assert interfaces.call_count == 1
+ assert ret["ip_interfaces"]["wlo1"] == ["172.16.13.85"]
+
+ grains = salt.loader.grain_funcs(opts)
+ ret = grains["core.ip_interfaces"]()
+ # A new loader clears the cache and interfaces is called again
+ assert interfaces.call_count == 2
+ assert ret["ip_interfaces"]["wlo1"] == ["172.16.13.86"]
--
2.35.1