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

OkHttpClient connection leak in OperationSupport / HttpResponse #4720

Closed
belks opened this issue Jan 3, 2023 · 0 comments · Fixed by #4722
Closed

OkHttpClient connection leak in OperationSupport / HttpResponse #4720

belks opened this issue Jan 3, 2023 · 0 comments · Fixed by #4722
Assignees
Milestone

Comments

@belks
Copy link

belks commented Jan 3, 2023

Hi,

while checking our logs we observed a warning from the OkHttpClient that a connection was leaked. As you can see in the stack trace at the very bottom of this ticket our application tried to call BaseOperation.list(), but ran into an unauthorized error. Shortly after that the OkHttpClient reports a connection leak.

Looking at your code we can see that in case of an unsuccessful response OperationSupport.assertResponseCode() calls OperationSupport.createStatus() which in turn gets the HTTP body string by calling HttpResponse.bodyString(). The default implementation of bodyString() of the HttpResponse interface then gets one of the SupportedResponses. In case of an input stream or reader this then calls IOHelpers.readFully. However the readFully does not close the stream that it is reading from. Our assumption is that in case of an error the SupportedResponses.INPUT_STREAM or SupportedResponses.READER is used. When looking at the OkHttpResponseImpl we see that the response body is closed in one case explicitly and for the string() and bytes() calls it is closed implicitly (according to the Kotlin sources of OkHttp). However, for the charStream() and byteStream() the response body should probably be closed be the consumer of the stream which is not happening in the SupportedResponses. And therefore the connection is leaked.

2022-12-31 22:08:19.788 WARN  [okhttp3.OkHttpClient] A connection to https://172.20.0.1/ was leaked. Did you forget to close a response body? To see where this was allocated, set the OkHttpClient logger level to FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);

2022-12-31 22:03:18.952 [...] WARN io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://172.20.0.1:443/api/v1/nodes?labelSelector=test%2Ftier%3Dapp. Message: Unauthorized! Configured service account doesn't have access. Service account may have been revoked. Unauthorized.
	at io.fabric8.kubernetes.client.KubernetesClientException.copyAsCause(KubernetesClientException.java:238) ~[kubernetes-client-api-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.waitForResult(OperationSupport.java:536) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:418) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:383) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:93) ~[kubernetes-client-6.3.1.jar:?]
[...]
Caused by: io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://172.20.0.1:443/api/v1/nodes?labelSelector=test%2Ftier%3Dapp. Message: Unauthorized! Configured service account doesn't have access. Service account may have been revoked. Unauthorized.
at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:742) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:722) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.assertResponseCode(OperationSupport.java:671) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.lambda$handleResponse$0(OperationSupport.java:601) ~[kubernetes-client-6.3.1.jar:?]
[...]

Fabric8 Kubernetes Client version

6.3.1

Steps to reproduce

  1. Call BaseOperation.list()
  2. Let the server return an unauthorized response for your request with the corresponding status code triggering the client to call OperationSupport.createStatus()
  3. Logs show a leaked OkHttp connection shortly afterwards

Expected behavior

No connection leak warning from OkHttp

Runtime

other (please specify in additional context)

Kubernetes API Server version

other (please specify in additional context)

Environment

Amazon

Fabric8 Kubernetes Client Logs

2022-12-31 22:08:19.788 WARN  [okhttp3.OkHttpClient] A connection to https://172.20.0.1/ was leaked. Did you forget to close a response body? To see where this was allocated, set the OkHttpClient logger level to FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);

2022-12-31 22:03:18.952 [...] WARN io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://172.20.0.1:443/api/v1/nodes?labelSelector=test%2Ftier%3Dapp. Message: Unauthorized! Configured service account doesn't have access. Service account may have been revoked. Unauthorized.
	at io.fabric8.kubernetes.client.KubernetesClientException.copyAsCause(KubernetesClientException.java:238) ~[kubernetes-client-api-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.waitForResult(OperationSupport.java:536) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:418) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:383) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.BaseOperation.list(BaseOperation.java:93) ~[kubernetes-client-6.3.1.jar:?]
[...]
Caused by: io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://172.20.0.1:443/api/v1/nodes?labelSelector=test%2Ftier%3Dapp. Message: Unauthorized! Configured service account doesn't have access. Service account may have been revoked. Unauthorized.
at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:742) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:722) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.assertResponseCode(OperationSupport.java:671) ~[kubernetes-client-6.3.1.jar:?]
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.lambda$handleResponse$0(OperationSupport.java:601) ~[kubernetes-client-6.3.1.jar:?]
[...]

Additional context

Unfortunately I don't know the kubernetes flavor or API server version, but it is anyways not relevant for this issue.

shawkins added a commit to shawkins/kubernetes-client that referenced this issue Jan 3, 2023
shawkins added a commit to shawkins/kubernetes-client that referenced this issue Jan 3, 2023
shawkins added a commit to shawkins/kubernetes-client that referenced this issue Jan 3, 2023
@manusa manusa added this to the 6.4.0 milestone Jan 4, 2023
@manusa manusa self-assigned this Jan 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants