HDDS-4985. [SCM HA Security] When Ratis enable, SCM secure cluster is not working. (#2052)
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAInvocationHandler.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAInvocationHandler.java
index 6dc0f15..62951d5 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAInvocationHandler.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAInvocationHandler.java
@@ -90,7 +90,8 @@
long startTime = Time.monotonicNowNanos();
Preconditions.checkNotNull(ratisHandler);
final SCMRatisResponse response = ratisHandler.submitRequest(
- SCMRatisRequest.of(requestType, method.getName(), args));
+ SCMRatisRequest.of(requestType, method.getName(),
+ method.getParameterTypes(), args));
LOG.info("Invoking method {} on target {}, cost {}us",
method, ratisHandler, (Time.monotonicNowNanos() - startTime) / 1000.0);
if (response.isSuccess()) {
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMRatisRequest.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMRatisRequest.java
index 4277bb0..da8fadf 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMRatisRequest.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMRatisRequest.java
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.List;
+import com.google.common.base.Preconditions;
import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.hadoop.hdds.scm.ha.io.CodecFactory;
@@ -39,18 +40,22 @@
private final RequestType type;
private final String operation;
private final Object[] arguments;
+ private final Class<?>[] parameterTypes;
private SCMRatisRequest(final RequestType type, final String operation,
- final Object... arguments) {
+ final Class<?>[] parameterTypes, final Object... arguments) {
this.type = type;
this.operation = operation;
+ this.parameterTypes = parameterTypes;
this.arguments = arguments;
}
public static SCMRatisRequest of(final RequestType type,
- final String operation,
- final Object... arguments) {
- return new SCMRatisRequest(type, operation, arguments);
+ final String operation,
+ final Class<?>[] parameterTypes,
+ final Object... arguments) {
+ Preconditions.checkState(parameterTypes.length == arguments.length);
+ return new SCMRatisRequest(type, operation, parameterTypes, arguments);
}
/**
@@ -74,6 +79,9 @@
return arguments.clone();
}
+ public Class<?>[] getParameterTypes() {
+ return parameterTypes.clone();
+ }
/**
* Encodes the request into Ratis Message.
*/
@@ -86,9 +94,14 @@
methodBuilder.setName(operation);
final List<MethodArgument> args = new ArrayList<>();
+
+ int paramCounter = 0;
for (Object argument : arguments) {
final MethodArgument.Builder argBuilder = MethodArgument.newBuilder();
- argBuilder.setType(argument.getClass().getName());
+ // Set actual method parameter type, not actual argument type.
+ // This is done to avoid MethodNotFoundException in case if argument is
+ // subclass type, where as method is defined with super class type.
+ argBuilder.setType(parameterTypes[paramCounter++].getName());
argBuilder.setValue(CodecFactory.getCodec(argument.getClass())
.serialize(argument));
args.add(argBuilder.build());
@@ -109,9 +122,12 @@
SCMRatisRequestProto.parseFrom(message.getContent().toByteArray());
final Method method = requestProto.getMethod();
List<Object> args = new ArrayList<>();
+ Class<?>[] parameterTypes = new Class[method.getArgsCount()];
+ int paramCounter = 0;
for (MethodArgument argument : method.getArgsList()) {
try {
final Class<?> clazz = ReflectionUtil.getClass(argument.getType());
+ parameterTypes[paramCounter++] = clazz;
args.add(CodecFactory.getCodec(clazz)
.deserialize(clazz, argument.getValue()));
} catch (ClassNotFoundException ex) {
@@ -120,7 +136,7 @@
}
}
return new SCMRatisRequest(requestProto.getType(),
- method.getName(), args.toArray());
+ method.getName(), parameterTypes, args.toArray());
}
}
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMStateMachine.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMStateMachine.java
index a1047b4..90ace48 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMStateMachine.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMStateMachine.java
@@ -19,9 +19,7 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
import java.util.EnumMap;
-import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
@@ -152,12 +150,8 @@
request.getType());
}
- final List<Class<?>> argumentTypes = new ArrayList<>();
- for(Object args : request.getArguments()) {
- argumentTypes.add(args.getClass());
- }
final Object result = handler.getClass().getMethod(
- request.getOperation(), argumentTypes.toArray(new Class<?>[0]))
+ request.getOperation(), request.getParameterTypes())
.invoke(handler, request.getArguments());
return SCMRatisResponse.encode(result);
} catch (NoSuchMethodException | SecurityException ex) {
diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/TestSCMRatisRequest.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/TestSCMRatisRequest.java
index 5295e0f..f5913aa 100644
--- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/TestSCMRatisRequest.java
+++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/ha/TestSCMRatisRequest.java
@@ -40,7 +40,8 @@
PipelineID pipelineID = PipelineID.randomId();
Object[] args = new Object[] {pipelineID.getProtobuf()};
String operation = "test";
- SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation, args);
+ SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation,
+ new Class[]{pipelineID.getProtobuf().getClass()}, args);
Assert.assertEquals(operation,
SCMRatisRequest.decode(request.encode()).getOperation());
Assert.assertEquals(args[0],
@@ -52,7 +53,8 @@
PipelineID pipelineID = PipelineID.randomId();
// Non proto args
Object[] args = new Object[] {pipelineID};
- SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, "test", args);
+ SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, "test",
+ new Class[]{pipelineID.getClass()}, args);
// Should throw exception there.
request.encode();
}
@@ -73,7 +75,8 @@
pids.add(PipelineID.randomId().getProtobuf());
Object[] args = new Object[] {pids};
String operation = "test";
- SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation, args);
+ SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation,
+ new Class[]{pids.getClass()}, args);
Assert.assertEquals(operation,
SCMRatisRequest.decode(request.encode()).getOperation());
Assert.assertEquals(args[0],
@@ -84,7 +87,8 @@
public void testEncodeAndDecodeOfLong() throws Exception {
final Long value = 10L;
String operation = "test";
- SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation, value);
+ SCMRatisRequest request = SCMRatisRequest.of(PIPELINE, operation,
+ new Class[]{value.getClass()}, value);
Assert.assertEquals(operation,
SCMRatisRequest.decode(request.encode()).getOperation());
Assert.assertEquals(value,
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
index 31011fa..a4c8e80d 100644
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
@@ -104,5 +104,6 @@
KERBEROS_KEYTABS: scm HTTP testuser testuser2
ENSURE_SCM_INITIALIZED: /data/metadata/scm/current/VERSION
OZONE-SITE.XML_hdds.scm.safemode.min.datanode: "${OZONE_SAFEMODE_MIN_DATANODES:-1}"
+ OZONE-SITE.XML_ozone.scm.ratis.enable: "${OZONE_SCM_RATIS_ENABLE:-false}"
OZONE_OPTS:
command: ["/opt/hadoop/bin/ozone","scm"]
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure/test.sh b/hadoop-ozone/dist/src/main/compose/ozonesecure/test.sh
index 9150b24..c482396 100755
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure/test.sh
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure/test.sh
@@ -27,39 +27,42 @@
: ${OZONE_BUCKET_KEY_NAME:=key1}
-start_docker_env
+for enable in true false; do
-execute_command_in_container kms hadoop key create ${OZONE_BUCKET_KEY_NAME}
+ start_docker_env 3 "${enable}"
-execute_robot_test scm kinit.robot
+ execute_command_in_container kms hadoop key create ${OZONE_BUCKET_KEY_NAME}
-execute_robot_test scm basic
+ execute_robot_test scm kinit.robot
-execute_robot_test scm security
+ execute_robot_test scm basic
-for scheme in ofs o3fs; do
- for bucket in link bucket; do
- execute_robot_test scm -v SCHEME:${scheme} -v BUCKET_TYPE:${bucket} -N ozonefs-${scheme}-${bucket} ozonefs/ozonefs.robot
+ execute_robot_test scm security
+
+ for scheme in ofs o3fs; do
+ for bucket in link bucket; do
+ execute_robot_test scm -v SCHEME:${scheme} -v BUCKET_TYPE:${bucket} -N ozonefs-${scheme}-${bucket} ozonefs/ozonefs.robot
+ done
done
-done
-for bucket in link generated; do
- execute_robot_test s3g -v BUCKET:${bucket} -N s3-${bucket} s3
-done
+ for bucket in link generated; do
+ execute_robot_test s3g -v BUCKET:${bucket} -N s3-${bucket} s3
+ done
-#expects 4 pipelines, should be run before
-#admincli which creates STANDALONE pipeline
-execute_robot_test scm recon
+ #expects 4 pipelines, should be run before
+ #admincli which creates STANDALONE pipeline
+ execute_robot_test scm recon
-execute_robot_test scm admincli
-execute_robot_test scm spnego
+ execute_robot_test scm admincli
+ execute_robot_test scm spnego
-# test replication
-docker-compose up -d --scale datanode=2
-execute_robot_test scm -v container:1 -v count:2 replication/wait.robot
-docker-compose up -d --scale datanode=3
-execute_robot_test scm -v container:1 -v count:3 replication/wait.robot
+ # test replication
+ docker-compose up -d --scale datanode=2
+ execute_robot_test scm -v container:1 -v count:2 replication/wait.robot
+ docker-compose up -d --scale datanode=3
+ execute_robot_test scm -v container:1 -v count:3 replication/wait.robot
-stop_docker_env
+ stop_docker_env
-generate_report
+ generate_report
+done
\ No newline at end of file
diff --git a/hadoop-ozone/dist/src/main/compose/testlib.sh b/hadoop-ozone/dist/src/main/compose/testlib.sh
index acc9fb3..1a13219 100755
--- a/hadoop-ozone/dist/src/main/compose/testlib.sh
+++ b/hadoop-ozone/dist/src/main/compose/testlib.sh
@@ -138,6 +138,8 @@
create_results_dir
export OZONE_SAFEMODE_MIN_DATANODES="${datanode_count}"
+
+ export OZONE_SCM_RATIS_ENABLE=${2:-false}
docker-compose --no-ansi down
if ! { docker-compose --no-ansi up -d --scale datanode="${datanode_count}" \
&& wait_for_safemode_exit \