mirror of https://github.com/grpc/grpc-java.git
core: Convert inappropriate call cred errors (#9543)
If a CallCredentials implementation returns an error that is not appropriate to propagate from the control plane to the data plane, we convert it to an INTERNAL error. This makes the inappropriate control plane behavior to be discoverable in the logs. https://github.com/grpc/proposal/blob/master/A54-restrict-control-plane-status-codes.md
This commit is contained in:
parent
944cbf84ed
commit
341fea8996
|
@ -82,7 +82,8 @@ final class MetadataApplierImpl extends MetadataApplier {
|
|||
public void fail(Status status) {
|
||||
checkArgument(!status.isOk(), "Cannot fail with OK status");
|
||||
checkState(!finalized, "apply() or fail() already called");
|
||||
finalizeWith(new FailingClientStream(status, tracers));
|
||||
finalizeWith(
|
||||
new FailingClientStream(GrpcUtil.replaceInappropriateControlPlaneStatus(status), tracers));
|
||||
}
|
||||
|
||||
private void finalizeWith(ClientStream stream) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package io.grpc.internal;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
@ -41,6 +42,7 @@ import io.grpc.Metadata;
|
|||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.SecurityLevel;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.StringMarshaller;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
@ -265,7 +267,7 @@ public class CallCredentialsApplyingTest {
|
|||
|
||||
@Test
|
||||
public void fail_inline() {
|
||||
final Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
|
||||
final Status error = Status.UNAVAILABLE.withDescription("channel not secure for creds");
|
||||
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
|
@ -291,6 +293,38 @@ public class CallCredentialsApplyingTest {
|
|||
verify(mockTransport).shutdownNow(Status.UNAVAILABLE);
|
||||
}
|
||||
|
||||
// If the creds return an error that is inappropriate to directly propagate from the control plane
|
||||
// to the call, it should be converted to an INTERNAL error.
|
||||
@Test
|
||||
public void fail_inline_inappropriate_error() {
|
||||
final Status error = Status.NOT_FOUND.withDescription("channel not secure for creds");
|
||||
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
CallCredentials.MetadataApplier applier =
|
||||
(CallCredentials.MetadataApplier) invocation.getArguments()[2];
|
||||
applier.fail(error);
|
||||
return null;
|
||||
}
|
||||
}).when(mockCreds).applyRequestMetadata(any(RequestInfo.class),
|
||||
same(mockExecutor), any(CallCredentials.MetadataApplier.class));
|
||||
|
||||
FailingClientStream stream = (FailingClientStream) transport.newStream(
|
||||
method, origHeaders, callOptions, tracers);
|
||||
|
||||
verify(mockTransport, never()).newStream(
|
||||
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class),
|
||||
ArgumentMatchers.<ClientStreamTracer[]>any());
|
||||
assertThat(stream.getError().getCode()).isEqualTo(Code.INTERNAL);
|
||||
assertThat(stream.getError().getDescription()).contains("Inappropriate");
|
||||
assertThat(stream.getError().getCause()).isNull();
|
||||
transport.shutdownNow(Status.UNAVAILABLE);
|
||||
assertTrue(transport.newStream(method, origHeaders, callOptions, tracers)
|
||||
instanceof FailingClientStream);
|
||||
verify(mockTransport).shutdownNow(Status.UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyMetadata_delayed() {
|
||||
when(mockTransport.getAttributes()).thenReturn(Attributes.EMPTY);
|
||||
|
@ -406,7 +440,7 @@ public class CallCredentialsApplyingTest {
|
|||
verify(mockCreds).applyRequestMetadata(any(RequestInfo.class),
|
||||
same(mockExecutor), applierCaptor.capture());
|
||||
|
||||
Status error = Status.FAILED_PRECONDITION.withDescription("channel not secure for creds");
|
||||
Status error = Status.UNAVAILABLE.withDescription("channel not secure for creds");
|
||||
applierCaptor.getValue().fail(error);
|
||||
|
||||
verify(mockTransport, never()).newStream(
|
||||
|
|
Loading…
Reference in New Issue