This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 7a138954ee HDDS-9663. Allow OM to detect client address when using
gRPC (#5590)
7a138954ee is described below
commit 7a138954ee628e161c1ce857e82e8a5117ff00ab
Author: Slava Tutrinov <[email protected]>
AuthorDate: Sat Nov 18 11:56:09 2023 +0300
HDDS-9663. Allow OM to detect client address when using gRPC (#5590)
---
hadoop-ozone/common/pom.xml | 5 ++
.../ozone/om/protocolPB/GrpcOmTransport.java | 21 ++++--
.../grpc/ClientAddressClientInterceptor.java | 55 +++++++++++++++
.../grpc/ClientAddressServerInterceptor.java | 48 +++++++++++++
.../om/protocolPB/grpc/GrpcClientConstants.java | 44 ++++++++++++
.../ozone/om/protocolPB/grpc/package-info.java | 22 ++++++
.../grpc/TestClientAddressClientInterceptor.java | 79 ++++++++++++++++++++++
.../grpc/TestClientAddressServerInterceptor.java | 78 +++++++++++++++++++++
.../hadoop/ozone/om/GrpcOzoneManagerServer.java | 2 +
.../apache/hadoop/ozone/om/OmMetadataReader.java | 13 +++-
.../hadoop/ozone/om/request/OMClientRequest.java | 9 +++
.../hadoop/ozone/om/TestOMMetadataReader.java | 74 ++++++++++++++++++++
.../ozone/om/request/OMRequestTestUtils.java | 16 +++++
.../request/TestOMClientRequestWithUserInfo.java | 47 +++++++++++--
14 files changed, 502 insertions(+), 11 deletions(-)
diff --git a/hadoop-ozone/common/pom.xml b/hadoop-ozone/common/pom.xml
index d074c36060..e48fe801c9 100644
--- a/hadoop-ozone/common/pom.xml
+++ b/hadoop-ozone/common/pom.xml
@@ -61,6 +61,11 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-inline</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>ch.qos.reload4j</groupId>
<artifactId>reload4j</artifactId>
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/GrpcOmTransport.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/GrpcOmTransport.java
index 74a6422f5c..96f7b48665 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/GrpcOmTransport.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/GrpcOmTransport.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.ozone.om.protocolPB;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.net.InetAddress;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -29,6 +30,7 @@ import java.util.HashMap;
import java.util.Map;
import com.google.common.net.HostAndPort;
+import io.grpc.Context;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import org.apache.hadoop.ipc.RemoteException;
@@ -43,6 +45,8 @@ import org.apache.hadoop.io.retry.RetryPolicy;
import org.apache.hadoop.ozone.OzoneConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
+import
org.apache.hadoop.ozone.om.protocolPB.grpc.ClientAddressClientInterceptor;
+import org.apache.hadoop.ozone.om.protocolPB.grpc.GrpcClientConstants;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
import org.apache.hadoop.security.UserGroupInformation;
@@ -160,7 +164,9 @@ public class GrpcOmTransport implements OmTransport {
channelBuilder.usePlaintext();
}
- channels.put(hostaddr, channelBuilder.build());
+ channels.put(hostaddr,
+ channelBuilder.intercept(new ClientAddressClientInterceptor())
+ .build());
clients.put(hostaddr,
OzoneManagerServiceGrpc
.newBlockingStub(channels.get(hostaddr)));
@@ -175,7 +181,7 @@ public class GrpcOmTransport implements OmTransport {
@Override
public OMResponse submitRequest(OMRequest payload) throws IOException {
- OMResponse resp = null;
+ AtomicReference<OMResponse> resp = new AtomicReference<>();
boolean tryOtherHost = true;
int expectedFailoverCount = 0;
ResultCodes resultCode = ResultCodes.INTERNAL_ERROR;
@@ -183,7 +189,14 @@ public class GrpcOmTransport implements OmTransport {
tryOtherHost = false;
expectedFailoverCount = syncFailoverCount.get();
try {
- resp = clients.get(host.get()).submitRequest(payload);
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ Context.current()
+ .withValue(GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY,
+ inetAddress.getHostAddress())
+ .withValue(GrpcClientConstants.CLIENT_HOSTNAME_CTX_KEY,
+ inetAddress.getHostName())
+ .run(() -> resp.set(clients.get(host.get())
+ .submitRequest(payload)));
} catch (StatusRuntimeException e) {
LOG.error("Failed to submit request", e);
if (e.getStatus().getCode() == Status.Code.UNAVAILABLE) {
@@ -201,7 +214,7 @@ public class GrpcOmTransport implements OmTransport {
}
}
}
- return resp;
+ return resp.get();
}
private Exception unwrapException(Exception ex) {
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressClientInterceptor.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressClientInterceptor.java
new file mode 100644
index 0000000000..5941309727
--- /dev/null
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressClientInterceptor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
+
+import io.grpc.CallOptions;
+import io.grpc.Channel;
+import io.grpc.ClientCall;
+import io.grpc.ClientInterceptor;
+import io.grpc.ForwardingClientCall;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
+
+/**
+ * GRPC client side interceptor to provide client hostname and IP address.
+ */
+public class ClientAddressClientInterceptor implements ClientInterceptor {
+ @Override
+ public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
+ MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions,
+ Channel channel) {
+ return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
+ channel.newCall(methodDescriptor, callOptions)) {
+ @Override
+ public void start(Listener<RespT> responseListener, Metadata headers) {
+ String ipAddress = GrpcClientConstants.CLIENT_HOSTNAME_CTX_KEY.get();
+ if (ipAddress != null) {
+ headers.put(GrpcClientConstants.CLIENT_HOSTNAME_METADATA_KEY,
+ ipAddress);
+ }
+ String hostname = GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY.get();
+ if (GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY.get() != null) {
+ headers.put(GrpcClientConstants.CLIENT_IP_ADDRESS_METADATA_KEY,
+ hostname);
+ }
+ super.start(responseListener, headers);
+ }
+ };
+ }
+}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressServerInterceptor.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressServerInterceptor.java
new file mode 100644
index 0000000000..d1f4f1a4db
--- /dev/null
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/ClientAddressServerInterceptor.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
+
+import io.grpc.Context;
+import io.grpc.Contexts;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+
+/**
+ * GRPC server side interceptor to retrieve the client IP and hostname.
+ */
+public class ClientAddressServerInterceptor implements ServerInterceptor {
+ @Override
+ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
+ ServerCall<ReqT, RespT> call, Metadata headers,
+ ServerCallHandler<ReqT, RespT> next) {
+ String clientHostname =
+ headers.get(GrpcClientConstants.CLIENT_HOSTNAME_METADATA_KEY);
+ String clientIpAddress =
+ headers.get(GrpcClientConstants.CLIENT_IP_ADDRESS_METADATA_KEY);
+
+ Context ctx = Context.current()
+ .withValue(GrpcClientConstants.CLIENT_HOSTNAME_CTX_KEY,
+ clientHostname)
+ .withValue(GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY,
+ clientIpAddress);
+ return Contexts.interceptCall(ctx, call, headers, next);
+ }
+}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/GrpcClientConstants.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/GrpcClientConstants.java
new file mode 100644
index 0000000000..4396108067
--- /dev/null
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/GrpcClientConstants.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
+
+import io.grpc.Context;
+import io.grpc.Metadata;
+
+/**
+ * Constants to store grpc-client specific header values.
+ */
+public final class GrpcClientConstants {
+
+ private GrpcClientConstants() {
+ }
+
+ public static final Context.Key<String> CLIENT_HOSTNAME_CTX_KEY =
+ Context.key("CLIENT_HOSTNAME");
+
+ public static final Metadata.Key<String> CLIENT_HOSTNAME_METADATA_KEY =
+ Metadata.Key.of("CLIENT_HOSTNAME", Metadata.ASCII_STRING_MARSHALLER);
+
+ public static final Context.Key<String> CLIENT_IP_ADDRESS_CTX_KEY =
+ Context.key("CLIENT_IP_ADDRESS");
+
+ public static final Metadata.Key<String> CLIENT_IP_ADDRESS_METADATA_KEY =
+ Metadata.Key.of("CLIENT_IP_ADDRESS", Metadata.ASCII_STRING_MARSHALLER);
+
+}
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/package-info.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/package-info.java
new file mode 100644
index 0000000000..f4d76862a1
--- /dev/null
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/grpc/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package contains grpc interceptors and their related classes.
+ * To provide specific grpc headers
+ */
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressClientInterceptor.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressClientInterceptor.java
new file mode 100644
index 0000000000..f8e95cfa80
--- /dev/null
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressClientInterceptor.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
+
+import io.grpc.CallOptions;
+import io.grpc.Channel;
+import io.grpc.ClientCall;
+import io.grpc.ClientInterceptor;
+import io.grpc.Context;
+import io.grpc.Metadata;
+import io.grpc.MethodDescriptor;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test OM GRPC client interceptor to define client ip and hostname headers.
+ */
+public class TestClientAddressClientInterceptor {
+
+ @Test
+ public void testClientAddressEntriesInRequestHeaders() {
+ try (MockedStatic<Context> grpcContextStaticMock =
+ Mockito.mockStatic(Context.class)) {
+ // given
+ Context.Key<String> ipAddressContextKey = mock(Context.Key.class);
+ when(ipAddressContextKey.get()).thenReturn("172.43.3.2");
+ grpcContextStaticMock.when(() -> Context.key("CLIENT_IP_ADDRESS"))
+ .thenReturn(ipAddressContextKey);
+
+ Context.Key<String> hostnameContextKey = mock(Context.Key.class);
+ when(hostnameContextKey.get()).thenReturn("host.example.com");
+ grpcContextStaticMock.when(() -> Context.key("CLIENT_HOSTNAME"))
+ .thenReturn(hostnameContextKey);
+
+ ClientInterceptor interceptor = new ClientAddressClientInterceptor();
+ Channel channel = mock(Channel.class);
+ MethodDescriptor methodDescriptor = mock(MethodDescriptor.class);
+ CallOptions callOptions = mock(CallOptions.class);
+ ClientCall delegate = mock(ClientCall.class);
+ when(channel.newCall(eq(methodDescriptor), eq(callOptions)))
+ .thenReturn(delegate);
+
+ // when
+ ClientCall clientCall = interceptor.interceptCall(methodDescriptor,
+ callOptions, channel);
+ Metadata metadata = mock(Metadata.class);
+ clientCall.start(mock(ClientCall.Listener.class), metadata);
+
+ // then
+ verify(metadata).put(GrpcClientConstants.CLIENT_HOSTNAME_METADATA_KEY,
+ hostnameContextKey.get());
+ verify(metadata).put(GrpcClientConstants.CLIENT_IP_ADDRESS_METADATA_KEY,
+ ipAddressContextKey.get());
+ }
+ }
+
+}
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressServerInterceptor.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressServerInterceptor.java
new file mode 100644
index 0000000000..d8a838440d
--- /dev/null
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/protocolPB/grpc/TestClientAddressServerInterceptor.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.protocolPB.grpc;
+
+import io.grpc.Context;
+import io.grpc.Contexts;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test OM GRPC server interceptor to define client ip and hostname.
+ */
+public class TestClientAddressServerInterceptor {
+
+ @Test
+ public void testClientAddressEntriesInHeaders() {
+ try (MockedStatic<Contexts> contextsMockedStatic =
+ Mockito.mockStatic(Contexts.class)) {
+ // given
+ ServerInterceptor serverInterceptor =
+ new ClientAddressServerInterceptor();
+ ServerCall serverCall = mock(ServerCall.class);
+ ServerCallHandler serverCallHandler = mock(ServerCallHandler.class);
+ Metadata headers = mock(Metadata.class);
+ when(headers.get(GrpcClientConstants.CLIENT_HOSTNAME_METADATA_KEY))
+ .thenReturn("host.example.com");
+ when(headers.get(GrpcClientConstants.CLIENT_IP_ADDRESS_METADATA_KEY))
+ .thenReturn("173.56.23.4");
+
+ // when
+ serverInterceptor.interceptCall(serverCall, headers, serverCallHandler);
+
+ // then
+ ArgumentCaptor<Context> contextArgumentCaptor =
+ ArgumentCaptor.forClass(Context.class);
+ contextsMockedStatic.verify(
+ () -> {
+ Contexts.interceptCall(contextArgumentCaptor.capture(),
+ eq(serverCall), eq(headers), eq(serverCallHandler));
+ }
+ );
+ Context context = contextArgumentCaptor.getValue();
+ context.attach();
+ Assertions.assertEquals("host.example.com",
+ GrpcClientConstants.CLIENT_HOSTNAME_CTX_KEY.get());
+ Assertions.assertEquals("173.56.23.4",
+ GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY.get());
+ }
+ }
+
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/GrpcOzoneManagerServer.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/GrpcOzoneManagerServer.java
index 7753f94a07..80085db7c6 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/GrpcOzoneManagerServer.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/GrpcOzoneManagerServer.java
@@ -35,6 +35,7 @@ import
org.apache.hadoop.ozone.grpc.metrics.GrpcMetricsServerResponseInterceptor
import org.apache.hadoop.ozone.grpc.metrics.GrpcMetricsServerTransportFilter;
import org.apache.hadoop.ozone.ha.ConfUtils;
import org.apache.hadoop.ozone.grpc.metrics.GrpcMetrics;
+import
org.apache.hadoop.ozone.om.protocolPB.grpc.ClientAddressServerInterceptor;
import
org.apache.hadoop.ozone.protocolPB.OzoneManagerProtocolServerSideTranslatorPB;
import org.apache.hadoop.ozone.om.protocolPB.GrpcOmTransport;
import org.apache.hadoop.ozone.security.OzoneDelegationTokenSecretManager;
@@ -153,6 +154,7 @@ public class GrpcOzoneManagerServer {
new OzoneManagerServiceGrpc(omTranslator,
delegationTokenMgr,
omServerConfig),
+ new ClientAddressServerInterceptor(),
new GrpcMetricsServerResponseInterceptor(omS3gGrpcMetrics),
new GrpcMetricsServerRequestInterceptor(omS3gGrpcMetrics)))
.addTransportFilter(
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
index 5d324cae62..6b390ccbba 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
@@ -39,6 +39,7 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatusLight;
import org.apache.hadoop.ozone.om.helpers.S3VolumeContext;
+import org.apache.hadoop.ozone.om.protocolPB.grpc.GrpcClientConstants;
import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
import org.apache.hadoop.ozone.security.acl.RequestContext;
import org.apache.hadoop.security.UserGroupInformation;
@@ -565,7 +566,13 @@ public class OmMetadataReader implements
IOmMetadataReader, Auditor {
static String getClientAddress() {
String clientMachine = Server.getRemoteAddress();
if (clientMachine == null) { //not a RPC client
- clientMachine = "";
+ String clientIpAddress =
+ GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY.get();
+ if (clientIpAddress != null) {
+ clientMachine = clientIpAddress;
+ } else {
+ clientMachine = "";
+ }
}
return clientMachine;
}
@@ -576,7 +583,7 @@ public class OmMetadataReader implements IOmMetadataReader,
Auditor {
return new AuditMessage.Builder()
.setUser(getRemoteUserName())
- .atIp(Server.getRemoteAddress())
+ .atIp(getClientAddress())
.forOperation(op)
.withParams(auditMap)
.withResult(AuditEventStatus.SUCCESS)
@@ -589,7 +596,7 @@ public class OmMetadataReader implements IOmMetadataReader,
Auditor {
return new AuditMessage.Builder()
.setUser(getRemoteUserName())
- .atIp(Server.getRemoteAddress())
+ .atIp(getClientAddress())
.forOperation(op)
.withParams(auditMap)
.withResult(AuditEventStatus.FAILURE)
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
index 48c68cb5aa..642faefa05 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
@@ -35,6 +35,7 @@ import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.OzonePrefixPathImpl;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.protocolPB.grpc.GrpcClientConstants;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
@@ -165,9 +166,17 @@ public abstract class OMClientRequest implements
RequestAuditor {
userInfo.setUserName(omRequest.getUserInfo().getUserName());
}
+ String grpcContextClientIpAddress =
+ GrpcClientConstants.CLIENT_IP_ADDRESS_CTX_KEY.get();
+ String grpcContextClientHostname =
+ GrpcClientConstants.CLIENT_HOSTNAME_CTX_KEY.get();
if (remoteAddress != null) {
userInfo.setHostName(remoteAddress.getHostName());
userInfo.setRemoteAddress(remoteAddress.getHostAddress()).build();
+ } else if (grpcContextClientHostname != null
+ && grpcContextClientIpAddress != null) {
+ userInfo.setHostName(grpcContextClientHostname);
+ userInfo.setRemoteAddress(grpcContextClientIpAddress);
}
return userInfo.build();
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
new file mode 100644
index 0000000000..e4e3d544a8
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+
+package org.apache.hadoop.ozone.om;
+
+import io.grpc.Context;
+import org.apache.hadoop.ipc.Server;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test ozone metadata reader.
+ */
+public class TestOMMetadataReader {
+
+ @Test
+ public void testGetClientAddress() {
+ try (
+ MockedStatic<Server> ipcServerStaticMock =
+ Mockito.mockStatic(Server.class);
+ MockedStatic<Context> grpcRequestContextStaticMock =
+ Mockito.mockStatic(Context.class);
+ ) {
+ // given
+ String expectedClientAddressInCaseOfHadoopRpcCall =
+ "hadoop.ipc.client.com";
+ ipcServerStaticMock.when(Server::getRemoteAddress)
+ .thenReturn(null, null, expectedClientAddressInCaseOfHadoopRpcCall);
+
+ String expectedClientAddressInCaseOfGrpcCall = "172.45.23.4";
+ Context.Key<String> clientIpAddressKey = mock(Context.Key.class);
+ when(clientIpAddressKey.get())
+ .thenReturn(expectedClientAddressInCaseOfGrpcCall, null);
+
+ grpcRequestContextStaticMock.when(() -> Context.key("CLIENT_IP_ADDRESS"))
+ .thenReturn(clientIpAddressKey);
+
+ // when (GRPC call with defined client address)
+ String clientAddress = OmMetadataReader.getClientAddress();
+ // then
+ assertEquals(expectedClientAddressInCaseOfGrpcCall, clientAddress);
+
+ // and when (GRPC call without client address)
+ clientAddress = OmMetadataReader.getClientAddress();
+ // then
+ assertEquals("", clientAddress);
+
+ // and when (Hadoop RPC client call)
+ clientAddress = OmMetadataReader.getClientAddress();
+ // then
+ assertEquals(expectedClientAddressInCaseOfHadoopRpcCall, clientAddress);
+ }
+ }
+
+}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
index 3e3433fab4..45209258f7 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
@@ -1605,4 +1605,20 @@ public final class OMRequestTestUtils {
.thenReturn(validator);
doCallRealMethod().when(ozoneManager).validateReplicationConfig(any());
}
+
+ public static OMRequest createRequestWithS3Credentials(String accessId,
+ String signature,
+ String stringToSign) {
+ return OMRequest.newBuilder()
+ .setS3Authentication(
+ OzoneManagerProtocolProtos.S3Authentication.newBuilder()
+ .setAccessId(accessId)
+ .setSignature(signature)
+ .setStringToSign(stringToSign)
+ .build())
+ .setCmdType(Type.CommitKey)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
index cb68a8b939..299a8d5652 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
@@ -19,18 +19,23 @@
package org.apache.hadoop.ozone.om.request;
+import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Path;
import java.util.UUID;
+import io.grpc.Context;
import mockit.Mock;
import mockit.MockUp;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketInfo;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -44,8 +49,10 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
import org.apache.hadoop.ozone.om.request.bucket.OMBucketCreateRequest;
import org.apache.hadoop.security.UserGroupInformation;
+import static
org.apache.hadoop.ozone.om.request.OMRequestTestUtils.createRequestWithS3Credentials;
import static
org.apache.hadoop.ozone.om.request.OMRequestTestUtils.newBucketInfoBuilder;
import static
org.apache.hadoop.ozone.om.request.OMRequestTestUtils.newCreateBucketRequest;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
@@ -75,7 +82,10 @@ public class TestOMClientRequestWithUserInfo {
when(ozoneManager.getMetrics()).thenReturn(omMetrics);
when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
inetAddress = InetAddress.getByName("127.0.0.1");
+ }
+ @Test
+ public void testUserInfoInCaseOfHadoopTransport() throws Exception {
new MockUp<ProtobufRpcEngine.Server>() {
@Mock
public UserGroupInformation getRemoteUser() {
@@ -91,10 +101,6 @@ public class TestOMClientRequestWithUserInfo {
return inetAddress;
}
};
- }
-
- @Test
- public void testUserInfo() throws Exception {
String bucketName = UUID.randomUUID().toString();
String volumeName = UUID.randomUUID().toString();
@@ -131,4 +137,37 @@ public class TestOMClientRequestWithUserInfo {
ugi.getUserName());
Assertions.assertEquals(inetAddress.getHostName(), hostName);
}
+
+ @Test
+ public void testUserInfoInCaseOfGrpcTransport() throws IOException {
+ try (MockedStatic<Context> mockedGrpcRequestContextKey =
+ Mockito.mockStatic(Context.class)) {
+ // given
+ Context.Key<String> hostnameKey = mock(Context.Key.class);
+ when(hostnameKey.get()).thenReturn("hostname");
+
+ Context.Key<String> ipAddress = mock(Context.Key.class);
+ when(ipAddress.get()).thenReturn("172.5.3.5");
+
+ mockedGrpcRequestContextKey.when(() -> Context.key("CLIENT_HOSTNAME"))
+ .thenReturn(hostnameKey);
+ mockedGrpcRequestContextKey.when(() -> Context.key("CLIENT_IP_ADDRESS"))
+ .thenReturn(ipAddress);
+
+ OMRequest s3SignedOMRequest = createRequestWithS3Credentials("AccessId",
+ "Signature", "StringToSign");
+ OMClientRequest omClientRequest =
+ new OMKeyCommitRequest(s3SignedOMRequest, mock(BucketLayout.class));
+
+ // when
+ OzoneManagerProtocolProtos.UserInfo userInfo =
+ omClientRequest.getUserInfo();
+
+ // then
+ Assertions.assertEquals("hostname", userInfo.getHostName());
+ Assertions.assertEquals("172.5.3.5", userInfo.getRemoteAddress());
+ Assertions.assertEquals("AccessId", userInfo.getUserName());
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]