From 90017aa4f2089a365bffce1249df6ce1c50d8846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Tomsa?= Date: Mon, 16 Dec 2024 14:43:58 +0100 Subject: [PATCH] feat: Check connection In case of DNS failure. The DNS is queried, then a connection is established to the resolved IP. If resolving fails, a hard-coded IP is tried for production or staging. In case of either failure, DNS query for a public CloudFlare URL one.one.one.one and its IP 1.1.1.1 is tried. --- insights/client/connection.py | 64 ++++++++++++++++++++++++++++++++++- insights/client/constants.py | 4 +++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/insights/client/connection.py b/insights/client/connection.py index a3dfd75fbb..751a00d52d 100644 --- a/insights/client/connection.py +++ b/insights/client/connection.py @@ -4,6 +4,7 @@ from __future__ import print_function from __future__ import absolute_import import requests +import socket import os import six import json @@ -18,10 +19,12 @@ try: # python 2 from urlparse import urlparse + from urlparse import urlunparse from urllib import quote except ImportError: # python 3 from urllib.parse import urlparse + from urllib.parse import urlunparse from urllib.parse import quote from .utilities import (determine_hostname, generate_machine_id, @@ -74,6 +77,26 @@ def _api_request_failed(exception, message='The Insights API could not be reache logger.error(message) +def _is_dns_error(exception): + while exception: + if isinstance(exception, socket.gaierror): + return True + + exception = exception.__context__ + + return False + + +def _fallback_ip(hostname): + if hostname.endswith("redhat.com"): + if hostname.endswith("stage.redhat.com"): + return constants.insights_ip_stage + else: + return constants.insights_ip_prod + else: + return None + + class InsightsConnection(object): """ @@ -369,7 +392,6 @@ def _legacy_test_urls(self, url, method): if test_req.status_code in (200, 201): return True else: - logger.error(" Failed.") return False except REQUEST_FAILED_EXCEPTIONS as exc: last_ex = exc @@ -492,6 +514,22 @@ def test_connection(self, rc=0): logger.info("Running Connection Tests...") logger.info("") + # base_url_hostname = urlparse(self.base_url).hostname + # if base_url_hostname.endswith("redhat.com"): + # if base_url_hostname.endswith("stage.redhat.com"): + # base_url_ip = constants.insights_ip_stage + # else: + # base_url_ip = constants.insights_ip_prod + # else: + # base_url_ip = None + # + # resolved_base_url_ip, success_base_url_ip = self._test_connection(base_url_hostname, base_url_ip) + # if not resolved_base_url_ip or not success_base_url_ip: + # resolved_fallback_ip, success_fallback_ip = self._test_connection("www.redhat.com", constants.stable_public_ip) + # logger.debug("dns %s, conn %s", resolved_fallback_ip, success_fallback_ip) + # return False + + last_ex = None for description, url, method in [ ("Uploading a file to Ingress", self.upload_url, "POST"), ("Getting hosts from Inventory", self.inventory_url + "/hosts", "GET"), @@ -520,6 +558,30 @@ def test_connection(self, rc=0): logger.error(" Additional information may be in %s" % self.config.logging_file) logger.error("") + if _is_dns_error(last_ex): + parsed_url = urlparse(url) + logger.error(" Could not resolve %s.", parsed_url.hostname) + fallback = [constants.stable_public_url, constants.stable_public_ip] + ip = _fallback_ip(parsed_url.hostname) + if ip: + fallback = [ip] + fallback + + for fallback_url in fallback: + parsed_ip_url = urlunparse((parsed_url.scheme, fallback_url, "/", "", "", "")) + try: + logger.info(' Testing %s', parsed_ip_url) + log_prefix = " " + log_level = NETWORK if self.config.verbose else logging.DEBUG + self.get(parsed_ip_url, log_prefix=log_prefix, log_level=log_level, verify=False) + except REQUEST_FAILED_EXCEPTIONS as exc: + logger.debug(" Caught %s: %s", type(exc).__name__, exc) + logger.error(" Failed.") + else: + logger.info(" SUCCESS.") + break + else: + logger.info(" FAILED.") + return 1 def handle_fail_rcs(self, req): diff --git a/insights/client/constants.py b/insights/client/constants.py index 688878ad4a..6087096a90 100644 --- a/insights/client/constants.py +++ b/insights/client/constants.py @@ -90,3 +90,7 @@ class InsightsConstants(object): rhsm_facts_file = os.path.join(os.sep, 'etc', 'rhsm', 'facts', 'insights-client.facts') # In MB archive_filesize_max = 100 + insights_ip_prod = "23.37.45.238" + insights_ip_stage = "23.53.5.13" + stable_public_url = "one.one.one.one" # Public CloudFlare DNS + stable_public_ip = "1.1.1.1" # Public CloudFlare DNS