def _get_ip_lookup_cache() -> IPLookupCache: """A file based fall-back DNS cache in case resolution fails""" if "ip_lookup" in _config_cache: # Return already created and initialized cache return IPLookupCache(_config_cache.get("ip_lookup")) cache = IPLookupCache(_config_cache.get("ip_lookup")) cache.load_persisted() return cache
def _ip_to_hostname(config_cache: config.ConfigCache, ip: Optional[HostAddress]) -> Optional[HostName]: if "ip_to_hostname" not in _config_cache: cache = _config_cache.get("ip_to_hostname") for host in config_cache.all_active_realhosts(): host_config = config_cache.get_host_config(host) try: cache[config.lookup_ip_address(host_config, family=socket.AF_INET)] = host except Exception: pass else: cache = _config_cache.get("ip_to_hostname") return cache.get(ip)
def cached_dns_lookup( hostname: HostName, *, family: socket.AddressFamily, is_no_ip_host: bool, ) -> Optional[str]: cache = _config_cache.get("cached_dns_lookup") cache_id = hostname, family # Address has already been resolved in prior call to this function? try: return cache[cache_id] except KeyError: pass ip_lookup_cache = _get_ip_lookup_cache() cached_ip = ip_lookup_cache.get(cache_id) if cached_ip and config.use_dns_cache: cache[cache_id] = cached_ip return cached_ip if is_no_ip_host: cache[cache_id] = None return None # Now do the actual DNS lookup try: ipa = socket.getaddrinfo(hostname, None, family)[0][4][0] # Update our cached address if that has changed or was missing if ipa != cached_ip: console.verbose("Updating %s DNS cache for %s: %s\n" % (family, hostname, ipa)) ip_lookup_cache.update_cache(cache_id, ipa) cache[cache_id] = ipa # Update in-memory-cache return ipa except (MKTerminate, MKTimeout): # We should be more specific with the exception handler below, then we # could drop this special handling here raise except Exception as e: # DNS failed. Use cached IP address if present, even if caching # is disabled. if cached_ip: cache[cache_id] = cached_ip return cached_ip cache[cache_id] = None raise MKIPAddressLookupError("Failed to lookup %s address of %s via DNS: %s" % ( { socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6" }[family], hostname, e, ))
def update_timeperiods_cache() -> None: # { "last_update": 1498820128, "timeperiods": [{"24x7": True}] } # The value is store within the config cache since we need a fresh start on reload tp_cache = _config_cache.get("timeperiods_cache") if not tp_cache: response = livestatus.LocalConnection().query("GET timeperiods\nColumns: name in") for tp_name, tp_active in response: tp_cache[tp_name] = bool(tp_active)
def timeperiod_active(timeperiod: TimeperiodName) -> Optional[bool]: """Returns True : active False: inactive None : unknown timeperiod Raises an exception if e.g. a timeout or connection error appears. This way errors can be handled upstream.""" update_timeperiods_cache() return _config_cache.get("timeperiods_cache").get(timeperiod)
def check_timeperiod(timeperiod: TimeperiodName) -> bool: """Check if a timeperiod is currently active. We have no other way than doing a Livestatus query. This is not really nice, but if you have a better idea, please tell me...""" # Let exceptions happen, they will be handled upstream. try: update_timeperiods_cache() except MKTimeout: raise except Exception: if cmk.utils.debug.enabled(): raise # If the query is not successful better skip this check then fail return True # Note: This also returns True when the timeperiod is unknown # The following function timeperiod_active handles this differently return _config_cache.get("timeperiods_cache").get(timeperiod, True)
def cached_dns_lookup( hostname: HostName, *, family: socket.AddressFamily, force_file_cache_renewal: bool, ) -> Optional[HostAddress]: """Cached DNS lookup in *two* caching layers 1) outer layer (this function): A *config cache* that caches all calls until the configuration is changed or runtime ends. Other than activating a changed configuration there is no way to remove cached results during runtime. Changes made by a differend process will not be noticed. This layer caches `None` for lookups that failed, after raising the corresponding exception *once*. Subsequent lookups for this hostname / family combination will not raise an exception, until the configuration is changed. 2) inner layer: see _file_cached_dns_lookup """ cache = _config_cache.get("cached_dns_lookup") cache_id = hostname, family # Address has already been resolved in prior call to this function? try: return cache[cache_id] except KeyError: pass try: ip_address = _file_cached_dns_lookup( hostname, family, force_file_cache_renewal=force_file_cache_renewal, ) except MKIPAddressLookupError: cache[cache_id] = None raise return cache.setdefault(cache_id, ip_address)
def cleanup_timeperiod_caches() -> None: _config_cache.get("timeperiods_cache").clear()
def cached_dns_lookup( hostname: HostName, *, family: socket.AddressFamily, force_file_cache_renewal: bool, ) -> Optional[str]: """Cached DNS lookup in *two* caching layers 1) outer layer: A *config cache* that caches all calls until the configuration is changed or runtime ends. Other than activating a changed configuration there is no way to remove cached results during runtime. Changes made by a differend process will not be noticed. This layer caches `None` for lookups that failed, after raising the corresponding exception *once*. Subsequent lookups for this hostname / family combination will not raise an exception, until the configuration is changed. 2) inner layer: This layer caches *successful* lookups of host name / IP address family combinations, and writes them to a file. Note that after the file is loaded initially, the data in the IPLookupCache is keept in sync with the file, and itself stored in a dict in the config cache. Before a new value is writte to file, the file is re-read, as another process might have changed it. """ cache = _config_cache.get("cached_dns_lookup") cache_id = hostname, family # Address has already been resolved in prior call to this function? try: return cache[cache_id] except KeyError: pass ip_lookup_cache = _get_ip_lookup_cache() cached_ip = ip_lookup_cache.get(cache_id) if cached_ip and not force_file_cache_renewal: cache[cache_id] = cached_ip return cached_ip # Now do the actual DNS lookup try: ipa = socket.getaddrinfo(hostname, None, family)[0][4][0] # Update our cached address if that has changed or was missing if ipa != cached_ip: console.verbose("Updating %s DNS cache for %s: %s\n" % (family, hostname, ipa)) ip_lookup_cache.update_cache(cache_id, ipa) cache[cache_id] = ipa # Update in-memory-cache return ipa except (MKTerminate, MKTimeout): # We should be more specific with the exception handler below, then we # could drop this special handling here raise except Exception as e: # DNS failed. Use cached IP address if present, even if caching # is disabled. if cached_ip: cache[cache_id] = cached_ip return cached_ip cache[cache_id] = None raise MKIPAddressLookupError( "Failed to lookup %s address of %s via DNS: %s" % ( { socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6" }[family], hostname, e, ))