From 3c956a1cf1de17c5c49f0856051cabe2ffb4d0f2 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 29 Jan 2019 11:11:38 +0100 Subject: [PATCH] Include aliases in the fqdns grains Add UT for "is_fqdn" Add "is_fqdn" check to the network utils Bugfix: include FQDNs aliases Deprecate UnitTest assertion in favour of built-in assert keyword Add UT for fqdns aliases Leverage cached interfaces, if any. --- salt/grains/core.py | 69 +++++++++++++++++++++----------- salt/utils/network.py | 16 ++++++++ tests/unit/grains/test_core.py | 45 ++++++++++++++++++--- tests/unit/utils/test_network.py | 37 +++++++++++++++++ 4 files changed, 138 insertions(+), 29 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index bc3cf129cd..006878f806 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -1733,29 +1733,31 @@ def _parse_cpe_name(cpe): def _parse_cpe_name(cpe): - ''' + """ Parse CPE_NAME data from the os-release Info: https://csrc.nist.gov/projects/security-content-automation-protocol/scap-specifications/cpe :param cpe: :return: - ''' + """ part = { - 'o': 'operating system', - 'h': 'hardware', - 'a': 'application', + "o": "operating system", + "h": "hardware", + "a": "application", } ret = {} - cpe = (cpe or '').split(':') - if len(cpe) > 4 and cpe[0] == 'cpe': - if cpe[1].startswith('/'): # WFN to URI - ret['vendor'], ret['product'], ret['version'] = cpe[2:5] - ret['phase'] = cpe[5] if len(cpe) > 5 else None - ret['part'] = part.get(cpe[1][1:]) - elif len(cpe) == 13 and cpe[1] == '2.3': # WFN to a string - ret['vendor'], ret['product'], ret['version'], ret['phase'] = [x if x != '*' else None for x in cpe[3:7]] - ret['part'] = part.get(cpe[2]) + cpe = (cpe or "").split(":") + if len(cpe) > 4 and cpe[0] == "cpe": + if cpe[1].startswith("/"): # WFN to URI + ret["vendor"], ret["product"], ret["version"] = cpe[2:5] + ret["phase"] = cpe[5] if len(cpe) > 5 else None + ret["part"] = part.get(cpe[1][1:]) + elif len(cpe) == 13 and cpe[1] == "2.3": # WFN to a string + ret["vendor"], ret["product"], ret["version"], ret["phase"] = [ + x if x != "*" else None for x in cpe[3:7] + ] + ret["part"] = part.get(cpe[2]) return ret @@ -2396,15 +2398,36 @@ def fqdns(): """ # Provides: # fqdns - opt = {"fqdns": []} - if __opts__.get( - "enable_fqdns_grains", - False - if salt.utils.platform.is_windows() or salt.utils.platform.is_proxy() - else True, - ): - opt = __salt__["network.fqdns"]() - return opt + + grains = {} + fqdns = set() + + 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" + for ip in addresses: + try: + name, aliaslist, addresslist = socket.gethostbyaddr(ip) + fqdns.update( + [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) + + return {"fqdns": sorted(list(fqdns))} def ip_fqdn(): diff --git a/salt/utils/network.py b/salt/utils/network.py index b3e8db3886..dd7fceb91a 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -2208,3 +2208,19 @@ def filter_by_networks(values, networks): raise ValueError("Do not know how to filter a {}".format(type(values))) else: return values + + +def is_fqdn(hostname): + """ + Verify if hostname conforms to be a FQDN. + + :param hostname: text string with the name of the host + :return: bool, True if hostname is correct FQDN, False otherwise + """ + + compliant = re.compile(r"(?!-)[A-Z\d\-\_]{1,63}(?