Skip to content
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

Implement Java 11's HttpClient within RestClient [HZ-2460] #25654

Merged
merged 19 commits into from Oct 18, 2023

Conversation

JamesHazelcast
Copy link
Contributor

@JamesHazelcast JamesHazelcast commented Oct 9, 2023

During the investigation of - and solution generation for - #24613, it was noted that Java 11 provides the new HttpClient that features interruptible connections - the original solution was kept in place for 5.3, but with 5.4 we have now dropped JDK 8 support, so we can introduce this JDK 11 feature 🎉

This PR does exactly that, introducing HttpClient within the RestClient implementation we maintain as a Proof of Concept - this allows connections to be interrupted, as demonstrated in the KubernetesClient implementation, which is where the majority of focus for this PoC has been. Changes are generally fairly minimal outside of the RestClient itself and KubernetesClient implementation, with the main areas requiring changes being those that used #withCaCertificates() (now replaced by a separate constructor for clients using SSL), and timeout changes (connection/read timeouts are now unified).

This PR now also includes a regression test for the original issue that was encountered, ensuring the HttpClient solution still resolves the issue.

This is WIP and currently a first stage attempt; compiles/runs and KubernetesClient functions correctly (without an extra thread 🎉), but RestClientTest has 2 failures
With the old RestClient implementation, the connection formed in this test is never `HttpsURLConnection`, so the certificate was never used. In the new RestClient, the SSL context is created before the connection, so passing an invalid certificate breaks functionality.

Since this test did not utilise the caCertificate value before, there should be no impact from removing it.
# Conflicts:
#	hazelcast/src/main/java/com/hazelcast/kubernetes/KubernetesClient.java
#	hazelcast/src/main/java/com/hazelcast/spi/utils/RestClient.java
#	hazelcast/src/test/java/com/hazelcast/kubernetes/StsMonitorTest.java
#	hazelcast/src/test/java/com/hazelcast/spi/utils/RestClientTest.java
@hazelcast hazelcast deleted a comment from hz-devops-test Oct 9, 2023
@hazelcast hazelcast deleted a comment from hz-devops-test Oct 9, 2023
@JamesHazelcast
Copy link
Contributor Author

run-lab-run

1 similar comment
@JamesHazelcast
Copy link
Contributor Author

run-lab-run

@@ -47,8 +47,7 @@ static String currentTimestamp(Clock clock) {

static RestClient createRestClient(String url, AwsConfig awsConfig) {
return RestClient.create(url)
.withConnectTimeoutSeconds(awsConfig.getConnectionTimeoutSeconds())
.withReadTimeoutSeconds(awsConfig.getReadTimeoutSeconds())
.withPreferredTimeoutSeconds(awsConfig.getConnectionTimeoutSeconds(), awsConfig.getReadTimeoutSeconds())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the AWS config, It probably makes sense to have both - the timeout and the connectionTimeout (using HttpClient.Builder.connectTimeout(Duration)). If we want to support just one, we should improve the AWS config too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, thanks @kwart - I had originally dropped separate values since they seemed to be the same in all areas of the codebase, but this doesn't account for customizable values such as an AWS config. I've restored functionality for both timeouts in this commit 👍 6ea8e09

Also returns functionality where they were previously split values.
@hazelcast hazelcast deleted a comment from hz-devops-test Oct 11, 2023
@JamesHazelcast
Copy link
Contributor Author

run-lab-run

HttpClient in J11 will raise  `java.lang.IllegalArgumentException: restricted header name: "Host"` if a "Host" header is provided - there are overrides for this in J12 onwards, but not possible in J11.
@JamesHazelcast
Copy link
Contributor Author

JamesHazelcast commented Oct 13, 2023

Aws API tests were failing due to the setting of "Host" header which is not allowed with HttpClient in Java 11 - there are override properties available in J12, but not with J11. I've removed the "Host" header definitions and tests are passing locally (the "Host" header is set to the endpoint value provided in the URL already): 53289d4

@SeriyBg please let me know if this is a breaking change, and if so we may need to re-assess the viability of using HttpClient.

@hz-devops-test
Copy link

The job Hazelcast-pr-builder of your PR failed. (Hazelcast internal details: build log, artifacts).
Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log file
---------ERRORS-----------
--------------------------
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.180 s <<< FAILURE! -- in com.hazelcast.internal.metrics.jmx.MemberJmxMetricsTest
--------------------------
[ERROR] com.hazelcast.internal.metrics.jmx.MemberJmxMetricsTest.testNoMBeanLeak -- Time elapsed: 1.179 s <<< FAILURE!
--------------------------
[ERROR] Failures: 
--------------------------
[ERROR]   MemberJmxMetricsTest.testNoMBeanLeak:64 expected:<0> but was:<1>
--------------------------
[ERROR] Tests run: 4623, Failures: 1, Errors: 0, Skipped: 15
--------------------------
[ERROR] There are test failures.
--------------------------
--------------------------
-------TEST FAILURE-------
--------------------------
[INFO] Results:
[INFO] 
[ERROR] Failures: 
[ERROR]   MemberJmxMetricsTest.testNoMBeanLeak:64 expected:<0> but was:<1>
[INFO] 
[ERROR] Tests run: 4623, Failures: 1, Errors: 0, Skipped: 15
[INFO] 

[ERROR] There are test failures.

@JamesHazelcast
Copy link
Contributor Author

run-lab-run

@SeriyBg SeriyBg added the run-discovery-tests Used to run discovery plugins tests label Oct 16, 2023
@SeriyBg
Copy link
Contributor

SeriyBg commented Oct 16, 2023

@JamesHazelcast, the changes don't seem to be breaking one, as the Host header is set automatically anyway. However, the AWS tests are failing. It might be related to your changes and could be caused by the instability of the test suites, but I will spend a bit more time checking it

@SeriyBg SeriyBg added run-discovery-tests Used to run discovery plugins tests and removed run-discovery-tests Used to run discovery plugins tests labels Oct 16, 2023
Copy link
Contributor

@vbekiaris vbekiaris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - @JamesHazelcast can you make sure we run the kubernetes+persistence integration tests on EE side once this is merged to verify no regression?

@SeriyBg SeriyBg added run-discovery-tests Used to run discovery plugins tests and removed run-discovery-tests Used to run discovery plugins tests labels Oct 17, 2023
@SeriyBg
Copy link
Contributor

SeriyBg commented Oct 17, 2023

@JamesHazelcast, it seems that the change is, in fact, breaking the AWS integration. It fails during the cluster formation with an exception:

com.hazelcast.spi.exception.RestClientException: Failure executing: POST at: https://ecs.us-east-1.amazonaws.com. Message: {"__type":"InvalidSignatureException","message":"'Host' or ':authority' must be a 'SignedHeader' in the AWS Authorization."}. HTTP Error Code: 400

It seems that there is a fix for Java 12, but no workaround for Java 11:
https://bugs.openjdk.org/browse/JDK-8213189

Trim `host` header at RestClient level, leaving it in place for all other usages during signing.
@JamesHazelcast JamesHazelcast added run-discovery-tests Used to run discovery plugins tests and removed run-discovery-tests Used to run discovery plugins tests labels Oct 17, 2023
@JamesHazelcast
Copy link
Contributor Author

@JamesHazelcast, it seems that the change is, in fact, breaking the AWS integration. It fails during the cluster formation with an exception:

com.hazelcast.spi.exception.RestClientException: Failure executing: POST at: https://ecs.us-east-1.amazonaws.com. Message: {"__type":"InvalidSignatureException","message":"'Host' or ':authority' must be a 'SignedHeader' in the AWS Authorization."}. HTTP Error Code: 400

It seems that there is a fix for Java 12, but no workaround for Java 11: https://bugs.openjdk.org/browse/JDK-8213189

My latest commit appears to have resolved the issue for the AWS discovery tests - hopefully no more failures 🤞

Copy link
Contributor

@SeriyBg SeriyBg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some failures in the K8s Test suite, but it seems to be a problem in the suite itself. I've checked the K8s discovery and can confirm that it's working, and the member discovery is working. LGTM

@JamesHazelcast
Copy link
Contributor Author

Thanks for the reviews everyone, greatly appreciated :)

@JamesHazelcast JamesHazelcast merged commit 13b466c into hazelcast:master Oct 18, 2023
14 of 17 checks passed
@JamesHazelcast JamesHazelcast deleted the poc/5.4/hz-2460 branch October 18, 2023 11:26
Fly-Style pushed a commit to Fly-Style/hazelcast that referenced this pull request Oct 31, 2023
…#25654)

During the investigation of - and solution generation for -
hazelcast#24613, it was noted that
Java 11 provides the new `HttpClient` that features interruptible
connections - the original solution was kept in place for 5.3, but with
5.4 we have now dropped JDK 8 support, so we can introduce this JDK 11
feature 🎉

This PR does exactly that, introducing `HttpClient` within the
`RestClient` implementation we maintain as a Proof of Concept - this
allows connections to be interrupted, as demonstrated in the
`KubernetesClient` implementation, which is where the majority of focus
for this PoC has been. Changes are generally fairly minimal outside of
the `RestClient` itself and `KubernetesClient` implementation, with the
main areas requiring changes being those that used
`#withCaCertificates()` (now replaced by a separate constructor for
clients using SSL), and timeout changes (connection/read timeouts are
now unified).

This PR now also includes a regression test for the original issue that
was encountered, ensuring the `HttpClient` solution still resolves the
issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants