-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Print config on connection test #4301
base: master
Are you sure you want to change the base?
Conversation
ca48f81
to
e3c1f79
Compare
5ba1101
to
27550e3
Compare
7a1a1b4
to
b7d593c
Compare
0afafe9
to
7561e75
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewing without running the code first. The methods seem reasonably split, that's a good indicator of it being maintainable, good job on that.
My biggest problem with this approach is that you are using logs as public API. Your output, to be pretty-printed, is prefixed with a bunch of space characters, and the fact that the stdout is your API makes your tests very verbose and difficult to handle. There is no separation between the business logic and the presentation.
Instead, I'd much rather see the tests return some kinds of objects (class instances, named tuples, exceptions, whatever) that would contain information about what has gone wrong.
For example, in _test_url_config()
, we could do something like
try:
parsed = urllib3.util.url.parse_url(url)
except urllib3.exceptions.LocationParseError:
return ConfigurationIssue(
cause="Malformed URL",
url=url,
description="API URL"
)
what would get pretty-printed somewhere else. This would make your tests much simpler and smaller.
I know the Core codebase does it, but please don't misuse logging for standard output. For this output-heavy command, let's use print
s instead. I'd like to see logs as well, for both ok and failed findings, to allow support and engineers debug network issues, though
14:37:01.001 ... test_connection OK: test=proxy-url, result=https://proxy.internal
14:37:01.003 ... test_connection OK: test=proxy-connection, result=can establish connection
that could be presented as text
Running tests...
- Proxy configuration is valid: OK
- Proxy is reachable: OK
...
|
||
|
||
def _exception_root_cause(exception): | ||
while True: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure this can't create an infinite loop?
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this looks smart, I'd be extremely worried to merge it. How can we be sure this will never change? Whole /11 range is owned by Akamai. The same goes to the DNS, I appreciate the effort, but I don't think we can do this in something that ships in RHEL.
For DNS diagnostics, I'd rather print "Unable to contact domain example.org (using DNS server a.b.c.d)." than use hardcoded ones.
for error in body["errors"]: | ||
if isinstance(error, dict) and "status" in error and error["status"] == 401 and "meta" in error and isinstance(error["meta"], dict) and "response_by" in error["meta"] and error["meta"]["response_by"] == "gateway": | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a long line! Wrap everything to 78 (or something higher but reasonable) please.
if "verify" not in kwargs: | ||
kwargs["verify"] = "/home/insights/simple-http-server/cert.pem" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
insights/client/connection.py
Outdated
if self.authmethod == "BASIC": | ||
logger.info("Authentication: login credentials (%s)", self.authmethod) | ||
|
||
for desc, var, placeholder in [ | ||
("Username", self.username, None), | ||
("Password", self.password, "********"), | ||
]: | ||
if not var: | ||
error = [" %s NOT SET.", desc] | ||
errors.append(error) | ||
|
||
val = placeholder or var if var else "NOT SET" | ||
logger.info(" %s: %s", desc, val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since 2025, BASIC authentication is not supported, we can drop this code.
(None, None, "NOT SET", "NOT SET", ["Username NOT SET", "Password NOT SET"]), | ||
], | ||
) | ||
def test_test_connection_basic_auth_incomplete_credentials_log( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BASIC auth is something we don't need to care about anymore.
d08127f
to
e0eae5d
Compare
e0eae5d
to
2d23bc6
Compare
For non-legacy, --test-connection dumps a user-friendly connection configuration. First, the authentication information is printed starting with type. For BASIC, username is printed. For CERT, certificate and key paths are verified and printed. In case of missing files or credentials, the connection test fails immediately. Second, tested URLs (base, Ingress, Inventory, API cast) are listed and server type (production, staging, Satellite) is determined. HTTPS proxy information is included. feat: Improve test URLs output _test_urls and _legacy_test_urls output is nicer, with clear SUCCESS/FAILURE statement. URLs are consistently listed, so is legacy fallback. With --verbose turned on, more information about requests, responses and errors are printed. The readability of the output improved drastically, with only little changes to the logging and tiny touches to the logic. The generic HTTP method logs information about the request. To make the log messages blend nicely into the connection test, introduced logging-related arguments: * To keep the output concise by default, but more helpful with --verbose, log_level suppresses HTTP details. * To match indentation with messages outside the request method, log_prefix allows to add spaces to the beginning. chore: Use return for flow control Exceptions in _(legacy_)test_urls are merely used for control-flow. Known ones are re-thrown and re-caught in test_connection, unknown ones are not caught at all. Return is more appropriate: _test_urls passes the result, test_connection decides how to handle it. feat: Test GET from Inventory Inventory is tested along with Ingress and an API ping. Hosts are listed as the most basic Inventory GET request. 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. feat: Recognize more errors * 429 Too Many requests means the rate limit was hit. * 401 Unauthorized from gateway means the username/password is invalid. * SSLError means the key/certificate pair is invalid. * SSL: WRONG_VERSION_NUMBER in the SSLError means that HTTPS has been used to contact an HTTP server. * ConnectionTimeout and ReadTimeout may mean the connection is slow. feat: Detect proxy errors HTTPS proxy introduces several possible error cases, similar to the actual remote server connection: * proxy name resolution (DNS) error, * proxy connection error, * proxy authentication error. The proxy authentication error can only be recognized by a string in the underlying OSError: the outer exception is a plain remote server connection error. Although the proxy is used for HTTPS connection, the actual communication for the proxy itself is HTTP. Thus, specifying a HTTPS protocol for the proxy causes a specific WRONG_VERSION_NUMBER SSL error. feat: Validate URLs urlparse from Python stdlib doesn’t fail on an invalid URL. parse_url from urllib3 used by requests does though. Invalid base URL or proxy URL raises thus an uncaught exception. Card IDs: * CCT-963 Signed-off-by: Štěpán Tomsa <stomsa@redhat.com>
2d23bc6
to
302347a
Compare
Copying my JIRA comment: To focus on another task, I am leaving this pull request to Petter. I pushed everything I have done so far. Matyáš’s review comments need to be addressed. Most importantly his request to split the presentation (error messages) from the logic (the actual connection tests). The test URLs method should return an object, which is then separately translated to the output. Doing so, the function can be mocked and tests are less brittle. (I was thinking about putting this in a follow-up card, keeping the current Insights Client style for now. Matyáš doesn’t want to merge without the split though.) Other things that need to be done are:
I thought it would be appropriate to change all the non-debug test connection log messages to the Personally, I would think parametrize the |
All Pull Requests:
Check all that apply:
Complete Description of Additions/Changes:
For non-legacy,
--test-connection
dumps a user-friendly connection configuration.First, the authentication information is printed starting with type. For
BASIC
, username is printed. ForCERT
, certificate and key paths are verified and printed. In case of missing files or credentials, the connection test fails immediately.Second, tested URLs (base, Ingress, Inventory, API cast) are listed and server type (production, staging, Satellite) is determined. HTTPS proxy information is included.
Card IDs: