From ac34a8d839f91285f4ced605250422a1ecf5cb55 Mon Sep 17 00:00:00 2001 From: EricS <54029547+ESiebigteroth@users.noreply.github.com> Date: Tue, 3 Sep 2019 11:22:53 +0200 Subject: [PATCH] Implement network.fqdns module function (bsc#1134860) (#172) * Duplicate fqdns logic in module.network * Move _get_interfaces to utils.network * Reuse network.fqdns in grains.core.fqdns * Return empty list when fqdns grains is disabled Co-authored-by: Eric Siebigteroth --- salt/grains/core.py | 58 +++------------------------------- salt/modules/network.py | 12 +++---- salt/utils/network.py | 2 +- tests/unit/grains/test_core.py | 55 ++++++++++++-------------------- 4 files changed, 31 insertions(+), 96 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index 5f18ba4a58..0dc1d97f97 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -23,7 +23,6 @@ import uuid import warnings import zlib from errno import EACCES, EPERM -from multiprocessing.pool import ThreadPool import distro import salt.exceptions @@ -2406,59 +2405,10 @@ def fqdns(): then trying to reverse resolve them (excluding 'lo' interface). To disable the fqdns grain, set enable_fqdns_grains: False in the minion configuration file. """ - # Provides: - # fqdns - - grains = {} - fqdns = set() - - def _lookup_fqdn(ip): - try: - name, aliaslist, addresslist = socket.gethostbyaddr(ip) - return [socket.getfqdn(name)] + [ - als for als in aliaslist if salt.utils.network.is_fqdn(als) - ] - except socket.herror as err: - if err.errno in (0, HOST_NOT_FOUND, NO_DATA): - # No FQDN for this IP address, so we don't need to know this all the time. - log.debug("Unable to resolve address %s: %s", ip, err) - else: - log.error(err_message, ip, err) - except (OSError, socket.gaierror, socket.timeout) as err: - log.error(err_message, ip, err) - - start = time.time() - - addresses = salt.utils.network.ip_addrs( - include_loopback=False, interface_data=_get_interfaces() - ) - addresses.extend( - salt.utils.network.ip_addrs6( - include_loopback=False, interface_data=_get_interfaces() - ) - ) - err_message = "Exception during resolving address: %s" - - # Create a ThreadPool to process the underlying calls to 'socket.gethostbyaddr' in parallel. - # This avoid blocking the execution when the "fqdn" is not defined for certains IP addresses, which was causing - # that "socket.timeout" was reached multiple times secuencially, blocking execution for several seconds. - - try: - pool = ThreadPool(8) - results = pool.map(_lookup_fqdn, addresses) - pool.close() - pool.join() - except Exception as exc: - log.error("Exception while creating a ThreadPool for resolving FQDNs: %s", exc) - - for item in results: - if item: - fqdns.update(item) - - elapsed = time.time() - start - log.debug("Elapsed time getting FQDNs: {} seconds".format(elapsed)) - - return {"fqdns": sorted(list(fqdns))} + opt = {"fqdns": []} + if __opts__.get("enable_fqdns_grains", True) == True: + opt = __salt__["network.fqdns"]() + return opt def ip_fqdn(): diff --git a/salt/modules/network.py b/salt/modules/network.py index 2e1410c288..59ed43bba6 100644 --- a/salt/modules/network.py +++ b/salt/modules/network.py @@ -2,7 +2,6 @@ Module for gathering and managing network information """ -# Import python libs import datetime import hashlib import logging @@ -12,7 +11,6 @@ import socket import time from multiprocessing.pool import ThreadPool -# Import salt libs import salt.utils.decorators.path import salt.utils.functools import salt.utils.network @@ -20,8 +18,6 @@ import salt.utils.platform import salt.utils.validate.net from salt._compat import ipaddress from salt.exceptions import CommandExecutionError - -# Import 3rd-party libs from salt.ext.six.moves import range log = logging.getLogger(__name__) @@ -2076,7 +2072,10 @@ def fqdns(): def _lookup_fqdn(ip): try: - return [socket.getfqdn(socket.gethostbyaddr(ip)[0])] + name, aliaslist, addresslist = socket.gethostbyaddr(ip) + return [socket.getfqdn(name)] + [ + als for als in aliaslist if salt.utils.network.is_fqdn(als) + ] except socket.herror as err: if err.errno in (0, HOST_NOT_FOUND, NO_DATA): # No FQDN for this IP address, so we don't need to know this all the time. @@ -2102,13 +2101,12 @@ def fqdns(): # This avoid blocking the execution when the "fqdn" is not defined for certains IP addresses, which was causing # that "socket.timeout" was reached multiple times secuencially, blocking execution for several seconds. - results = [] try: pool = ThreadPool(8) results = pool.map(_lookup_fqdn, addresses) pool.close() pool.join() - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: log.error("Exception while creating a ThreadPool for resolving FQDNs: %s", exc) for item in results: diff --git a/salt/utils/network.py b/salt/utils/network.py index d253ded3ab..25b2d06758 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -49,7 +49,7 @@ except (ImportError, OSError, AttributeError, TypeError): _INTERFACES = {} -def _get_interfaces(): +def _get_interfaces(): #! function """ Provide a dict of the connected interfaces and their ip addresses """ diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py index d760e57a54..a5ceeb8317 100644 --- a/tests/unit/grains/test_core.py +++ b/tests/unit/grains/test_core.py @@ -18,6 +18,7 @@ import salt.utils.network import salt.utils.path import salt.utils.platform 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.unit import TestCase, skipIf @@ -1293,14 +1294,14 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): ): assert core.dns() == ret - def test_enable_fqdns_false(self): + def test_enablefqdnsFalse(self): """ tests enable_fqdns_grains is set to False """ with patch.dict("salt.grains.core.__opts__", {"enable_fqdns_grains": False}): assert core.fqdns() == {"fqdns": []} - def test_enable_fqdns_true(self): + def test_enablefqdnsTrue(self): """ testing that grains uses network.fqdns module """ @@ -1311,14 +1312,14 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): with patch.dict("salt.grains.core.__opts__", {"enable_fqdns_grains": True}): assert core.fqdns() == "my.fake.domain" - def test_enable_fqdns_none(self): + def test_enablefqdnsNone(self): """ testing default fqdns grains is returned when enable_fqdns_grains is None """ with patch.dict("salt.grains.core.__opts__", {"enable_fqdns_grains": None}): assert core.fqdns() == {"fqdns": []} - def test_enable_fqdns_without_patching(self): + def test_enablefqdnswithoutpaching(self): """ testing fqdns grains is enabled by default """ @@ -1326,23 +1327,7 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): "salt.grains.core.__salt__", {"network.fqdns": MagicMock(return_value="my.fake.domain")}, ): - # fqdns is disabled by default on Windows - if salt.utils.platform.is_windows(): - assert core.fqdns() == {"fqdns": []} - else: - assert core.fqdns() == "my.fake.domain" - - def test_enable_fqdns_false_is_proxy(self): - """ - testing fqdns grains is disabled by default for proxy minions - """ - with patch("salt.utils.platform.is_proxy", return_value=True, autospec=True): - with patch.dict( - "salt.grains.core.__salt__", - {"network.fqdns": MagicMock(return_value="my.fake.domain")}, - ): - # fqdns is disabled by default on proxy minions - assert core.fqdns() == {"fqdns": []} + assert core.fqdns() == "my.fake.domain" @skipIf(not salt.utils.platform.is_linux(), "System is not Linux") @patch( @@ -1367,11 +1352,12 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): ("bluesniff.foo.bar", [], ["fe80::a8b2:93ff:dead:beef"]), ] ret = {"fqdns": ["bluesniff.foo.bar", "foo.bar.baz", "rinzler.evil-corp.com"]} - with patch.object(socket, "gethostbyaddr", side_effect=reverse_resolv_mock): - fqdns = core.fqdns() - assert "fqdns" in fqdns - assert len(fqdns["fqdns"]) == len(ret["fqdns"]) - assert set(fqdns["fqdns"]) == set(ret["fqdns"]) + with patch.dict(core.__salt__, {"network.fqdns": salt.modules.network.fqdns}): + with patch.object(socket, "gethostbyaddr", side_effect=reverse_resolv_mock): + fqdns = core.fqdns() + assert "fqdns" in fqdns + assert len(fqdns["fqdns"]) == len(ret["fqdns"]) + assert set(fqdns["fqdns"]) == set(ret["fqdns"]) @skipIf(not salt.utils.platform.is_linux(), "System is not Linux") @patch("salt.utils.network.ip_addrs", MagicMock(return_value=["1.2.3.4"])) @@ -1437,14 +1423,15 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin): ["fe80::a8b2:93ff:dead:beef"], ), ] - with patch.object(socket, "gethostbyaddr", side_effect=reverse_resolv_mock): - fqdns = core.fqdns() - assert "fqdns" in fqdns - for alias in ["this.is.valid.alias", "alias.bluesniff.foo.bar"]: - assert alias in fqdns["fqdns"] - - for alias in ["throwmeaway", "false-hostname", "badaliass"]: - assert alias not in fqdns["fqdns"] + with patch.dict(core.__salt__, {"network.fqdns": salt.modules.network.fqdns}): + with patch.object(socket, "gethostbyaddr", side_effect=reverse_resolv_mock): + fqdns = core.fqdns() + assert "fqdns" in fqdns + for alias in ["this.is.valid.alias", "alias.bluesniff.foo.bar"]: + assert alias in fqdns["fqdns"] + + for alias in ["throwmeaway", "false-hostname", "badaliass"]: + assert alias not in fqdns["fqdns"] def test_core_virtual(self): """ -- 2.29.2