diff --git a/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RequestFeatureValidatorProcessor.java b/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/OmRequestFeatureValidatorProcessor.java similarity index 88% rename from hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RequestFeatureValidatorProcessor.java rename to hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/OmRequestFeatureValidatorProcessor.java index 830706e9a540..0c93caba7e6b 100644 --- a/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RequestFeatureValidatorProcessor.java +++ b/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/OmRequestFeatureValidatorProcessor.java @@ -34,6 +34,7 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleAnnotationValueVisitor8; import javax.tools.Diagnostic; +import java.util.Arrays; import java.util.List; import java.util.Map.Entry; import java.util.Set; @@ -50,14 +51,11 @@ * META-INF/services/javax.annotation.processing.Processor file in the module's * resources folder. */ -@SupportedAnnotationTypes( - "org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator") +@SupportedAnnotationTypes({ + "org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator", + "org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) -public class RequestFeatureValidatorProcessor extends AbstractProcessor { - - public static final String ERROR_CONDITION_IS_EMPTY = - "RequestFeatureValidator has an empty condition list. Please define the" - + " ValidationCondition in which the validator has to be applied."; +public class OmRequestFeatureValidatorProcessor extends AbstractProcessor { public static final String ERROR_ANNOTATED_ELEMENT_IS_NOT_A_METHOD = "RequestFeatureValidator annotation is not applied to a method."; public static final String ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC = @@ -90,8 +88,8 @@ public class RequestFeatureValidatorProcessor extends AbstractProcessor { public static final String VALIDATION_CONTEXT_CLASS_NAME = "org.apache.hadoop.ozone.om.request.validation.ValidationContext"; - public static final String ANNOTATION_SIMPLE_NAME = "RequestFeatureValidator"; - public static final String ANNOTATION_CONDITIONS_PROPERTY_NAME = "conditions"; + private static final List ANNOTATION_SIMPLE_NAMES = Arrays.asList("OMClientVersionValidator", + "OMLayoutVersionValidator"); public static final String ANNOTATION_PROCESSING_PHASE_PROPERTY_NAME = "processingPhase"; @@ -104,7 +102,7 @@ public class RequestFeatureValidatorProcessor extends AbstractProcessor { public boolean process(Set annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { - if (!annotation.getSimpleName().contentEquals(ANNOTATION_SIMPLE_NAME)) { + if (!ANNOTATION_SIMPLE_NAMES.contains(annotation.getSimpleName().toString())) { continue; } processElements(roundEnv.getElementsAnnotatedWith(annotation)); @@ -172,7 +170,7 @@ private void ensurePostProcessorReturnsOMResponse( ExecutableElement elem, boolean isPreprocessor) { if (!isPreprocessor && !elem.getReturnType().toString() .equals(OM_RESPONSE_CLASS_NAME)) { - emitErrorMsg(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE); + emitErrorMsg(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE + " " + elem.getSimpleName()); } } @@ -201,10 +199,6 @@ private boolean checkAndEvaluateAnnotation( boolean isPreprocessor = false; for (Entry entry : methodAnnotation.getElementValues().entrySet()) { - - if (hasInvalidValidationCondition(entry)) { - emitErrorMsg(ERROR_CONDITION_IS_EMPTY); - } if (isProcessingPhaseValue(entry)) { isPreprocessor = evaluateProcessingPhase(entry); } @@ -228,11 +222,6 @@ private boolean isProcessingPhaseValue( return isPropertyNamedAs(entry, ANNOTATION_PROCESSING_PHASE_PROPERTY_NAME); } - private boolean hasInvalidValidationCondition( - Entry entry) { - return isPropertyNamedAs(entry, ANNOTATION_CONDITIONS_PROPERTY_NAME) - && !visit(entry, new ConditionValidator()); - } private boolean isPropertyNamedAs( Entry entry, @@ -246,24 +235,6 @@ private T visit( return entry.getValue().accept(visitor, null); } - private static class ConditionValidator - extends SimpleAnnotationValueVisitor8 { - - ConditionValidator() { - super(Boolean.TRUE); - } - - @Override - public Boolean visitArray(List vals, - Void unused) { - if (vals.isEmpty()) { - return Boolean.FALSE; - } - return Boolean.TRUE; - } - - } - private static class ProcessingPhaseVisitor extends SimpleAnnotationValueVisitor8 { diff --git a/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RegisterValidatorProcessor.java b/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RegisterValidatorProcessor.java new file mode 100644 index 000000000000..8089c330e4a1 --- /dev/null +++ b/hadoop-hdds/annotations/src/main/java/org/apache/ozone/annotations/RegisterValidatorProcessor.java @@ -0,0 +1,142 @@ +/* + * 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.ozone.annotations; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; +import java.util.Set; + +/** + * This class is an annotation processor that is hooked into the java compiler + * and is used to validate the RegisterValidator annotations in the + * codebase, to ensure that the annotated classes have the proper methods returning appropriate object types. + * + * The module is compiled in a different execution via Maven before anything + * else is compiled, and then javac picks this class up as an annotation + * processor from the classpath via a ServiceLoader, based on the + * META-INF/services/javax.annotation.processing.Processor file in the module's + * resources folder. + */ +@SupportedAnnotationTypes("org.apache.hadoop.ozone.request.validation.RegisterValidator") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class RegisterValidatorProcessor extends AbstractProcessor { + + public static final String ANNOTATION_SIMPLE_NAME = "RegisterValidator"; + public static final String VERSION_CLASS_NAME = "org.apache.hadoop.ozone.Version"; + public static final String REQUEST_PROCESSING_PHASE_CLASS_NAME = "org.apache.hadoop.ozone.om.request.validation" + + ".RequestProcessingPhase"; + public static final String APPLY_BEFORE_METHOD_NAME = "applyBefore"; + public static final String REQUEST_TYPE_METHOD_NAME = "requestType"; + public static final String PROCESSING_PHASE_METHOD_NAME = "processingPhase"; + + public static final String MAX_VERSION_NOT_FOUND_ERROR_MESSAGE = "Method " + APPLY_BEFORE_METHOD_NAME + + " returning an enum implementing " + VERSION_CLASS_NAME + " not found"; + public static final String REQUEST_TYPE_NOT_FOUND_ERROR_MESSAGE = "Method " + REQUEST_TYPE_METHOD_NAME + + " returning an enum not found"; + public static final String PROCESSING_PHASE_NOT_FOUND_ERROR_MESSAGE = "Method " + PROCESSING_PHASE_METHOD_NAME + + " returning an enum implementing " + REQUEST_PROCESSING_PHASE_CLASS_NAME + " not found"; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement annotation : annotations) { + if (!annotation.getSimpleName().contentEquals(ANNOTATION_SIMPLE_NAME)) { + continue; + } + processElements(roundEnv.getElementsAnnotatedWith(annotation)); + } + return false; + } + + private boolean validateArrayMethod(ExecutableElement method, String expectedMethodName, + ElementKind expectedReturnType, + String expectedReturnClass) { + Elements elementUtils = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + TypeElement expectedReturnInterface = expectedReturnClass == null || expectedReturnClass.equals("") ? null : + elementUtils.getTypeElement(expectedReturnClass); + return method.getSimpleName().toString().equals(expectedMethodName) && (expectedReturnType == null || + TypeKind.ARRAY.equals(method.getReturnType().getKind()) && + types.asElement(((ArrayType)method.getReturnType()).getComponentType()).getKind() == expectedReturnType) && + (expectedReturnInterface == null || + types.isAssignable(types.asElement(method.getReturnType()).asType(), expectedReturnInterface.asType())); + } + + private boolean validateMethod(ExecutableElement method, String expectedMethodName, ElementKind expectedReturnType, + String expectedReturnClass) { + Elements elementUtils = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + TypeElement expectedReturnInterface = expectedReturnClass == null || expectedReturnClass.equals("") ? null : + elementUtils.getTypeElement(expectedReturnClass); + return method.getSimpleName().toString().equals(expectedMethodName) && (expectedReturnType == null || + types.asElement(method.getReturnType()) != null && + types.asElement(method.getReturnType()).getKind() == expectedReturnType) && + (expectedReturnInterface == null || + types.isAssignable(types.asElement(method.getReturnType()).asType(), expectedReturnInterface.asType())); + } + + private void processElements(Set annotatedElements) { + for (Element element : annotatedElements) { + if (element.getKind().equals(ElementKind.ANNOTATION_TYPE)) { + boolean hasApplyBeforeMethod = false; + boolean hasRequestType = false; + boolean hasRequestProcessPhase = false; + for (Element enclosedElement : element.getEnclosedElements()) { + // Check if the annotation has a method called "validatorName" returning a String + if (enclosedElement instanceof ExecutableElement) { + ExecutableElement method = (ExecutableElement) enclosedElement; + hasApplyBeforeMethod = hasApplyBeforeMethod || validateMethod(method, APPLY_BEFORE_METHOD_NAME, + ElementKind.ENUM, VERSION_CLASS_NAME); + hasRequestType = hasRequestType || validateArrayMethod(method, REQUEST_TYPE_METHOD_NAME, ElementKind.ENUM, + null); + hasRequestProcessPhase = hasRequestProcessPhase || validateMethod(method, PROCESSING_PHASE_METHOD_NAME, + ElementKind.ENUM, REQUEST_PROCESSING_PHASE_CLASS_NAME); + } + } + if (!hasApplyBeforeMethod) { + emitErrorMsg(MAX_VERSION_NOT_FOUND_ERROR_MESSAGE + " for " + + element.getSimpleName().toString()); + } + if (!hasRequestType) { + emitErrorMsg(REQUEST_TYPE_NOT_FOUND_ERROR_MESSAGE + " for " + + element.getSimpleName().toString()); + } + if (!hasRequestProcessPhase) { + emitErrorMsg(PROCESSING_PHASE_NOT_FOUND_ERROR_MESSAGE + " for " + + element.getSimpleName().toString()); + } + } + } + } + + + private void emitErrorMsg(String s) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, s); + } +} diff --git a/hadoop-hdds/client/pom.xml b/hadoop-hdds/client/pom.xml index 333b960fc243..6534db5a1876 100644 --- a/hadoop-hdds/client/pom.xml +++ b/hadoop-hdds/client/pom.xml @@ -154,7 +154,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-hdds/common/pom.xml b/hadoop-hdds/common/pom.xml index f2576f7cf08b..b26bd4cdd15a 100644 --- a/hadoop-hdds/common/pom.xml +++ b/hadoop-hdds/common/pom.xml @@ -336,7 +336,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersion.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersion.java index 08e293563435..c5627ec30d89 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersion.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersion.java @@ -43,6 +43,10 @@ public enum ClientVersion implements ComponentVersion { "This client version has support for Object Store and File " + "System Optimized Bucket Layouts."), + EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST(4, + "This client version enforces replica index is set for fixing read corruption that could occur when " + + "replicaIndex parameter is not validated before EC block reads."), + FUTURE_VERSION(-1, "Used internally when the server side is older and an" + " unknown client version has arrived from the client."); diff --git a/hadoop-hdds/container-service/pom.xml b/hadoop-hdds/container-service/pom.xml index c21ca8203b56..c501bd5ca423 100644 --- a/hadoop-hdds/container-service/pom.xml +++ b/hadoop-hdds/container-service/pom.xml @@ -266,7 +266,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java index 06a4543bd794..d20fda555b60 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java @@ -122,6 +122,7 @@ import static org.apache.hadoop.hdds.scm.protocolPB.ContainerCommandResponseBuilders.putBlockResponseSuccess; import static org.apache.hadoop.hdds.scm.protocolPB.ContainerCommandResponseBuilders.unsupportedRequest; import static org.apache.hadoop.hdds.scm.utils.ClientCommandsUtils.getReadChunkVersion; +import static org.apache.hadoop.ozone.ClientVersion.EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST; import static org.apache.hadoop.ozone.OzoneConsts.INCREMENTAL_CHUNK_LIST; import static org.apache.hadoop.ozone.container.common.interfaces.Container.ScanResult; @@ -665,6 +666,15 @@ ContainerCommandResponseProto handleEcho( return getEchoResponse(request); } + /** + * Checks if a replicaIndex needs to be checked based on the client version for a request. + * @param request ContainerCommandRequest object. + * @return true if the validation is required for the client version else false. + */ + private boolean replicaIndexCheckRequired(ContainerCommandRequestProto request) { + return request.hasVersion() && request.getVersion() >= EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST.toProtoValue(); + } + /** * Handle Get Block operation. Calls BlockManager to process the request. */ @@ -683,7 +693,9 @@ ContainerCommandResponseProto handleGetBlock( try { BlockID blockID = BlockID.getFromProtobuf( request.getGetBlock().getBlockID()); - BlockUtils.verifyReplicaIdx(kvContainer, blockID); + if (replicaIndexCheckRequired(request)) { + BlockUtils.verifyReplicaIdx(kvContainer, blockID); + } responseData = blockManager.getBlock(kvContainer, blockID).getProtoBufMessage(); final long numBytes = responseData.getSerializedSize(); metrics.incContainerBytesStats(Type.GetBlock, numBytes); @@ -806,7 +818,9 @@ ContainerCommandResponseProto handleReadChunk( ChunkInfo chunkInfo = ChunkInfo.getFromProtoBuf(request.getReadChunk() .getChunkData()); Preconditions.checkNotNull(chunkInfo); - BlockUtils.verifyReplicaIdx(kvContainer, blockID); + if (replicaIndexCheckRequired(request)) { + BlockUtils.verifyReplicaIdx(kvContainer, blockID); + } BlockUtils.verifyBCSId(kvContainer, blockID); if (dispatcherContext == null) { diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/BlockUtils.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/BlockUtils.java index 8bbc2478004d..945efbcf6ea9 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/BlockUtils.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/BlockUtils.java @@ -247,9 +247,7 @@ public static void verifyBCSId(Container container, BlockID blockID) public static void verifyReplicaIdx(Container container, BlockID blockID) throws IOException { Integer containerReplicaIndex = container.getContainerData().getReplicaIndex(); - Integer blockReplicaIndex = blockID.getReplicaIndex(); - if (containerReplicaIndex > 0 && blockReplicaIndex != null && blockReplicaIndex != 0 && - !containerReplicaIndex.equals(blockReplicaIndex)) { + if (containerReplicaIndex > 0 && !containerReplicaIndex.equals(blockID.getReplicaIndex())) { throw new StorageContainerException( "Unable to find the Container with replicaIdx " + blockID.getReplicaIndex() + ". Container " + container.getContainerData().getContainerID() + " replicaIdx is " diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandlerWithUnhealthyContainer.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandlerWithUnhealthyContainer.java index 395e943c7684..1db2d7ff53eb 100644 --- a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandlerWithUnhealthyContainer.java +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandlerWithUnhealthyContainer.java @@ -124,7 +124,8 @@ public void testGetBlockWithReplicaIndexMismatch(ClientVersion clientVersion, in handler.handleGetBlock( getDummyCommandRequestProto(clientVersion, ContainerProtos.Type.GetBlock, rid), container); - assertEquals((replicaIndex > 0 && rid != 0 && rid != replicaIndex) ? + assertEquals((replicaIndex > 0 && rid != replicaIndex && clientVersion.toProtoValue() >= + ClientVersion.EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST.toProtoValue()) ? ContainerProtos.Result.CONTAINER_NOT_FOUND : UNKNOWN_BCSID, response.getResult()); } @@ -166,7 +167,8 @@ public void testReadChunkWithReplicaIndexMismatch(ClientVersion clientVersion, i ContainerProtos.ContainerCommandResponseProto response = handler.handleReadChunk(getDummyCommandRequestProto(clientVersion, ContainerProtos.Type.ReadChunk, rid), container, null); - assertEquals((replicaIndex > 0 && rid != 0 && rid != replicaIndex) ? + assertEquals((replicaIndex > 0 && rid != replicaIndex && + clientVersion.toProtoValue() >= ClientVersion.EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST.toProtoValue()) ? ContainerProtos.Result.CONTAINER_NOT_FOUND : UNKNOWN_BCSID, response.getResult()); } diff --git a/hadoop-hdds/framework/pom.xml b/hadoop-hdds/framework/pom.xml index 37d41cde390a..766212c181b8 100644 --- a/hadoop-hdds/framework/pom.xml +++ b/hadoop-hdds/framework/pom.xml @@ -353,7 +353,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.kohsuke.MetaInfServices diff --git a/hadoop-hdds/server-scm/pom.xml b/hadoop-hdds/server-scm/pom.xml index 4c2e40c37592..aa374c0a5ab4 100644 --- a/hadoop-hdds/server-scm/pom.xml +++ b/hadoop-hdds/server-scm/pom.xml @@ -265,7 +265,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.kohsuke.MetaInfServices diff --git a/hadoop-hdds/tools/pom.xml b/hadoop-hdds/tools/pom.xml index 5b77f394c96f..f92936d1689f 100644 --- a/hadoop-hdds/tools/pom.xml +++ b/hadoop-hdds/tools/pom.xml @@ -210,7 +210,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> org.apache.hadoop.hdds.conf.Config org.apache.hadoop.hdds.conf.ConfigGroup org.apache.hadoop.hdds.scm.metadata.Replicate - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator diff --git a/hadoop-ozone/client/pom.xml b/hadoop-ozone/client/pom.xml index 6b5a1ac0c8b7..4a8f47e990f7 100644 --- a/hadoop-ozone/client/pom.xml +++ b/hadoop-ozone/client/pom.xml @@ -160,7 +160,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/common/pom.xml b/hadoop-ozone/common/pom.xml index f7f60dcd1d13..8f603fc1ea44 100644 --- a/hadoop-ozone/common/pom.xml +++ b/hadoop-ozone/common/pom.xml @@ -251,7 +251,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RegisterValidator.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RegisterValidator.java new file mode 100644 index 000000000000..d2b3d7b37738 --- /dev/null +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RegisterValidator.java @@ -0,0 +1,41 @@ +/* + * 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.request.validation; + +import org.apache.hadoop.ozone.Versioned; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Annotations to register a validator. {@link org.apache.ozone.annotations.RegisterValidatorProcessor} + * enforces other annotation to have the following methods: + * applyBefore : Returns an enum which implement {@link Versioned} + * requestType: Returns an Enum value. + * processingPhase: Returns {@link RequestProcessingPhase} + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface RegisterValidator { + String APPLY_BEFORE_METHOD_NAME = "applyBefore"; + String REQUEST_TYPE_METHOD_NAME = "requestType"; + String PROCESSING_PHASE_METHOD_NAME = "processingPhase"; +} diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestProcessingPhase.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RequestProcessingPhase.java similarity index 95% rename from hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestProcessingPhase.java rename to hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RequestProcessingPhase.java index 672156842914..225ac1a6d452 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestProcessingPhase.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/RequestProcessingPhase.java @@ -14,7 +14,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package org.apache.hadoop.ozone.om.request.validation; +package org.apache.hadoop.ozone.request.validation; /** * Processing phase defines when a request validator should run. diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/ValidatorRegistry.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/ValidatorRegistry.java new file mode 100644 index 000000000000..6d1263bf372f --- /dev/null +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/ValidatorRegistry.java @@ -0,0 +1,314 @@ +/* + * 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.request.validation; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.ozone.Versioned; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Registry that loads and stores the request validators to be applied by + * a service. + */ +public class ValidatorRegistry> { + + /** + * A validator registered should have the following parameters: + * applyBeforeVersion: Enum extending Version + * RequestType: Enum signifying the type of request. + * RequestProcessingPhase: Signifying if the validator is supposed to run pre or post submitting the request. + * Based on the afforementioned parameters a complete map is built which stores the validators in a sorted order of + * the applyBeforeVersion value of the validator method. + * Thus when a request comes with a certain version value, all validators containing `applyBeforeVersion` parameter + * greater than the request versions get triggered. + * {@link #validationsFor(Enum, RequestProcessingPhase, Class, Versioned)} + */ + private final Map, EnumMap>>> indexedValidatorMap; + + /** + * Creates a {@link ValidatorRegistry} instance that discovers validation + * methods in the provided package and the packages in the same resource. + * A validation method is recognized by all the annotations classes which + * are annotated by {@link RegisterValidator} annotation that contains + * important information about how and when to use the validator. + * @param requestType class of request type enum. + * @param validatorPackage the main package inside which validatiors should + * be discovered. + * @param allowedValidators a set containing the various types of version allowed to be registered. + * @param allowedProcessingPhases set of request processing phases which would be allowed to be registered to + * registry. + * + */ + public ValidatorRegistry(Class requestType, + String validatorPackage, + Set> allowedValidators, + Set allowedProcessingPhases) { + this(requestType, ClasspathHelper.forPackage(validatorPackage), allowedValidators, allowedProcessingPhases); + } + + /** + * Creates a {@link ValidatorRegistry} instance that discovers validation + * methods under the provided URL. + * A validation method is recognized by all annotations annotated by the {@link RegisterValidator} + * annotation that contains important information about how and when to use + * the validator. + * @param requestType class of request type enum. + * @param searchUrls the path in which the annotated methods are searched. + * @param allowedValidators a set containing the various types of validator annotation allowed to be registered. + * @param allowedProcessingPhases set of request processing phases which would be allowed to be registered to + * registry. + */ + public ValidatorRegistry(Class requestType, + Collection searchUrls, + Set> allowedValidators, + Set allowedProcessingPhases) { + Class requestArrayClass = (Class) Array.newInstance(requestType, 0) + .getClass(); + Set> validatorsToBeRegistered = + new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("org.apache.hadoop")) + .setScanners(Scanners.TypesAnnotated) + .setParallel(true)).getTypesAnnotatedWith(RegisterValidator.class).stream() + .filter(allowedValidators::contains) + .filter(annotationClass -> getReturnTypeOfAnnotationMethod((Class) annotationClass, + RegisterValidator.REQUEST_TYPE_METHOD_NAME) + .equals(requestArrayClass)) + .map(annotationClass -> (Class) annotationClass) + .collect(Collectors.toSet()); + this.indexedValidatorMap = allowedValidators.stream().collect(ImmutableMap.toImmutableMap(Function.identity(), + validatorClass -> new EnumMap<>(requestType))); + Reflections reflections = new Reflections(new ConfigurationBuilder() + .setUrls(searchUrls) + .setScanners(Scanners.MethodsAnnotated) + .setParallel(true) + ); + initMaps(requestArrayClass, allowedProcessingPhases, validatorsToBeRegistered, reflections); + } + + /** + * Get the validators that has to be run in the given list of, + * for the given requestType and for the given request versions. + * {@link RequestProcessingPhase}. + * + * @param requestType the type of the protocol message + * @param phase the request processing phase + * @param requestVersions different versions extracted from the request. + * @return the list of validation methods that has to run. + */ + public List validationsFor(RequestType requestType, + RequestProcessingPhase phase, + Map, ? extends Versioned> requestVersions) { + return requestVersions.entrySet().stream() + .flatMap(requestVersion -> this.validationsFor(requestType, phase, requestVersion.getKey(), + requestVersion.getValue()).stream()) + .distinct().collect(Collectors.toList()); + } + + /** + * Get the validators that has to be run in the given list of, + * for the given requestType and for the given request versions. + * {@link RequestProcessingPhase}. + * + * @param requestType the type of the protocol message + * @param phase the request processing phase + * @param requestVersion version extracted corresponding to the request. + * @return the list of validation methods that has to run. + */ + public List validationsFor(RequestType requestType, + RequestProcessingPhase phase, + Class validatorClass, + V requestVersion) { + + return Optional.ofNullable(this.indexedValidatorMap.get(requestVersion.getClass())) + .map(requestTypeMap -> requestTypeMap.get(requestType)) + .map(phaseMap -> phaseMap.get(phase)) + .map(indexedMethods -> requestVersion.version() < 0 ? + indexedMethods.getItemsEqualToIdx(requestVersion.version()) : + indexedMethods.getItemsGreaterThanIdx(requestVersion.version())) + .orElse(Collections.emptyList()); + + } + + /** + * Calls a specified method on the validator. + * @Throws IllegalArgumentException when the specified method in the validator is invalid. + */ + private ReturnValue callAnnotationMethod( + Validator validator, String methodName, Class returnValueType) { + try { + return (ReturnValue) validator.getClass().getMethod(methodName).invoke(validator); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Method " + methodName + " not found in class:" + + validator.getClass().getCanonicalName(), e); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new IllegalArgumentException("Error while invoking Method " + methodName + " from " + + validator.getClass().getCanonicalName(), e); + } + } + + private Class getReturnTypeOfAnnotationMethod(Class clzz, String methodName) { + try { + return clzz.getMethod(methodName).getReturnType(); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Method " + methodName + " not found in class:" + clzz.getCanonicalName()); + } + } + + private Versioned getApplyBeforeVersion(Validator validator) { + return callAnnotationMethod(validator, RegisterValidator.APPLY_BEFORE_METHOD_NAME, Versioned.class); + } + + private RequestProcessingPhase getRequestPhase(Validator validator) { + return callAnnotationMethod(validator, RegisterValidator.PROCESSING_PHASE_METHOD_NAME, + RequestProcessingPhase.class); + } + + private RequestType[] getRequestType(Validator validator, + Class requestType) { + return callAnnotationMethod(validator, RegisterValidator.REQUEST_TYPE_METHOD_NAME, requestType); + } + + + private void checkAllowedAnnotationValues(Set values, V value, String valueName, String methodName) { + if (!values.contains(value)) { + throw new IllegalArgumentException( + String.format("Invalid %1$s defined at annotation defined for method : %2$s, Annotation value : %3$s " + + "Allowed versionType: %4$s", valueName, methodName, value.toString(), values)); + } + } + + /** + * Initializes the internal request validator store. + * The requests are stored in the following structure: + * - An EnumMap with the RequestType as the key, and in which + * - values are an EnumMap with the request processing phase as the key, and in which + * - values is an {@link IndexedItems } containing the validation list + * @param validatorsToBeRegistered collection of the annotated validtors to process. + */ + private void initMaps(Class requestType, + Set allowedPhases, + Collection> validatorsToBeRegistered, + Reflections reflections) { + for (Class validator : validatorsToBeRegistered) { + registerValidator(requestType, allowedPhases, validator, reflections); + } + } + + private void registerValidator(Class requestType, + Set allowedPhases, + Class validatorToBeRegistered, + Reflections reflections) { + Collection methods = reflections.getMethodsAnnotatedWith(validatorToBeRegistered); + List> sortedMethodsByApplyBeforeVersion = methods.stream() + .map(method -> Pair.of(method.getAnnotation(validatorToBeRegistered), method)) + .sorted((validatorMethodPair1, validatorMethodPair2) -> + Integer.compare( + this.getApplyBeforeVersion(validatorMethodPair1.getKey()).version(), + this.getApplyBeforeVersion(validatorMethodPair2.getKey()).version())) + .collect(Collectors.toList()); + for (Pair validatorMethodPair : sortedMethodsByApplyBeforeVersion) { + Annotation validator = validatorMethodPair.getKey(); + Method method = validatorMethodPair.getValue(); + Versioned applyBeforeVersion = this.getApplyBeforeVersion(validator); + RequestProcessingPhase phase = this.getRequestPhase(validator); + checkAllowedAnnotationValues(allowedPhases, phase, RegisterValidator.PROCESSING_PHASE_METHOD_NAME, + method.getName()); + Set types = Sets.newHashSet(this.getRequestType(validator, requestType)); + method.setAccessible(true); + for (RequestType type : types) { + EnumMap>> requestMap = + this.indexedValidatorMap.get(validatorToBeRegistered); + EnumMap> phaseMap = + requestMap.computeIfAbsent(type, k -> new EnumMap<>(RequestProcessingPhase.class)); + phaseMap.computeIfAbsent(phase, k -> new IndexedItems<>()).add(method, applyBeforeVersion.version()); + } + } + } + + /** + * Class responsible for maintaining indexs of items. Here each item should have an index corresponding to it. + * The class implements functions for efficiently fetching range gets on the items added to the data structure. + * @param Refers to the Type of the item in the data structure + * @param Type of the index of an item added in the data structure. It is important that the index is + * comparable to each other. + */ + private static final class IndexedItems> { + private final List items; + private final TreeMap indexMap; + + private IndexedItems() { + this.items = new ArrayList<>(); + this.indexMap = new TreeMap<>(); + } + + /** + * Add an item to the collection and update index if required. The order of items added should have their index + * sorted in increasing order. + * @param item + * @param idx + */ + public void add(T item, IDX idx) { + indexMap.putIfAbsent(idx, items.size()); + items.add(item); + } + + /** + * @param indexValue Given index value. + * @return All the items which has an index value greater than given index value. + */ + public List getItemsGreaterThanIdx(IDX indexValue) { + return Optional.ofNullable(indexMap.higherEntry(indexValue)) + .map(Map.Entry::getValue) + .map(startIndex -> items.subList(startIndex, items.size())).orElse(Collections.emptyList()); + } + + /** + * @param indexValue Given index value. + * @return All the items which has an index value greater than given index value. + */ + public List getItemsEqualToIdx(IDX indexValue) { + return Optional.ofNullable(indexMap.get(indexValue)) + .map(startIndex -> items.subList(startIndex, Optional.ofNullable(indexMap.higherEntry(indexValue)) + .map(Map.Entry::getValue).orElse(items.size()))) + .orElse(Collections.emptyList()); + } + + } + +} diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/package-info.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/package-info.java new file mode 100644 index 000000000000..2666db0b6066 --- /dev/null +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/request/validation/package-info.java @@ -0,0 +1,40 @@ +/* + * 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. + */ +/** + * Request's validation handling. + * + * This package holds facilities to add new situation specific behaviour to + * request handling without cluttering the basic logic of the request handler + * code for any server. + * {@link org.apache.hadoop.ozone.request.validation.RegisterValidator} + * is used to register any validator which has the following methods: + * - applyBefore : Returns an enum which implement {@link org.apache.hadoop.ozone.Version} + * - requestType: Returns an Enum value. + * - processingPhase: Returns {@link org.apache.hadoop.ozone.request.validation.RequestProcessingPhase} + * + * The system uses a reflection based discovery to find methods that are + * annotated with the + * {@link org.apache.hadoop.ozone.request.validation.RegisterValidator} + * annotation. + * This annotation is used to register a particular annotation which inturn would be used to specify conditions in + * which a certain validator has to be used, the request type to which the validation should be applied, + * and the request processing phase in which we apply the validation and the maxVersion corresponding to which this + * is supposed to run. + */ + +package org.apache.hadoop.ozone.request.validation; diff --git a/hadoop-ozone/csi/pom.xml b/hadoop-ozone/csi/pom.xml index ba66c5d5272e..fc57c81ea338 100644 --- a/hadoop-ozone/csi/pom.xml +++ b/hadoop-ozone/csi/pom.xml @@ -275,7 +275,8 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/insight/pom.xml b/hadoop-ozone/insight/pom.xml index fa3862a7f71d..46ec0d0cd42d 100644 --- a/hadoop-ozone/insight/pom.xml +++ b/hadoop-ozone/insight/pom.xml @@ -165,7 +165,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java index 1b7eb837cf89..6f79839cd021 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java @@ -460,7 +460,7 @@ public void testCreateRecoveryContainer() throws Exception { int replicaIndex = 4; XceiverClientSpi dnClient = xceiverClientManager.acquireClient( createSingleNodePipeline(newPipeline, newPipeline.getNodes().get(0), - 2)); + replicaIndex)); try { // To create the actual situation, container would have been in closed // state at SCM. diff --git a/hadoop-ozone/interface-storage/pom.xml b/hadoop-ozone/interface-storage/pom.xml index cd2e1e347831..9c5e7b63f973 100644 --- a/hadoop-ozone/interface-storage/pom.xml +++ b/hadoop-ozone/interface-storage/pom.xml @@ -125,7 +125,8 @@ Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/ozone-manager/pom.xml b/hadoop-ozone/ozone-manager/pom.xml index 8e78814eb6b4..6eced24a0672 100644 --- a/hadoop-ozone/ozone-manager/pom.xml +++ b/hadoop-ozone/ozone-manager/pom.xml @@ -419,7 +419,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> org.apache.hadoop.hdds.conf.ConfigFileGenerator - org.apache.ozone.annotations.RequestFeatureValidatorProcessor + org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor + org.apache.ozone.annotations.RegisterValidatorProcessor diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java index 3c21a2a851b8..29e4f2be61dc 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java @@ -20,6 +20,7 @@ import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension; import org.apache.hadoop.hdds.client.DefaultReplicationConfig; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.hdds.utils.db.cache.CacheValue; @@ -42,9 +43,8 @@ import org.apache.hadoop.ozone.om.helpers.OzoneAclUtil; import org.apache.hadoop.ozone.om.request.OMClientRequest; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.bucket.OMBucketCreateResponse; @@ -400,10 +400,10 @@ public boolean checkQuotaBytesValid(OMMetadataManager metadataManager, } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateBucket + requestType = Type.CreateBucket, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCreateBucketWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -423,10 +423,10 @@ public static OMRequest disallowCreateBucketWithECReplicationConfig( return req; } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateBucket + requestType = Type.CreateBucket, + applyBefore = OMLayoutFeature.BUCKET_LAYOUT_SUPPORT ) public static OMRequest handleCreateBucketWithBucketLayoutDuringPreFinalize( OMRequest req, ValidationContext ctx) throws OMException { @@ -464,10 +464,10 @@ public static OMRequest handleCreateBucketWithBucketLayoutDuringPreFinalize( * write to them, instead of using the server default which may be in a layout * they do not understand. */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateBucket + requestType = Type.CreateBucket, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest setDefaultBucketLayoutForOlderClients(OMRequest req, ValidationContext ctx) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketDeleteRequest.java index 22e710dc9116..8c13d6ac4ef8 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketDeleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketDeleteRequest.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.Map; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.Table; import org.apache.hadoop.hdds.utils.db.TableIterator; @@ -32,9 +33,8 @@ import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; import org.apache.hadoop.ozone.om.helpers.SnapshotInfo; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -280,10 +280,10 @@ private boolean bucketContainsSnapshotInCache( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.DeleteBucket + requestType = Type.DeleteBucket, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockBucketDeleteWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java index 941b41ca49b3..4b5be598cc0c 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java @@ -25,6 +25,7 @@ import com.google.common.base.Preconditions; import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension; import org.apache.hadoop.hdds.client.DefaultReplicationConfig; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.audit.AuditLogger; @@ -33,9 +34,7 @@ import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -357,10 +356,10 @@ public boolean checkQuotaNamespaceValid(OmVolumeArgs omVolumeArgs, return true; } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.SetBucketProperty + requestType = Type.SetBucketProperty, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowSetBucketPropertyWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMDirectoryCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMDirectoryCreateRequest.java index 732886fa0e6c..b4afe8d614d1 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMDirectoryCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMDirectoryCreateRequest.java @@ -26,14 +26,15 @@ import java.util.Map; import com.google.common.base.Preconditions; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -271,10 +272,10 @@ private void logResult(CreateDirectoryRequest createDirectoryRequest, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateDirectory + requestType = Type.CreateDirectory, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCreateDirectoryWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -304,10 +305,10 @@ public static OMRequest disallowCreateDirectoryWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateDirectory + requestType = Type.CreateDirectory, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockCreateDirectoryWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java index 08b25718288c..e81eb27bf0d1 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java @@ -29,14 +29,15 @@ import com.google.common.base.Preconditions; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hdds.client.ReplicationConfig; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.OzoneConfigUtil; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.file.OMFileCreateResponse; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; @@ -384,10 +385,10 @@ protected void checkAllParentsExist(KeyArgs keyArgs, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = CreateFile + requestType = CreateFile, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCreateFileWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -416,10 +417,10 @@ public static OMRequest disallowCreateFileWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateFile + requestType = Type.CreateFile, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockCreateFileWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java index bbf5ec0afaf1..d1576c11adcc 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java @@ -26,14 +26,15 @@ import com.google.common.base.Preconditions; import org.apache.hadoop.hdds.client.ReplicationConfig; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.QuotaUtil; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -277,10 +278,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn return omClientResponse; } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.AllocateBlock + requestType = Type.AllocateBlock, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowAllocateBlockWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -307,10 +308,10 @@ public static OMRequest disallowAllocateBlockWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.AllocateBlock + requestType = Type.AllocateBlock, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockAllocateBlockWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java index 87d126de98a9..91efd57073de 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java @@ -28,7 +28,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneManagerVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.helpers.KeyValueUtil; @@ -41,9 +43,8 @@ import org.apache.hadoop.ozone.om.helpers.WithMetadata; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; import org.apache.hadoop.ozone.om.request.util.OmKeyHSyncUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -492,10 +493,10 @@ protected void processResult(CommitKeyRequest commitKeyRequest, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CommitKey + requestType = Type.CommitKey, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCommitKeyWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -522,10 +523,10 @@ public static OMRequest disallowCommitKeyWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CommitKey + requestType = Type.CommitKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockCommitKeyWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { @@ -541,10 +542,10 @@ public static OMRequest blockCommitKeyWithBucketLayoutFromOldClient( return req; } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CommitKey + requestType = Type.CommitKey, + applyBefore = OMLayoutFeature.HBASE_SUPPORT ) public static OMRequest disallowHsync( OMRequest req, ValidationContext ctx) throws OMException { @@ -574,8 +575,8 @@ public static OMRequest disallowHsync( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( + applyBefore = OMLayoutFeature.HBASE_SUPPORT, processingPhase = RequestProcessingPhase.PRE_PROCESS, requestType = Type.CommitKey ) diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java index e817901c22ef..5d8e9f379a06 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java @@ -28,7 +28,9 @@ import com.google.common.base.Preconditions; import org.apache.hadoop.hdds.client.ReplicationConfig; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneManagerVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.om.OzoneConfigUtil; import org.apache.hadoop.ozone.om.exceptions.OMException; @@ -36,9 +38,8 @@ import org.apache.hadoop.ozone.om.lock.OzoneLockStrategy; import org.apache.hadoop.ozone.om.request.file.OMFileRequest; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UserInfo; @@ -390,10 +391,10 @@ protected void logResult(CreateKeyRequest createKeyRequest, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateKey + requestType = Type.CreateKey, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCreateKeyWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -420,10 +421,10 @@ public static OMRequest disallowCreateKeyWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CreateKey + requestType = Type.CreateKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockCreateKeyWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java index db1adc138939..7b26513726e6 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java @@ -24,15 +24,15 @@ import org.apache.hadoop.ozone.om.OMPerformanceMetrics; import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OmUtils; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType; import org.slf4j.Logger; @@ -242,10 +242,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.DeleteKey + requestType = Type.DeleteKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockDeleteKeyWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java index 35940f5a770a..dc968d2844af 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java @@ -23,13 +23,13 @@ import java.util.Map; import com.google.common.base.Preconditions; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; import org.apache.hadoop.ozone.security.acl.OzoneObj; @@ -262,10 +262,10 @@ private Map buildAuditMap( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.RenameKey + requestType = Type.RenameKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockRenameKeyWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java index e090d61afd3f..d7792f8765d2 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; @@ -38,9 +39,8 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.key.OMKeysDeleteResponse; @@ -361,10 +361,10 @@ protected static void addDeletedKeys(Map auditMap, * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.DeleteKeys + requestType = Type.DeleteKeys, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockDeleteKeysWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysRenameRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysRenameRequest.java index 0d105c1d2279..40146116e66e 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysRenameRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysRenameRequest.java @@ -19,6 +19,7 @@ package org.apache.hadoop.ozone.om.request.key; import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.Table; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; @@ -34,9 +35,8 @@ import org.apache.hadoop.ozone.om.OzoneManager; import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.key.OMKeysRenameResponse; @@ -296,10 +296,10 @@ private Map buildAuditMap(Map auditMap, * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.RenameKeys + requestType = Type.RenameKeys, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockRenameKeysWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java index 90a6dfa31ad9..934eaf8fdfc2 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java @@ -23,6 +23,7 @@ import java.util.Map; import com.google.common.collect.Lists; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.OzoneConsts; @@ -34,9 +35,8 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.request.util.ObjectParser; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.key.acl.OMKeyAclResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; @@ -164,10 +164,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.AddAcl + requestType = Type.AddAcl, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockAddAclWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java index 00af126e1e43..aa17720d1a7a 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java @@ -23,6 +23,7 @@ import java.util.Map; import com.google.common.collect.Lists; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.OzoneConsts; @@ -34,9 +35,8 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.request.util.ObjectParser; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.key.acl.OMKeyAclResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; @@ -165,10 +165,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.RemoveAcl + requestType = Type.RemoveAcl, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockRemoveAclWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java index 2f50fde5cb98..52533fd1e39e 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java @@ -23,6 +23,7 @@ import java.util.Map; import com.google.common.collect.Lists; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.OzoneConsts; @@ -35,9 +36,8 @@ import org.apache.hadoop.ozone.om.helpers.OzoneAclUtil; import org.apache.hadoop.ozone.om.request.util.ObjectParser; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.key.acl.OMKeyAclResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; @@ -161,10 +161,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.SetAcl + requestType = Type.SetAcl, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockSetAclWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3InitiateMultipartUploadRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3InitiateMultipartUploadRequest.java index 0a2703c769ed..bee24223648b 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3InitiateMultipartUploadRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3InitiateMultipartUploadRequest.java @@ -20,8 +20,10 @@ import com.google.common.base.Preconditions; import org.apache.hadoop.hdds.client.ReplicationConfig; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.helpers.KeyValueUtil; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.audit.OMAction; import org.apache.hadoop.ozone.om.OMMetadataManager; @@ -37,9 +39,8 @@ import org.apache.hadoop.ozone.om.request.key.OMKeyRequest; import org.apache.hadoop.ozone.om.request.util.OMMultipartUploadUtils; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.s3.multipart.S3InitiateMultipartUploadResponse; @@ -286,10 +287,10 @@ protected void logResult(OzoneManager ozoneManager, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.InitiateMultiPartUpload + requestType = Type.InitiateMultiPartUpload, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowInitiateMultiPartUploadWithECReplicationConfig( @@ -319,10 +320,10 @@ protected void logResult(OzoneManager ozoneManager, * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.InitiateMultiPartUpload + requestType = Type.InitiateMultiPartUpload, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockInitiateMPUWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java index 268c92dbd6ec..2ab8e89b4c86 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java @@ -22,16 +22,17 @@ import java.nio.file.InvalidPathException; import java.util.Map; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneConsts; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.QuotaUtil; import org.apache.hadoop.ozone.om.request.util.OMMultipartUploadUtils; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -257,10 +258,10 @@ protected String getMultipartOpenKey(String multipartUploadID, getBucketLayout()); } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.AbortMultiPartUpload + requestType = Type.AbortMultiPartUpload, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowAbortMultiPartUploadWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -288,10 +289,10 @@ public static OMRequest disallowAbortMultiPartUploadWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.AbortMultiPartUpload + requestType = Type.AbortMultiPartUpload, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockMPUAbortWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCommitPartRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCommitPartRequest.java index 16ab458a014f..779362e82fca 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCommitPartRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCommitPartRequest.java @@ -19,6 +19,8 @@ package org.apache.hadoop.ozone.om.request.s3.multipart; import com.google.common.annotations.VisibleForTesting; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.audit.OMAction; @@ -33,9 +35,8 @@ import org.apache.hadoop.ozone.om.helpers.OmMultipartKeyInfo; import org.apache.hadoop.ozone.om.request.key.OMKeyRequest; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.s3.multipart @@ -348,10 +349,10 @@ private String getMultipartKey(String volumeName, String bucketName, keyName, uploadID); } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CommitMultiPartUpload + requestType = Type.CommitMultiPartUpload, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCommitMultiPartUploadWithECReplicationConfig( OMRequest req, ValidationContext ctx) throws OMException { @@ -379,10 +380,10 @@ public static OMRequest disallowCommitMultiPartUploadWithECReplicationConfig( * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CommitMultiPartUpload + requestType = Type.CommitMultiPartUpload, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockMPUCommitWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCompleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCompleteRequest.java index 2bb77005c957..5fa2b92484a7 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCompleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadCompleteRequest.java @@ -32,8 +32,10 @@ import java.util.function.BiFunction; import org.apache.hadoop.hdds.client.ReplicationConfig; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.om.OzoneConfigUtil; import org.apache.hadoop.ozone.om.request.file.OMFileRequest; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.hadoop.ozone.protocolPB.OMPBHelper; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; @@ -54,9 +56,8 @@ import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; import org.apache.hadoop.ozone.om.request.key.OMKeyRequest; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.response.s3.multipart.S3MultipartUploadCompleteResponse; @@ -707,10 +708,10 @@ private void updateCache(OMMetadataManager omMetadataManager, } } - @RequestFeatureValidator( - conditions = ValidationCondition.CLUSTER_NEEDS_FINALIZATION, + @OMLayoutVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CompleteMultiPartUpload + requestType = Type.CompleteMultiPartUpload, + applyBefore = OMLayoutFeature.ERASURE_CODED_STORAGE_SUPPORT ) public static OMRequest disallowCompleteMultiPartUploadWithECReplicationConfig( @@ -739,10 +740,10 @@ private void updateCache(OMMetadataManager omMetadataManager, * @return the validated request * @throws OMException if the request is invalid */ - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.PRE_PROCESS, - requestType = Type.CompleteMultiPartUpload + requestType = Type.CompleteMultiPartUpload, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMRequest blockMPUCompleteWithBucketLayoutFromOldClient( OMRequest req, ValidationContext ctx) throws IOException { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMClientVersionValidator.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMClientVersionValidator.java new file mode 100644 index 000000000000..fe3e735c4753 --- /dev/null +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMClientVersionValidator.java @@ -0,0 +1,102 @@ +/* + * 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.request.validation; + +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; +import org.apache.hadoop.ozone.request.validation.RegisterValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; +import org.apache.hadoop.ozone.request.validation.ValidatorRegistry; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An annotation to mark methods that do certain request validations based on the + * request protocol's client version. + * + * The methods annotated with this annotation are collected by the + * {@link ValidatorRegistry} class during the initialization of the server. + * + * The conditions specify the specific use case in which the validator should be + * applied to the request. See {@link VersionExtractor} for getting all the supported different + * {@link org.apache.hadoop.ozone.Version}. + * The validator method should be applied the specified request types + * to help keep these methods simple and straightforward. If you want to use + * the same validation for different requests just put it as part of the lists of request types. + * + * The annotated methods have to have a fixed signature. + * A {@link RequestProcessingPhase#PRE_PROCESS} phase method is running before + * the request is processed by the regular code. + * Its signature has to be the following: + * - it has to be static and idempotent + * - it has to have two parameters + * - the first parameter it is an + * {@link + * org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest} + * - the second parameter of type {@link ValidationContext} + * - the method has to return the modified request, or throw a ServiceException + * in case the request is considered to be invalid + * - the method does not need to care about preserving the request it gets, + * the original request is captured and saved by the calling environment. + * + * A {@link RequestProcessingPhase#POST_PROCESS} phase method is running once + * the + * {@link + * org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse} + * is calculated for a given request. + * Its signature has to be the following: + * - it has to be static and idempotent + * - it has three parameters + * - similarly to the pre-processing validators, first parameter is the + * OMRequest, the second parameter is the OMResponse, and the third + * parameter is a ValidationContext. + * - the method has to return the modified OMResponse or throw a + * ServiceException if the request is considered invalid based on response. + * - the method gets the request object that was supplied for the general + * request processing code, not the original request, while it gets a copy + * of the original response object provided by the general request processing + * code. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@RegisterValidator +public @interface OMClientVersionValidator { + + /** + * Defines if the validation has to run before or after the general request + * processing. + * @return if this is a pre or post processing validator + */ + RequestProcessingPhase processingPhase(); + + /** + * The type of the request handled by this validator method. + * @return the requestType to whihc the validator should be applied + */ + Type[] requestType(); + + /** + * The max version for which the validator would run. The validator would run for the request + * where the version is older than the excluding of the specified version. + * @returns the max client version until which the validator runs excluding the specified version itself. + */ + ClientVersion applyBefore(); + +} diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestFeatureValidator.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMLayoutVersionValidator.java similarity index 80% rename from hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestFeatureValidator.java rename to hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMLayoutVersionValidator.java index 5f1f08266b85..be7e62829534 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestFeatureValidator.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/OMLayoutVersionValidator.java @@ -16,7 +16,11 @@ */ package org.apache.hadoop.ozone.om.request.validation; +import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; +import org.apache.hadoop.ozone.request.validation.RegisterValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; +import org.apache.hadoop.ozone.request.validation.ValidatorRegistry; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -24,14 +28,15 @@ import java.lang.annotation.Target; /** - * An annotation to mark methods that do certain request validations. + * An annotation to mark methods that do certain request validations based on the + * server's layout version and capability to perform a certain operation. * * The methods annotated with this annotation are collected by the * {@link ValidatorRegistry} class during the initialization of the server. * * The conditions specify the specific use case in which the validator should be - * applied to the request. See {@link ValidationCondition} for more details - * on the specific conditions. + * applied to the request. See {@link VersionExtractor} for getting all the supported different + * {@link org.apache.hadoop.ozone.Version}. * The validator method should be applied to just one specific request type * to help keep these methods simple and straightforward. If you want to use * the same validation for different request types, use inheritance, and @@ -75,13 +80,8 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface RequestFeatureValidator { - - /** - * Runtime conditions in which a validator should run. - * @return a list of conditions when the validator should be applied - */ - ValidationCondition[] conditions(); +@RegisterValidator +public @interface OMLayoutVersionValidator { /** * Defines if the validation has to run before or after the general request @@ -92,8 +92,15 @@ /** * The type of the request handled by this validator method. - * @return the requestType to whihc the validator shoudl be applied + * @return the requestType to whihc the validator should be applied + */ + Type[] requestType(); + + /** + * The max version for which the validator would run. The validator would run for the request + * where the version is older than the excluding of the specified version. + * @returns the max layout version until which the validator runs excluding the specified version itself. */ - Type requestType(); + OMLayoutFeature applyBefore(); } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestValidations.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestValidations.java index b9fbb0c927fe..56a29f27fd2f 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestValidations.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/RequestValidations.java @@ -16,21 +16,31 @@ */ package org.apache.hadoop.ozone.om.request.validation; +import com.google.common.collect.Sets; import com.google.protobuf.ServiceException; +import org.apache.hadoop.ozone.Versioned; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; +import org.apache.hadoop.ozone.request.validation.ValidatorRegistry; +import org.jgrapht.alg.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.POST_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.PRE_PROCESS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.POST_PROCESS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.PRE_PROCESS; /** * Main class to configure and set up and access the request/response @@ -40,10 +50,13 @@ public class RequestValidations { static final Logger LOG = LoggerFactory.getLogger(RequestValidations.class); private static final String DEFAULT_PACKAGE = "org.apache.hadoop.ozone"; - + private static final Set ALLOWED_REQUEST_PROCESSING_PHASES = + Sets.immutableEnumSet(PRE_PROCESS, POST_PROCESS); private String validationsPackageName = DEFAULT_PACKAGE; private ValidationContext context = null; - private ValidatorRegistry registry = null; + private ValidatorRegistry registry = null; + + public synchronized RequestValidations fromPackage(String packageName) { validationsPackageName = packageName; @@ -56,15 +69,17 @@ public RequestValidations withinContext(ValidationContext validationContext) { } public synchronized RequestValidations load() { - registry = new ValidatorRegistry(validationsPackageName); + registry = new ValidatorRegistry<>(Type.class, validationsPackageName, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + ALLOWED_REQUEST_PROCESSING_PHASES); return this; } public OMRequest validateRequest(OMRequest request) throws Exception { - List validations = registry.validationsFor( - conditions(request), request.getCmdType(), PRE_PROCESS); + List validations = registry.validationsFor(request.getCmdType(), PRE_PROCESS, + this.getVersions(request)); OMRequest validatedRequest = request; try { for (Method m : validations) { @@ -87,10 +102,10 @@ public OMRequest validateRequest(OMRequest request) public OMResponse validateResponse(OMRequest request, OMResponse response) throws ServiceException { - List validations = registry.validationsFor( - conditions(request), request.getCmdType(), POST_PROCESS); - OMResponse validatedResponse = response; + List validations = registry.validationsFor(request.getCmdType(), POST_PROCESS, this.getVersions(request)); + + OMResponse validatedResponse = response.toBuilder().build(); try { for (Method m : validations) { LOG.debug("Running the {} request post-process validation from {}.{}", @@ -105,9 +120,11 @@ public OMResponse validateResponse(OMRequest request, OMResponse response) return validatedResponse; } - private List conditions(OMRequest request) { - return Arrays.stream(ValidationCondition.values()) - .filter(c -> c.shouldApply(request, context)) - .collect(Collectors.toList()); + private Map, Versioned> getVersions(OMRequest request) { + return Arrays.stream(VersionExtractor.values()) + .map(versionExtractor -> Pair.of(versionExtractor.getValidatorClass(), + versionExtractor.extractVersion(request, context))) + .filter(pair -> Objects.nonNull(pair.getSecond())) + .collect(Collectors.toMap(pair -> pair.getFirst(), pair -> pair.getSecond())); } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidationCondition.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidationCondition.java deleted file mode 100644 index 9630500cbd53..000000000000 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidationCondition.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.request.validation; - -import org.apache.hadoop.ozone.ClientVersion; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; - -/** - * Defines conditions for which validators can be assigned to. - * - * These conditions describe a situation where special request handling might - * be necessary. In these cases we do not override the actual request handling - * code, but based on certain request properties we might reject a request - * early, or we might modify the request, or the response received/sent from/to - * the client. - */ -public enum ValidationCondition { - /** - * Classifies validations that has to run after an upgrade until the cluster - * is in a pre-finalized state. - */ - CLUSTER_NEEDS_FINALIZATION { - @Override - public boolean shouldApply(OMRequest req, ValidationContext ctx) { - return ctx.versionManager().needsFinalization(); - } - }, - - /** - * Classifies validations that has to run, when the client uses an older - * protocol version than the server. - */ - OLDER_CLIENT_REQUESTS { - @Override - public boolean shouldApply(OMRequest req, ValidationContext ctx) { - return req.getVersion() < ClientVersion.CURRENT_VERSION; - } - }; - - public abstract boolean shouldApply(OMRequest req, ValidationContext ctx); -} diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidatorRegistry.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidatorRegistry.java deleted file mode 100644 index ac09664cc789..000000000000 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/ValidatorRegistry.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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.request.validation; - -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; -import org.reflections.util.ClasspathHelper; -import org.reflections.util.ConfigurationBuilder; - -import java.lang.reflect.Method; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.POST_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.PRE_PROCESS; - -/** - * Registry that loads and stores the request validators to be applied by - * a service. - */ -public class ValidatorRegistry { - - private final EnumMap>>> - validators = new EnumMap<>(ValidationCondition.class); - - /** - * Creates a {@link ValidatorRegistry} instance that discovers validation - * methods in the provided package and the packages in the same resource. - * A validation method is recognized by the {@link RequestFeatureValidator} - * annotation that contains important information about how and when to use - * the validator. - * @param validatorPackage the main package inside which validatiors should - * be discovered. - */ - ValidatorRegistry(String validatorPackage) { - this(ClasspathHelper.forPackage(validatorPackage)); - } - - /** - * Creates a {@link ValidatorRegistry} instance that discovers validation - * methods under the provided URL. - * A validation method is recognized by the {@link RequestFeatureValidator} - * annotation that contains important information about how and when to use - * the validator. - * @param searchUrls the path in which the annotated methods are searched. - */ - ValidatorRegistry(Collection searchUrls) { - Reflections reflections = new Reflections(new ConfigurationBuilder() - .setUrls(searchUrls) - .setScanners(Scanners.MethodsAnnotated) - .setParallel(true) - ); - - Set describedValidators = - reflections.getMethodsAnnotatedWith(RequestFeatureValidator.class); - initMaps(describedValidators); - } - - /** - * Get the validators that has to be run in the given list of - * {@link ValidationCondition}s, for the given requestType and - * {@link RequestProcessingPhase}. - * - * @param conditions conditions that are present for the request - * @param requestType the type of the protocol message - * @param phase the request processing phase - * @return the list of validation methods that has to run. - */ - List validationsFor( - List conditions, - Type requestType, - RequestProcessingPhase phase) { - - if (conditions.isEmpty() || validators.isEmpty()) { - return Collections.emptyList(); - } - - Set returnValue = new HashSet<>(); - - for (ValidationCondition condition: conditions) { - returnValue.addAll(validationsFor(condition, requestType, phase)); - } - return new ArrayList<>(returnValue); - } - - /** - * Grabs validations for one particular condition. - * - * @param condition conditions that are present for the request - * @param requestType the type of the protocol message - * @param phase the request processing phase - * @return the list of validation methods that has to run. - */ - private List validationsFor( - ValidationCondition condition, - Type requestType, - RequestProcessingPhase phase) { - - EnumMap>> - requestTypeMap = validators.get(condition); - if (requestTypeMap == null || requestTypeMap.isEmpty()) { - return Collections.emptyList(); - } - - EnumMap> phases = - requestTypeMap.get(requestType); - if (phases == null) { - return Collections.emptyList(); - } - - List validatorsForPhase = phases.get(phase); - if (validatorsForPhase == null) { - return Collections.emptyList(); - } - return validatorsForPhase; - } - - /** - * Initializes the internal request validator store. - * The requests are stored in the following structure: - * - An EnumMap with the {@link ValidationCondition} as the key, and in which - * - values are an EnumMap with the request type as the key, and in which - * - values are Pair of lists, in which - * - left side is the pre-processing validations list - * - right side is the post-processing validations list - * @param describedValidators collection of the annotated methods to process. - */ - void initMaps(Collection describedValidators) { - for (Method m : describedValidators) { - RequestFeatureValidator descriptor = - m.getAnnotation(RequestFeatureValidator.class); - m.setAccessible(true); - - for (ValidationCondition condition : descriptor.conditions()) { - EnumMap>> - requestTypeMap = getAndInitialize( - condition, this::newTypeMap, validators); - EnumMap> phases = getAndInitialize( - descriptor.requestType(), this::newPhaseMap, requestTypeMap); - if (isPreProcessValidator(descriptor)) { - getAndInitialize(PRE_PROCESS, ArrayList::new, phases).add(m); - } else if (isPostProcessValidator(descriptor)) { - getAndInitialize(POST_PROCESS, ArrayList::new, phases).add(m); - } - } - } - } - - private EnumMap>> newTypeMap() { - return new EnumMap<>(Type.class); - } - - private EnumMap> newPhaseMap() { - return new EnumMap<>(RequestProcessingPhase.class); - } - - private V getAndInitialize(K key, Supplier defaultSupplier, Map from) { - return from.computeIfAbsent(key, k -> defaultSupplier.get()); - } - - private boolean isPreProcessValidator(RequestFeatureValidator descriptor) { - return descriptor.processingPhase() - .equals(PRE_PROCESS); - } - - private boolean isPostProcessValidator(RequestFeatureValidator descriptor) { - return descriptor.processingPhase() - .equals(POST_PROCESS); - } - -} diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/VersionExtractor.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/VersionExtractor.java index e7acef45bfe2..3639511020f4 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/VersionExtractor.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/VersionExtractor.java @@ -22,6 +22,8 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.upgrade.LayoutVersionManager; +import java.lang.annotation.Annotation; + /** * Class to extract version out of OM request. */ @@ -37,8 +39,8 @@ public Versioned extractVersion(OMRequest req, ValidationContext ctx) { } @Override - public Class getVersionClass() { - return OMLayoutFeature.class; + public Class getValidatorClass() { + return OMLayoutVersionValidator.class; } }, @@ -53,11 +55,11 @@ public Versioned extractVersion(OMRequest req, ValidationContext ctx) { } @Override - public Class getVersionClass() { - return ClientVersion.class; + public Class getValidatorClass() { + return OMClientVersionValidator.class; } }; public abstract Versioned extractVersion(OMRequest req, ValidationContext ctx); - public abstract Class getVersionClass(); + public abstract Class getValidatorClass(); } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/package-info.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/package-info.java index 8f5ac133b19f..326abac63598 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/package-info.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/validation/package-info.java @@ -16,7 +16,7 @@ */ /** - * Request's feature validation handling. + * Request's validation handling. * * This package holds facilities to add new situation specific behaviour to * request handling without cluttering the basic logic of the request handler @@ -28,25 +28,29 @@ * request type * - a client connects to the server but uses an older version of the protocol * - a client connects to the server but uses a newer version of the protocol + * - a client connects to the server and performs an operation corresponding + * to a feature the server hasn't finalized for which these requests might have + * to be rejected. * - the code can handle certain checks that have to run all the time, but at * first we do not see a general use case that we would pull in immediately. - * These are the current - * {@link org.apache.hadoop.ozone.om.request.validation.ValidationCondition}s - * but this list might be extended later on if we see other use cases. + * These are the current registered + * {@link org.apache.hadoop.ozone.om.request.validation.VersionExtractor}s + * which would be extracted out of the om request and all validators + * fulfilling the condition would be run. * - * The system uses a reflection based discovery to find methods that are + * The system uses a reflection based discovery to find annotations that are * annotated with the - * {@link org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator} + * {@link org.apache.hadoop.ozone.request.validation.RegisterValidator} * annotation. - * This annotation is used to specify the condition in which a certain validator - * has to be used, the request type to which the validation should be applied, - * and the request processing phase in which we apply the validation. + * This annotation is used to register a particular annotation which in turn would be used to specify + * the request type to which the validation should be applied, + * and the request processing phase in which we apply the validation and the maxVersion corresponding to which this + * is supposed to run. + * + * One validator can be applied in multiple, E.g. + * {@link org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator}, + * {@link org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator} * - * One validator can be applied in multiple - * {@link org.apache.hadoop.ozone.om.request.validation.ValidationCondition} - * but a validator has to handle strictly just one - * {@link org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type - * }. * The main reason to avoid validating multiple request types with the same * validator, is that these validators have to be simple methods without state * any complex validation has to happen in the reql request handling. diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java index ab1f68d9928a..7cb8d482e2eb 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java @@ -41,6 +41,7 @@ import org.apache.hadoop.hdds.client.ReplicationConfig; import org.apache.hadoop.hdds.scm.protocolPB.OzonePBHelper; import org.apache.hadoop.hdds.utils.FaultInjector; +import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.om.helpers.OMAuditLogger; import org.apache.hadoop.ozone.om.helpers.KeyValueUtil; @@ -77,9 +78,8 @@ import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils; import org.apache.hadoop.ozone.om.request.OMClientRequest; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; -import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase; -import org.apache.hadoop.ozone.om.request.validation.ValidationCondition; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.om.response.OMClientResponse; import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion; @@ -666,10 +666,10 @@ private GetKeyInfoResponse getKeyInfo(GetKeyInfoRequest request, return keyInfo.toProtobuf(clientVersion); } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.LookupKey + requestType = Type.LookupKey, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowLookupKeyResponseWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -693,10 +693,10 @@ public static OMResponse disallowLookupKeyResponseWithECReplicationConfig( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.LookupKey + requestType = Type.LookupKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowLookupKeyWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -780,10 +780,10 @@ private ListKeysLightResponse listKeysLight(ListKeysRequest request) return resp.build(); } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListKeys + requestType = Type.ListKeys, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowListKeysResponseWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -807,10 +807,10 @@ public static OMResponse disallowListKeysResponseWithECReplicationConfig( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListKeys + requestType = Type.ListKeys, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowListKeysWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -848,10 +848,10 @@ public static OMResponse disallowListKeysWithBucketLayout( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListTrash + requestType = Type.ListTrash, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowListTrashWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -878,10 +878,10 @@ public static OMResponse disallowListTrashWithECReplicationConfig( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListTrash + requestType = Type.ListTrash, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowListTrashWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1091,10 +1091,10 @@ private RefetchSecretKeyResponse refetchSecretKey() { return response; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.GetFileStatus + requestType = Type.GetFileStatus, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowGetFileStatusWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1121,10 +1121,10 @@ public static OMResponse disallowGetFileStatusWithECReplicationConfig( } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.GetFileStatus + requestType = Type.GetFileStatus, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowGetFileStatusWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1170,10 +1170,10 @@ private LookupFileResponse lookupFile(LookupFileRequest request, .build(); } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.LookupFile + requestType = Type.LookupFile, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowLookupFileWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1198,10 +1198,10 @@ public static OMResponse disallowLookupFileWithECReplicationConfig( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.LookupFile + requestType = Type.LookupFile, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowLookupFileWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1280,10 +1280,10 @@ private ListStatusLightResponse listStatusLight( return listStatusLightResponseBuilder.build(); } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListStatus + requestType = Type.ListStatus, + applyBefore = ClientVersion.ERASURE_CODING_SUPPORT ) public static OMResponse disallowListStatusResponseWithECReplicationConfig( OMRequest req, OMResponse resp, ValidationContext ctx) @@ -1308,10 +1308,10 @@ public static OMResponse disallowListStatusResponseWithECReplicationConfig( return resp; } - @RequestFeatureValidator( - conditions = ValidationCondition.OLDER_CLIENT_REQUESTS, + @OMClientVersionValidator( processingPhase = RequestProcessingPhase.POST_PROCESS, - requestType = Type.ListStatus + requestType = Type.ListStatus, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) public static OMResponse disallowListStatusResponseWithBucketLayout( OMRequest req, OMResponse resp, ValidationContext ctx) diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestOMValidatorProcessor.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestOMValidatorProcessor.java new file mode 100644 index 000000000000..2dd96e9d7d3f --- /dev/null +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestOMValidatorProcessor.java @@ -0,0 +1,583 @@ +/* + * 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.request.validation; + +import com.google.testing.compile.Compilation; +import com.google.testing.compile.JavaFileObjects; +import org.apache.hadoop.ozone.Versioned; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; +import org.apache.hadoop.ozone.request.validation.RegisterValidator; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; +import org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_UNEXPECTED_PARAMETER_COUNT; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMREQUEST; +import static org.apache.ozone.annotations.OmRequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * Compile tests against the annotation processor for all validators annotated with + * {@link RegisterValidator} annotation. + * + * The processor should ensure the method signatures and return values, based + * on annotation arguments provided. + */ +public class TestOMValidatorProcessor { + + private static final String CLASSNAME = "Validation"; + private static final Map, Class> ANNOTATION_VERSION_CLASS_MAP = new Reflections( + new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("")).setScanners(Scanners.TypesAnnotated) + .setParallel(true)).getTypesAnnotatedWith(RegisterValidator.class).stream().filter(annotationClass -> { + try { + return annotationClass.getMethod(RegisterValidator.REQUEST_TYPE_METHOD_NAME).getReturnType() + .equals(Type[].class); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toMap(Function.identity(), annotationClass -> { + try { + return annotationClass.getMethod(RegisterValidator.APPLY_BEFORE_METHOD_NAME).getReturnType(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + })); + + private static Stream annotatedClasses() { + return ANNOTATION_VERSION_CLASS_MAP.entrySet().stream().flatMap(e -> + Arrays.stream(e.getValue().getEnumConstants()).map(version -> Arguments.of(e.getKey(), version))); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testAnnotationCanOnlyBeAppliedOnMethods(Class annotationClass, + V version) { + for (Annotation a : annotationClass.getAnnotations()) { + if (a instanceof Target) { + assertEquals(1, ((Target) a).value().length); + assertSame(((Target) a).value()[0], ElementType.METHOD); + } + } + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testACorrectAnnotationSetupForPreProcessCompiles(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions("ServiceException"), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testACorrectAnnotationSetupForPostProcessCompiles( + Class annotationClass, V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), + exceptions("ServiceException"), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testValidatorDoesNotNecessarilyThrowsExceptions(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testNonStaticValidatorDoesNotCompile(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testValidatorMethodCanBeFinal(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static", "final"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testValidatorMethodCanBePrivate(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("private", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testValidatorMethodCanBeDefaultVisible(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testValidatorMethodCanBeProtected(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("protected", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)).succeeded(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testNotEnoughParametersForPreProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining( + String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 2, 1)); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testTooManyParametersForPreProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining( + String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 2, 3)); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testNotEnoughParametersForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining( + String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 3, 2)); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testTooManyParametersForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx", + "String name"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining( + String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 3, 4)); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongReturnValueForPreProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("String"), + parameters("OMRequest rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMREQUEST); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongReturnValueForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("String"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongFirstArgumentForPreProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("String rq", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongFirstArgumentForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("String rq", "OMResponse rp", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongSecondArgumentForPreProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(preProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMRequest"), + parameters("OMRequest rq", "String ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongSecondArgumentForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "String rp", "ValidationContext ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testWrongThirdArgumentForPostProcess(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp", "String ctx"), + exceptions(), annotationClass); + + assertThat(compile(source)) + .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testInvalidProcessingPhase(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf("INVALID", aReqType(), annotationClass, version), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), + exceptions("ServiceException"), annotationClass); + + assertThat(compile(source)).failed(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testInvalidClientVersion(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(RequestProcessingPhase.PRE_PROCESS, aReqType(), annotationClass, null), + modifiers("public", "static"), + returnValue("OMResponse"), + parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), + exceptions("ServiceException"), annotationClass); + + assertThat(compile(source)).failed(); + } + + @ParameterizedTest + @MethodSource("annotatedClasses") + public & Versioned> void testMultipleErrorMessages(Class annotationClass, + V version) { + List source = generateSourceOfValidatorMethodWith( + annotationOf(postProcess(), aReqType(), annotationClass, version), + modifiers(), + returnValue("String"), + parameters("String rq", "int rp", "String ctx"), + exceptions(), annotationClass); + + Compilation compilation = compile(source); + assertThat(compilation) + .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC); + assertThat(compilation) + .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE); + assertThat(compilation) + .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); + assertThat(compilation) + .hadErrorContaining(ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE); + assertThat(compilation) + .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); + } + + private Compilation compile(List source) { + Compilation c = javac() + .withProcessors(new OmRequestFeatureValidatorProcessor()) + .compile(JavaFileObjects.forSourceLines(CLASSNAME, source)); + c.diagnostics().forEach(System.out::println); + return c; + } + + private RequestProcessingPhase preProcess() { + return RequestProcessingPhase.PRE_PROCESS; + } + + private RequestProcessingPhase postProcess() { + return RequestProcessingPhase.POST_PROCESS; + } + + private Type aReqType() { + return Type.CreateVolume; + } + + private String returnValue(String retVal) { + return retVal; + } + + private String[] parameters(String... params) { + return params; + } + + private String[] modifiers(String... modifiers) { + return modifiers; + } + + private String[] exceptions(String... exceptions) { + return exceptions; + } + + private List generateSourceOfValidatorMethodWith( + String annotation, + String[] modifiers, + String returnType, + String[] paramspecs, + String[] exceptions, + Class annotationClass) { + List lines = new ArrayList<>(allImports(annotationClass)); + lines.add(""); + lines.add("public class " + CLASSNAME + " {"); + lines.add(""); + lines.add(" " + annotation); + StringBuilder signature = + buildMethodSignature(modifiers, returnType, paramspecs, exceptions); + lines.add(signature.toString()); + lines.add(" return null;"); + lines.add(" }"); + lines.add("}"); + lines.add(""); + lines.stream().forEach(System.out::println); + return lines; + } + + private & Versioned> String annotationOf( + RequestProcessingPhase phase, Type reqType, Class annotationClass, V applyBeforeVersion) { + return annotationOf(phase.name(), reqType, annotationClass, applyBeforeVersion); + } + + private & Versioned> String annotationOf( + String phase, + Type reqType, + Class annotationClass, + V applyBeforeVersion) { + StringBuilder annotation = new StringBuilder(); + annotation.append("@" + annotationClass.getName() + "("); + annotation.append("processingPhase = ").append(phase); + annotation.append(", requestType = ").append(reqType.name()); + if (applyBeforeVersion != null) { + annotation.append(", applyBefore = ").append(applyBeforeVersion.name()); + } + annotation.append(" )"); + return annotation.toString(); + } + + private List allImports(Class annotationClass) { + List imports = new ArrayList<>(); + imports.add("import org.apache.hadoop.ozone.protocol.proto" + + ".OzoneManagerProtocolProtos.OMRequest;"); + imports.add("import org.apache.hadoop.ozone.protocol.proto" + + ".OzoneManagerProtocolProtos.OMResponse;"); + imports.add("import org.apache.hadoop.ozone.om.request.validation" + + ".ValidationContext;"); + imports.add("import com.google.protobuf.ServiceException;"); + for (RequestProcessingPhase phase : RequestProcessingPhase.values()) { + imports.add("import static org.apache.hadoop.ozone.request.validation" + + ".RequestProcessingPhase." + phase.name() + ";"); + } + for (Type reqType : Type.values()) { + imports.add("import static org.apache.hadoop.ozone.protocol.proto" + + ".OzoneManagerProtocolProtos.Type." + reqType.name() + ";"); + } + imports.add("import " + annotationClass.getName() + ";"); + + for (Object enumConstant : ANNOTATION_VERSION_CLASS_MAP.get(annotationClass).getEnumConstants()) { + imports.add("import static " + ANNOTATION_VERSION_CLASS_MAP.get(annotationClass).getCanonicalName() + "." + + ((Enum)enumConstant).name() + ";"); + } + return imports; + } + + private StringBuilder buildMethodSignature( + String[] modifiers, String returnType, + String[] paramspecs, String[] exceptions) { + StringBuilder signature = new StringBuilder(); + signature.append(" "); + for (String modifier : modifiers) { + signature.append(modifier).append(" "); + } + signature.append(returnType).append(" "); + signature.append("validatorMethod("); + signature.append(createParameterList(paramspecs)); + signature.append(") "); + signature.append(createThrowsClause(exceptions)); + return signature.append(" {"); + } + + private String createParameterList(String[] paramSpecs) { + if (paramSpecs == null || paramSpecs.length == 0) { + return ""; + } + StringBuilder parameters = new StringBuilder(); + for (String paramSpec : paramSpecs) { + parameters.append(paramSpec).append(", "); + } + return parameters.substring(0, parameters.length() - 2); + } + + private String createThrowsClause(String[] exceptions) { + StringBuilder throwsClause = new StringBuilder(); + if (exceptions != null && exceptions.length > 0) { + throwsClause.append(" throws "); + StringBuilder exceptionList = new StringBuilder(); + for (String exception : exceptions) { + exceptionList.append(exception).append(", "); + } + throwsClause + .append(exceptionList.substring(0, exceptionList.length() - 2)); + } + return throwsClause.toString(); + } +} diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestFeatureValidatorProcessor.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestFeatureValidatorProcessor.java deleted file mode 100644 index 48947518abd4..000000000000 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestFeatureValidatorProcessor.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * 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.request.validation; - -import com.google.testing.compile.Compilation; -import com.google.testing.compile.JavaFileObjects; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; -import org.apache.ozone.annotations.RequestFeatureValidatorProcessor; -import org.junit.jupiter.api.Test; - -import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.List; - -import static com.google.testing.compile.CompilationSubject.assertThat; -import static com.google.testing.compile.Compiler.javac; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_CONDITION_IS_EMPTY; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_UNEXPECTED_PARAMETER_COUNT; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMREQUEST; -import static org.apache.ozone.annotations.RequestFeatureValidatorProcessor.ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; - -/** - * Compile tests against the annotation processor for the - * {@link RequestFeatureValidator} annotation. - * - * The processor should ensure the method signatures and return values, based - * on annotation arguments provided. - */ -public class TestRequestFeatureValidatorProcessor { - - private static final String CLASSNAME = "Validation"; - - @Test - public void testAnnotationCanOnlyBeAppliedOnMethods() { - Class c = RequestFeatureValidator.class; - for (Annotation a : c.getAnnotations()) { - if (a instanceof Target) { - assertEquals(1, ((Target) a).value().length); - assertSame(((Target) a).value()[0], ElementType.METHOD); - } - } - } - - @Test - public void testACorrectAnnotationSetupForPreProcessCompiles() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions("ServiceException")); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testACorrectAnnotationSetupForPostProcessCompiles() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), - exceptions("ServiceException")); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testValidatorDoesNotNecessarilyThrowsExceptions() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testNonStaticValidatorDoesNotCompile() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC); - } - - @Test - public void testValidatorMethodCanBeFinal() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static", "final"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testValidatorMethodCanBePrivate() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("private", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testValidatorMethodCanBeDefaultVisible() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testValidatorMethodCanBeProtected() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("protected", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).succeeded(); - } - - @Test - public void testEmptyValidationConditionListDoesNotCompile() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(emptyConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)).hadErrorContaining(ERROR_CONDITION_IS_EMPTY); - } - - @Test - public void testNotEnoughParametersForPreProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining( - String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 2, 1)); - } - - @Test - public void testTooManyParametersForPreProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining( - String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 2, 3)); - } - - @Test - public void testNotEnoughParametersForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "OMResponse rp"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining( - String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 3, 2)); - } - - @Test - public void testTooManyParametersForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx", - "String name"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining( - String.format(ERROR_UNEXPECTED_PARAMETER_COUNT, 3, 4)); - } - - @Test - public void testWrongReturnValueForPreProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("String"), - parameters("OMRequest rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMREQUEST); - } - - @Test - public void testWrongReturnValueForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("String"), - parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE); - } - - @Test - public void testWrongFirstArgumentForPreProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("String rq", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); - } - - @Test - public void testWrongFirstArgumentForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("String rq", "OMResponse rp", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); - } - - @Test - public void testWrongSecondArgumentForPreProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), preProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMRequest"), - parameters("OMRequest rq", "String ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); - } - - @Test - public void testWrongSecondArgumentForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "String rp", "ValidationContext ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE); - } - - @Test - public void testWrongThirdArgumentForPostProcess() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), postProcess(), aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "OMResponse rp", "String ctx"), - exceptions()); - - assertThat(compile(source)) - .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); - } - - @Test - public void testInvalidProcessingPhase() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(someConditions(), "INVALID", aReqType()), - modifiers("public", "static"), - returnValue("OMResponse"), - parameters("OMRequest rq", "OMResponse rp", "ValidationContext ctx"), - exceptions("ServiceException")); - - assertThat(compile(source)).failed(); - } - - @Test - public void testMultipleErrorMessages() { - List source = generateSourceOfValidatorMethodWith( - annotationOf(emptyConditions(), postProcess(), aReqType()), - modifiers(), - returnValue("String"), - parameters("String rq", "int rp", "String ctx"), - exceptions()); - - Compilation compilation = compile(source); - assertThat(compilation).hadErrorContaining(ERROR_CONDITION_IS_EMPTY); - assertThat(compilation) - .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_BE_STATIC); - assertThat(compilation) - .hadErrorContaining(ERROR_VALIDATOR_METHOD_HAS_TO_RETURN_OMRESPONSE); - assertThat(compilation) - .hadErrorContaining(ERROR_FIRST_PARAM_HAS_TO_BE_OMREQUEST); - assertThat(compilation) - .hadErrorContaining(ERROR_SECOND_PARAM_HAS_TO_BE_OMRESPONSE); - assertThat(compilation) - .hadErrorContaining(ERROR_LAST_PARAM_HAS_TO_BE_VALIDATION_CONTEXT); - } - - private Compilation compile(List source) { - Compilation c = javac() - .withProcessors(new RequestFeatureValidatorProcessor()) - .compile(JavaFileObjects.forSourceLines(CLASSNAME, source)); - c.diagnostics().forEach(System.out::println); - return c; - } - - private ValidationCondition[] someConditions() { - return - new ValidationCondition[] {ValidationCondition.OLDER_CLIENT_REQUESTS}; - } - - private ValidationCondition[] emptyConditions() { - return new ValidationCondition[] {}; - } - - private RequestProcessingPhase preProcess() { - return RequestProcessingPhase.PRE_PROCESS; - } - - private RequestProcessingPhase postProcess() { - return RequestProcessingPhase.POST_PROCESS; - } - - private Type aReqType() { - return Type.CreateVolume; - } - - private String returnValue(String retVal) { - return retVal; - } - - private String[] parameters(String... params) { - return params; - } - - private String[] modifiers(String... modifiers) { - return modifiers; - } - - private String[] exceptions(String... exceptions) { - return exceptions; - } - - private List generateSourceOfValidatorMethodWith( - String annotation, - String[] modifiers, - String returnType, - String[] paramspecs, - String[] exceptions) { - List lines = new ArrayList<>(allImports()); - lines.add(""); - lines.add("public class " + CLASSNAME + " {"); - lines.add(""); - lines.add(" " + annotation); - StringBuilder signature = - buildMethodSignature(modifiers, returnType, paramspecs, exceptions); - lines.add(signature.toString()); - lines.add(" return null;"); - lines.add(" }"); - lines.add("}"); - lines.add(""); - lines.stream() - .filter(s -> !s.startsWith("import")) - .forEach(System.out::println); - return lines; - } - - private String annotationOf( - ValidationCondition[] conditions, - RequestProcessingPhase phase, - Type reqType) { - return annotationOf(conditions, phase.name(), reqType); - } - - private String annotationOf( - ValidationCondition[] conditions, - String phase, - Type reqType) { - StringBuilder annotation = new StringBuilder(); - annotation.append("@RequestFeatureValidator("); - StringBuilder conditionsArray = new StringBuilder(); - conditionsArray.append("conditions = { "); - if (conditions.length > 0) { - for (ValidationCondition condition : conditions) { - conditionsArray.append(condition.name()).append(", "); - } - annotation - .append(conditionsArray.substring(0, conditionsArray.length() - 2)); - } else { - annotation.append(conditionsArray); - } - annotation.append(" }"); - annotation.append(", processingPhase = ").append(phase); - annotation.append(", requestType = ").append(reqType.name()); - annotation.append(" )"); - return annotation.toString(); - } - - private List allImports() { - List imports = new ArrayList<>(); - imports.add("import org.apache.hadoop.ozone.om.request.validation" - + ".RequestFeatureValidator;"); - imports.add("import org.apache.hadoop.ozone.protocol.proto" - + ".OzoneManagerProtocolProtos.OMRequest;"); - imports.add("import org.apache.hadoop.ozone.protocol.proto" - + ".OzoneManagerProtocolProtos.OMResponse;"); - imports.add("import org.apache.hadoop.ozone.om.request.validation" - + ".ValidationContext;"); - imports.add("import com.google.protobuf.ServiceException;"); - for (ValidationCondition condition : ValidationCondition.values()) { - imports.add("import static org.apache.hadoop.ozone.om.request.validation" - + ".ValidationCondition." + condition.name() + ";"); - } - for (RequestProcessingPhase phase : RequestProcessingPhase.values()) { - imports.add("import static org.apache.hadoop.ozone.om.request.validation" - + ".RequestProcessingPhase." + phase.name() + ";"); - } - for (Type reqType : Type.values()) { - imports.add("import static org.apache.hadoop.ozone.protocol.proto" - + ".OzoneManagerProtocolProtos.Type." + reqType.name() + ";"); - } - return imports; - } - - private StringBuilder buildMethodSignature( - String[] modifiers, String returnType, - String[] paramspecs, String[] exceptions) { - StringBuilder signature = new StringBuilder(); - signature.append(" "); - for (String modifier : modifiers) { - signature.append(modifier).append(" "); - } - signature.append(returnType).append(" "); - signature.append("validatorMethod("); - signature.append(createParameterList(paramspecs)); - signature.append(") "); - signature.append(createThrowsClause(exceptions)); - return signature.append(" {"); - } - - private String createParameterList(String[] paramSpecs) { - if (paramSpecs == null || paramSpecs.length == 0) { - return ""; - } - StringBuilder parameters = new StringBuilder(); - for (String paramSpec : paramSpecs) { - parameters.append(paramSpec).append(", "); - } - return parameters.substring(0, parameters.length() - 2); - } - - private String createThrowsClause(String[] exceptions) { - StringBuilder throwsClause = new StringBuilder(); - if (exceptions != null && exceptions.length > 0) { - throwsClause.append(" throws "); - StringBuilder exceptionList = new StringBuilder(); - for (String exception : exceptions) { - exceptionList.append(exception).append(", "); - } - throwsClause - .append(exceptionList.substring(0, exceptionList.length() - 2)); - } - return throwsClause.toString(); - } -} diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestValidations.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestValidations.java index fdb332f66042..efc5e71b60ab 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestValidations.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestRequestValidations.java @@ -24,6 +24,7 @@ import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.request.validation.testvalidatorset1.GeneralValidatorsForTesting; import org.apache.hadoop.ozone.om.request.validation.testvalidatorset1.GeneralValidatorsForTesting.ValidationListener; +import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; @@ -45,6 +46,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -159,7 +162,7 @@ public void testPreProcessorExceptionHandling() throws Exception { ValidationContext ctx = of(aFinalizedVersionManager(), metadataManager); RequestValidations validations = loadValidations(ctx); assertThrows(Exception.class, - () -> validations.validateRequest(aDeleteKeysRequest(olderClientVersion()))); + () -> validations.validateRequest(aDeleteKeysRequest(ClientVersion.ERASURE_CODING_SUPPORT))); validationListener.assertNumOfEvents(1); validationListener.assertExactListOfValidatorsCalled( @@ -171,7 +174,8 @@ public void testPostProcessorExceptionHandling() { ValidationContext ctx = of(aFinalizedVersionManager(), metadataManager); RequestValidations validations = loadValidations(ctx); assertThrows(Exception.class, - () -> validations.validateResponse(aDeleteKeysRequest(olderClientVersion()), aDeleteKeysResponse())); + () -> validations.validateResponse(aDeleteKeysRequest(ClientVersion.ERASURE_CODING_SUPPORT), + aDeleteKeysResponse())); validationListener.assertNumOfEvents(1); validationListener.assertExactListOfValidatorsCalled( @@ -184,11 +188,11 @@ public void testOldClientConditionIsRecognizedAndPreValidatorsApplied() ValidationContext ctx = of(aFinalizedVersionManager(), metadataManager); RequestValidations validations = loadValidations(ctx); - validations.validateRequest(aCreateKeyRequest(olderClientVersion())); + validations.validateRequest(aCreateKeyRequest(ClientVersion.ERASURE_CODING_SUPPORT)); validationListener.assertNumOfEvents(1); validationListener.assertExactListOfValidatorsCalled( - "oldClientPreProcessCreateKeyValidator"); + "preProcessCreateKeyBucketLayoutClientValidator"); } @Test @@ -198,12 +202,12 @@ public void testOldClientConditionIsRecognizedAndPostValidatorsApplied() RequestValidations validations = loadValidations(ctx); validations.validateResponse( - aCreateKeyRequest(olderClientVersion()), aCreateKeyResponse()); + aCreateKeyRequest(ClientVersion.ERASURE_CODING_SUPPORT), aCreateKeyResponse()); validationListener.assertNumOfEvents(2); validationListener.assertExactListOfValidatorsCalled( - "oldClientPostProcessCreateKeyValidator", - "oldClientPostProcessCreateKeyValidator2"); + "postProcessCreateKeyBucketLayoutClientValidator", + "postProcessCreateKeyECReplicaIndexRequiredClientValidator"); } @Test @@ -212,12 +216,12 @@ public void testPreFinalizedWithOldClientConditionPreProcValidatorsApplied() ValidationContext ctx = of(anUnfinalizedVersionManager(), metadataManager); RequestValidations validations = loadValidations(ctx); - validations.validateRequest(aCreateKeyRequest(olderClientVersion())); + validations.validateRequest(aCreateKeyRequest(ClientVersion.ERASURE_CODING_SUPPORT)); validationListener.assertNumOfEvents(2); validationListener.assertExactListOfValidatorsCalled( - "preFinalizePreProcessCreateKeyValidator", - "oldClientPreProcessCreateKeyValidator"); + "preProcessCreateKeyQuotaLayoutValidator", + "preProcessCreateKeyBucketLayoutClientValidator"); } @Test @@ -227,13 +231,13 @@ public void testPreFinalizedWithOldClientConditionPostProcValidatorsApplied() RequestValidations validations = loadValidations(ctx); validations.validateResponse( - aCreateKeyRequest(olderClientVersion()), aCreateKeyResponse()); + aCreateKeyRequest(ClientVersion.ERASURE_CODING_SUPPORT), aCreateKeyResponse()); validationListener.assertNumOfEvents(3); validationListener.assertExactListOfValidatorsCalled( - "preFinalizePostProcessCreateKeyValidator", - "oldClientPostProcessCreateKeyValidator", - "oldClientPostProcessCreateKeyValidator2"); + "postProcessCreateKeyQuotaLayoutValidator", + "postProcessCreateKeyBucketLayoutClientValidator", + "postProcessCreateKeyECReplicaIndexRequiredClientValidator"); } /** @@ -295,6 +299,14 @@ private OMRequest aCreateKeyRequest(int clientVersion) { return aRequest(CreateKey, clientVersion); } + private OMRequest aCreateKeyRequest(ClientVersion clientVersion) { + return aRequest(CreateKey, clientVersion.toProtoValue()); + } + + private OMRequest aDeleteKeysRequest(ClientVersion clientVersion) { + return aDeleteKeysRequest(clientVersion.toProtoValue()); + } + private OMRequest aDeleteKeysRequest(int clientVersion) { return aRequest(DeleteKeys, clientVersion); } @@ -333,12 +345,16 @@ private OMResponse aResponse(Type type) { private LayoutVersionManager aFinalizedVersionManager() { LayoutVersionManager vm = mock(LayoutVersionManager.class); when(vm.needsFinalization()).thenReturn(false); + when(vm.getFeature(anyString())).thenReturn(OMLayoutFeature.QUOTA); + when(vm.getFeature(anyInt())).thenReturn(OMLayoutFeature.QUOTA); return vm; } private LayoutVersionManager anUnfinalizedVersionManager() { LayoutVersionManager vm = mock(LayoutVersionManager.class); when(vm.needsFinalization()).thenReturn(true); + when(vm.getFeature(anyString())).thenReturn(OMLayoutFeature.HSYNC); + when(vm.getFeature(anyInt())).thenReturn(OMLayoutFeature.HSYNC); return vm; } diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestValidatorRegistry.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestValidatorRegistry.java index 076ba0187272..434322af86df 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestValidatorRegistry.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestValidatorRegistry.java @@ -16,6 +16,13 @@ */ package org.apache.hadoop.ozone.om.request.validation; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; +import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase; +import org.apache.hadoop.ozone.request.validation.ValidatorRegistry; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,16 +32,16 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.POST_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.PRE_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.ValidationCondition.CLUSTER_NEEDS_FINALIZATION; -import static org.apache.hadoop.ozone.om.request.validation.ValidationCondition.OLDER_CLIENT_REQUESTS; +import static org.apache.hadoop.ozone.om.request.validation.VersionExtractor.CLIENT_VERSION_EXTRACTOR; +import static org.apache.hadoop.ozone.om.request.validation.VersionExtractor.LAYOUT_VERSION_EXTRACTOR; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.POST_PROCESS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.PRE_PROCESS; import static org.apache.hadoop.ozone.om.request.validation.testvalidatorset1.GeneralValidatorsForTesting.startValidatorTest; import static org.apache.hadoop.ozone.om.request.validation.testvalidatorset1.GeneralValidatorsForTesting.finishValidatorTest; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.CreateDirectory; @@ -59,6 +66,9 @@ public class TestValidatorRegistry { private static final String PACKAGE_WO_VALIDATORS = "org.apache.hadoop.hdds.annotation"; + private static final Set REQUEST_PROCESSING_PHASES = + Sets.immutableEnumSet(PRE_PROCESS, POST_PROCESS); + @BeforeEach public void setup() { startValidatorTest(); @@ -71,121 +81,148 @@ public void tearDown() { @Test public void testNoValidatorsReturnedForEmptyConditionList() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); - List validators = - registry.validationsFor(emptyList(), CreateKey, PRE_PROCESS); + ValidatorRegistry registry = + new ValidatorRegistry<>(OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass) + .collect(Collectors.toSet()), REQUEST_PROCESSING_PHASES); + List validators = registry.validationsFor(CreateKey, PRE_PROCESS, + CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.CURRENT); assertTrue(validators.isEmpty()); } @Test public void testRegistryHasThePreFinalizePreProcessCreateKeyValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); List validators = - registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION), CreateKey, PRE_PROCESS); + registry.validationsFor(CreateKey, PRE_PROCESS, + ImmutableMap.of(CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.CURRENT, + LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), OMLayoutFeature.FILESYSTEM_SNAPSHOT)); assertEquals(1, validators.size()); - String expectedMethodName = "preFinalizePreProcessCreateKeyValidator"; + String expectedMethodName = "preProcessCreateKeyQuotaLayoutValidator"; assertEquals(expectedMethodName, validators.get(0).getName()); } @Test public void testRegistryHasThePreFinalizePostProcessCreateKeyValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); - List validators = - registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION), CreateKey, POST_PROCESS); + ValidatorRegistry registry = + new ValidatorRegistry<>(OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + List validators = registry.validationsFor(CreateKey, POST_PROCESS, + ImmutableMap.of(CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.CURRENT, + LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), OMLayoutFeature.BUCKET_LAYOUT_SUPPORT)); assertEquals(1, validators.size()); - String expectedMethodName = "preFinalizePostProcessCreateKeyValidator"; + String expectedMethodName = "postProcessCreateKeyQuotaLayoutValidator"; assertEquals(expectedMethodName, validators.get(0).getName()); } @Test public void testRegistryHasTheOldClientPreProcessCreateKeyValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); + ValidatorRegistry registry = + new ValidatorRegistry<>(OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); List validators = - registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateKey, PRE_PROCESS); + registry.validationsFor(CreateKey, PRE_PROCESS, CLIENT_VERSION_EXTRACTOR.getValidatorClass(), + ClientVersion.ERASURE_CODING_SUPPORT); assertEquals(2, validators.size()); List methodNames = validators.stream().map(Method::getName).collect(Collectors.toList()); - assertThat(methodNames).contains("oldClientPreProcessCreateKeyValidator"); - assertThat(methodNames).contains("oldClientPreProcessCreateKeyValidator2"); + assertEquals(Arrays.asList("preProcessCreateKeyBucketLayoutClientValidator", + "preProcessCreateKeyBucketLayoutClientValidator"), methodNames); } @Test public void testRegistryHasTheOldClientPostProcessCreateKeyValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); - List validators = - registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateKey, POST_PROCESS); + ValidatorRegistry registry = + new ValidatorRegistry<>(OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + List validators = registry.validationsFor(CreateKey, POST_PROCESS, + CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.ERASURE_CODING_SUPPORT); assertEquals(2, validators.size()); List methodNames = validators.stream().map(Method::getName).collect(Collectors.toList()); - assertThat(methodNames).contains("oldClientPostProcessCreateKeyValidator"); - assertThat(methodNames).contains("oldClientPostProcessCreateKeyValidator2"); + assertThat(methodNames).contains("postProcessCreateKeyBucketLayoutClientValidator"); + assertThat(methodNames).contains("postProcessCreateKeyECReplicaIndexRequiredClientValidator"); } @Test public void testRegistryHasTheMultiPurposePreProcessCreateVolumeValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); + ValidatorRegistry registry = + new ValidatorRegistry<>(OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); List preFinalizeValidators = - registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION), CreateVolume, PRE_PROCESS); + registry.validationsFor(CreateVolume, PRE_PROCESS, LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), + OMLayoutFeature.HSYNC); List newClientValidators = - registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateVolume, PRE_PROCESS); + registry.validationsFor(CreateVolume, PRE_PROCESS, CLIENT_VERSION_EXTRACTOR.getValidatorClass(), + ClientVersion.ERASURE_CODING_SUPPORT); assertEquals(1, preFinalizeValidators.size()); assertEquals(1, newClientValidators.size()); - String expectedMethodName = "multiPurposePreProcessCreateVolumeValidator"; + String expectedMethodName = "multiPurposePreProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator"; assertEquals(expectedMethodName, preFinalizeValidators.get(0).getName()); assertEquals(expectedMethodName, newClientValidators.get(0).getName()); } @Test public void testRegistryHasTheMultiPurposePostProcessCreateVolumeValidator() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); List preFinalizeValidators = - registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION), CreateVolume, POST_PROCESS); + registry.validationsFor(CreateVolume, POST_PROCESS, LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), + OMLayoutFeature.HSYNC); List oldClientValidators = - registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateVolume, POST_PROCESS); + registry.validationsFor(CreateVolume, POST_PROCESS, CLIENT_VERSION_EXTRACTOR.getValidatorClass(), + ClientVersion.ERASURE_CODING_SUPPORT); assertEquals(1, preFinalizeValidators.size()); assertEquals(1, oldClientValidators.size()); - String expectedMethodName = "multiPurposePostProcessCreateVolumeValidator"; + String expectedMethodName = "multiPurposePostProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator"; assertEquals(expectedMethodName, preFinalizeValidators.get(0).getName()); assertEquals(expectedMethodName, oldClientValidators.get(0).getName()); } @Test public void testValidatorsAreReturnedForMultiCondition() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); - List validators = - registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION, OLDER_CLIENT_REQUESTS), - CreateKey, POST_PROCESS); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + List validators = registry.validationsFor(CreateKey, POST_PROCESS, + ImmutableMap.of(CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.ERASURE_CODING_SUPPORT, + LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), OMLayoutFeature.HSYNC)); assertEquals(3, validators.size()); List methodNames = validators.stream().map(Method::getName).collect(Collectors.toList()); - assertThat(methodNames).contains("preFinalizePostProcessCreateKeyValidator"); - assertThat(methodNames).contains("oldClientPostProcessCreateKeyValidator"); - assertThat(methodNames).contains("oldClientPostProcessCreateKeyValidator2"); + assertThat(methodNames).contains("postProcessCreateKeyQuotaLayoutValidator"); + assertThat(methodNames).contains("postProcessCreateKeyBucketLayoutClientValidator"); + assertThat(methodNames).contains("postProcessCreateKeyECReplicaIndexRequiredClientValidator"); } @Test public void testNoValidatorForRequestsAtAllReturnsEmptyList() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE_WO_VALIDATORS); - assertTrue(registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateKey, PRE_PROCESS).isEmpty()); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE_WO_VALIDATORS, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + assertTrue(registry.validationsFor(CreateKey, PRE_PROCESS, + ImmutableMap.of(CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.ERASURE_CODING_SUPPORT, + LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), OMLayoutFeature.HSYNC)).isEmpty()); } @Test @@ -196,18 +233,41 @@ public void testNoValidatorForConditionReturnsEmptyList() for (URL url : urls) { urlsToUse.add(new URL(url, PACKAGE2.replaceAll("\\.", "/"))); } - ValidatorRegistry registry = new ValidatorRegistry(urlsToUse); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, urlsToUse, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); - assertTrue(registry.validationsFor( - asList(CLUSTER_NEEDS_FINALIZATION), CreateKey, PRE_PROCESS).isEmpty()); + assertTrue(registry.validationsFor(CreateKey, PRE_PROCESS, + ImmutableMap.of(CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.CURRENT, + LAYOUT_VERSION_EXTRACTOR.getValidatorClass(), OMLayoutFeature.BUCKET_LAYOUT_SUPPORT)).isEmpty()); } @Test public void testNoDefinedValidationForRequestReturnsEmptyList() { - ValidatorRegistry registry = new ValidatorRegistry(PACKAGE); + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + + assertTrue(registry.validationsFor(CreateDirectory, null, CLIENT_VERSION_EXTRACTOR.getValidatorClass(), + ClientVersion.ERASURE_CODING_SUPPORT).isEmpty()); + } - assertTrue(registry.validationsFor( - asList(OLDER_CLIENT_REQUESTS), CreateDirectory, null).isEmpty()); + @Test + public void testFutureVersionForRequestReturnsOnlyFutureVersionValidators() { + ValidatorRegistry registry = new ValidatorRegistry<>( + OzoneManagerProtocolProtos.Type.class, PACKAGE, + Arrays.stream(VersionExtractor.values()).map(VersionExtractor::getValidatorClass).collect(Collectors.toSet()), + REQUEST_PROCESSING_PHASES); + + List validators = registry.validationsFor(CreateKey, PRE_PROCESS, + CLIENT_VERSION_EXTRACTOR.getValidatorClass(), ClientVersion.FUTURE_VERSION); + + assertEquals(1, validators.size()); + List methodNames = + validators.stream().map(Method::getName).collect(Collectors.toList()); + assertThat(methodNames).contains("preProcessCreateKeyFutureClientValidator"); } } diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestVersionExtractor.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestVersionExtractor.java index a3c9c76e70fe..5b3c0660a7cf 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestVersionExtractor.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/TestVersionExtractor.java @@ -16,6 +16,7 @@ */ package org.apache.hadoop.ozone.om.request.validation; +import com.google.common.collect.ImmutableMap; import org.apache.hadoop.ozone.ClientVersion; import org.apache.hadoop.ozone.Versioned; import org.apache.hadoop.ozone.om.exceptions.OMException; @@ -23,10 +24,14 @@ import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.upgrade.LayoutVersionManager; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.ValueSource; +import java.lang.annotation.Annotation; +import java.util.Map; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -41,7 +46,6 @@ void testLayoutVersionExtractor(OMLayoutFeature layoutVersionValue) throws OMExc when(context.versionManager()).thenReturn(layoutVersionManager); Versioned version = VersionExtractor.LAYOUT_VERSION_EXTRACTOR.extractVersion(null, context); assertEquals(layoutVersionValue, version); - assertEquals(OMLayoutFeature.class, VersionExtractor.LAYOUT_VERSION_EXTRACTOR.getVersionClass()); } @ParameterizedTest @@ -51,7 +55,6 @@ void testClientVersionExtractor(ClientVersion expectedClientVersion) { when(request.getVersion()).thenReturn(expectedClientVersion.version()); Versioned version = VersionExtractor.CLIENT_VERSION_EXTRACTOR.extractVersion(request, null); assertEquals(expectedClientVersion, version); - assertEquals(ClientVersion.class, VersionExtractor.CLIENT_VERSION_EXTRACTOR.getVersionClass()); } @ParameterizedTest @@ -61,6 +64,15 @@ void testClientVersionExtractorForFutureValues(int futureVersion) { when(request.getVersion()).thenReturn(ClientVersion.CURRENT_VERSION + futureVersion); Versioned version = VersionExtractor.CLIENT_VERSION_EXTRACTOR.extractVersion(request, null); assertEquals(ClientVersion.FUTURE_VERSION, version); - assertEquals(ClientVersion.class, VersionExtractor.CLIENT_VERSION_EXTRACTOR.getVersionClass()); + } + + @Test + void testGetValidatorClass() { + Map> expectedValidatorClasses = + ImmutableMap.of(VersionExtractor.CLIENT_VERSION_EXTRACTOR, OMClientVersionValidator.class, + VersionExtractor.LAYOUT_VERSION_EXTRACTOR, OMLayoutVersionValidator.class); + for (VersionExtractor extractor : VersionExtractor.values()) { + assertEquals(expectedValidatorClasses.get(extractor), extractor.getValidatorClass()); + } } } diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset1/GeneralValidatorsForTesting.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset1/GeneralValidatorsForTesting.java index 35c3afa4cf96..bc60dbf21b29 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset1/GeneralValidatorsForTesting.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset1/GeneralValidatorsForTesting.java @@ -16,9 +16,12 @@ */ package org.apache.hadoop.ozone.om.request.validation.testvalidatorset1; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; +import org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator; import org.apache.hadoop.ozone.om.request.validation.TestRequestValidations; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; +import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse; @@ -26,10 +29,8 @@ import java.util.ArrayList; import java.util.List; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.POST_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.PRE_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.ValidationCondition.CLUSTER_NEEDS_FINALIZATION; -import static org.apache.hadoop.ozone.om.request.validation.ValidationCondition.OLDER_CLIENT_REQUESTS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.POST_PROCESS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.PRE_PROCESS; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.CreateKey; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.CreateVolume; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.DeleteKeys; @@ -88,82 +89,98 @@ private static void fireValidationEvent(String calledMethodName) { listeners.forEach(l -> l.validationCalled(calledMethodName)); } - @RequestFeatureValidator( - conditions = { CLUSTER_NEEDS_FINALIZATION }, + @OMLayoutVersionValidator( + applyBefore = OMLayoutFeature.QUOTA, processingPhase = PRE_PROCESS, requestType = CreateKey) - public static OMRequest preFinalizePreProcessCreateKeyValidator( + public static OMRequest preProcessCreateKeyQuotaLayoutValidator( OMRequest req, ValidationContext ctx) { - fireValidationEvent("preFinalizePreProcessCreateKeyValidator"); + fireValidationEvent("preProcessCreateKeyQuotaLayoutValidator"); return req; } - @RequestFeatureValidator( - conditions = { CLUSTER_NEEDS_FINALIZATION }, + @OMClientVersionValidator( + applyBefore = ClientVersion.FUTURE_VERSION, + processingPhase = PRE_PROCESS, + requestType = CreateKey) + public static OMRequest preProcessCreateKeyFutureClientValidator( + OMRequest req, ValidationContext ctx) { + fireValidationEvent("preProcessCreateKeyFutureClientValidator"); + return req; + } + + @OMLayoutVersionValidator( + applyBefore = OMLayoutFeature.QUOTA, processingPhase = POST_PROCESS, requestType = CreateKey) - public static OMResponse preFinalizePostProcessCreateKeyValidator( + public static OMResponse postProcessCreateKeyQuotaLayoutValidator( OMRequest req, OMResponse resp, ValidationContext ctx) { - fireValidationEvent("preFinalizePostProcessCreateKeyValidator"); + fireValidationEvent("postProcessCreateKeyQuotaLayoutValidator"); return resp; } - @RequestFeatureValidator( - conditions = { OLDER_CLIENT_REQUESTS }, + @OMClientVersionValidator( processingPhase = PRE_PROCESS, - requestType = CreateKey) - public static OMRequest oldClientPreProcessCreateKeyValidator( + requestType = CreateKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT) + public static OMRequest preProcessCreateKeyBucketLayoutClientValidator( OMRequest req, ValidationContext ctx) { - fireValidationEvent("oldClientPreProcessCreateKeyValidator"); + fireValidationEvent("preProcessCreateKeyBucketLayoutClientValidator"); return req; } - @RequestFeatureValidator( - conditions = { OLDER_CLIENT_REQUESTS }, + @OMClientVersionValidator( processingPhase = POST_PROCESS, - requestType = CreateKey) - public static OMResponse oldClientPostProcessCreateKeyValidator( + requestType = CreateKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT) + public static OMResponse postProcessCreateKeyBucketLayoutClientValidator( OMRequest req, OMResponse resp, ValidationContext ctx) { - fireValidationEvent("oldClientPostProcessCreateKeyValidator"); + fireValidationEvent("postProcessCreateKeyBucketLayoutClientValidator"); return resp; } - @RequestFeatureValidator( - conditions = { CLUSTER_NEEDS_FINALIZATION, OLDER_CLIENT_REQUESTS }, + @OMClientVersionValidator( processingPhase = PRE_PROCESS, - requestType = CreateVolume) - public static OMRequest multiPurposePreProcessCreateVolumeValidator( + requestType = CreateVolume, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT) + @OMLayoutVersionValidator(processingPhase = PRE_PROCESS, + requestType = CreateVolume, + applyBefore = OMLayoutFeature.QUOTA) + public static OMRequest multiPurposePreProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator( OMRequest req, ValidationContext ctx) { - fireValidationEvent("multiPurposePreProcessCreateVolumeValidator"); + fireValidationEvent("multiPurposePreProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator"); return req; } - @RequestFeatureValidator( - conditions = { OLDER_CLIENT_REQUESTS, CLUSTER_NEEDS_FINALIZATION }, + @OMClientVersionValidator( processingPhase = POST_PROCESS, - requestType = CreateVolume) - public static OMResponse multiPurposePostProcessCreateVolumeValidator( + requestType = CreateVolume, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT) + @OMLayoutVersionValidator(processingPhase = POST_PROCESS, + requestType = CreateVolume, + applyBefore = OMLayoutFeature.QUOTA) + public static OMResponse multiPurposePostProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator( OMRequest req, OMResponse resp, ValidationContext ctx) { - fireValidationEvent("multiPurposePostProcessCreateVolumeValidator"); + fireValidationEvent("multiPurposePostProcessCreateVolumeBucketLayoutCLientQuotaLayoutValidator"); return resp; } - @RequestFeatureValidator( - conditions = { OLDER_CLIENT_REQUESTS }, + @OMClientVersionValidator( processingPhase = POST_PROCESS, - requestType = CreateKey) - public static OMResponse oldClientPostProcessCreateKeyValidator2( + requestType = CreateKey, + applyBefore = ClientVersion.EC_REPLICA_INDEX_REQUIRED_IN_BLOCK_REQUEST) + public static OMResponse postProcessCreateKeyECReplicaIndexRequiredClientValidator( OMRequest req, OMResponse resp, ValidationContext ctx) { - fireValidationEvent("oldClientPostProcessCreateKeyValidator2"); + fireValidationEvent("postProcessCreateKeyECReplicaIndexRequiredClientValidator"); return resp; } - @RequestFeatureValidator( - conditions = {OLDER_CLIENT_REQUESTS}, + @OMClientVersionValidator( processingPhase = PRE_PROCESS, - requestType = DeleteKeys + requestType = DeleteKeys, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) - public static OMRequest throwingPreProcessValidator( + public static OMRequest throwingPreProcessDeleteKeyBucketLayoutClientValidator( OMRequest req, ValidationContext ctx) throws IOException { fireValidationEvent("throwingPreProcessValidator"); if (validatorTestsRunning) { @@ -172,12 +189,12 @@ public static OMRequest throwingPreProcessValidator( return req; } - @RequestFeatureValidator( - conditions = {OLDER_CLIENT_REQUESTS}, + @OMClientVersionValidator( processingPhase = POST_PROCESS, - requestType = DeleteKeys + requestType = DeleteKeys, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT ) - public static OMResponse throwingPostProcessValidator( + public static OMResponse throwingPostProcessDeleteKeyBucketLayoutClientValidator( OMRequest req, OMResponse resp, ValidationContext ctx) throws IOException { fireValidationEvent("throwingPostProcessValidator"); diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset2/ValidatorsForOnlyOldClientValidations.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset2/ValidatorsForOnlyOldClientValidations.java index 447b9ab0260b..061a5b9c429d 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset2/ValidatorsForOnlyOldClientValidations.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/validation/testvalidatorset2/ValidatorsForOnlyOldClientValidations.java @@ -16,12 +16,12 @@ */ package org.apache.hadoop.ozone.om.request.validation.testvalidatorset2; -import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator; +import org.apache.hadoop.ozone.ClientVersion; +import org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator; import org.apache.hadoop.ozone.om.request.validation.ValidationContext; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; -import static org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase.PRE_PROCESS; -import static org.apache.hadoop.ozone.om.request.validation.ValidationCondition.OLDER_CLIENT_REQUESTS; +import static org.apache.hadoop.ozone.request.validation.RequestProcessingPhase.PRE_PROCESS; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.CreateKey; /** @@ -32,11 +32,11 @@ public final class ValidatorsForOnlyOldClientValidations { private ValidatorsForOnlyOldClientValidations() { } - @RequestFeatureValidator( - conditions = { OLDER_CLIENT_REQUESTS }, + @OMClientVersionValidator( processingPhase = PRE_PROCESS, - requestType = CreateKey) - public static OMRequest oldClientPreProcessCreateKeyValidator2( + requestType = CreateKey, + applyBefore = ClientVersion.BUCKET_LAYOUT_SUPPORT) + public static OMRequest preProcessCreateKeyBucketLayoutClientValidator( OMRequest req, ValidationContext ctx) { return req; } diff --git a/hadoop-ozone/recon-codegen/pom.xml b/hadoop-ozone/recon-codegen/pom.xml index b8345c7d343f..006c155cc574 100644 --- a/hadoop-ozone/recon-codegen/pom.xml +++ b/hadoop-ozone/recon-codegen/pom.xml @@ -105,7 +105,8 @@ Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/recon/pom.xml b/hadoop-ozone/recon/pom.xml index f203689b6699..01ba22f1c3b4 100644 --- a/hadoop-ozone/recon/pom.xml +++ b/hadoop-ozone/recon/pom.xml @@ -64,7 +64,8 @@ Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/s3gateway/pom.xml b/hadoop-ozone/s3gateway/pom.xml index f012d3f1aabb..28f28e186801 100644 --- a/hadoop-ozone/s3gateway/pom.xml +++ b/hadoop-ozone/s3gateway/pom.xml @@ -283,7 +283,8 @@ Only selected annotation processors are enabled, see configuration of maven-compiler-plugin. - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices diff --git a/hadoop-ozone/tools/pom.xml b/hadoop-ozone/tools/pom.xml index 8ea8ded01ce4..71a4631f1207 100644 --- a/hadoop-ozone/tools/pom.xml +++ b/hadoop-ozone/tools/pom.xml @@ -317,7 +317,8 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> org.apache.hadoop.hdds.conf.Config org.apache.hadoop.hdds.conf.ConfigGroup org.apache.hadoop.hdds.scm.metadata.Replicate - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator diff --git a/pom.xml b/pom.xml index 8cf055522b23..f0ba7ea0e704 100644 --- a/pom.xml +++ b/pom.xml @@ -1558,7 +1558,8 @@ org.apache.hadoop.hdds.conf.Config org.apache.hadoop.hdds.conf.ConfigGroup - org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator + org.apache.hadoop.ozone.om.request.validation.OMLayoutVersionValidator + org.apache.hadoop.ozone.om.request.validation.OMClientVersionValidator org.apache.hadoop.hdds.scm.metadata.Replicate org.kohsuke.MetaInfServices