diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersions.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersions.java index 691cf9a7314b..d095a5bdb0ea 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersions.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/ClientVersions.java @@ -28,8 +28,27 @@ public final class ClientVersions { // DatanodeDetails#getFromProtobuf handles unknown types of ports public static final int VERSION_HANDLES_UNKNOWN_DN_PORTS = 1; + // TODO: Change the version of FSO/EC if one is released before the other. + // Client supports EC objects + public static final int CLIENT_EC_CAPABLE = 2; + // Client supports FSO buckets + public static final int CLIENT_FSO_CAPABLE = CLIENT_EC_CAPABLE; + // this should always point to the latest version - public static final int CURRENT_VERSION = VERSION_HANDLES_UNKNOWN_DN_PORTS; + public static final int CURRENT_VERSION = CLIENT_EC_CAPABLE; + + /** + * Validates if the client version is equal to or newer than the expected + * version supported. Client are expected to be backward compatible if it + * is sending a request. + * @param desiredClientVersion Minimum version of the client expected. + * @param actualClientVersion Version of the client witnessed. + * @return true if client is at or newer than the desired version. + */ + public static boolean isClientCompatible(int desiredClientVersion, + int actualClientVersion) { + return desiredClientVersion >= actualClientVersion; + } private ClientVersions() { // no instances diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OMProtocolVersion.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OMProtocolVersion.java new file mode 100644 index 000000000000..fdcb994328dc --- /dev/null +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OMProtocolVersion.java @@ -0,0 +1,64 @@ +/* + * 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; + +import org.apache.hadoop.util.ComparableVersion; + +/** + * Versioning for OM's APIs used by ozone clients. + */ +public final class OMProtocolVersion { + + // OM Authenticates the user using the S3 Auth info embedded in request proto. + public static final String OM_SUPPORTS_S3AUTH_VIA_PROTO = "2.0.0"; + public static final String OM_SUPPORTS_EC = "2.1.0"; + public static final String OM_SUPPORTS_FSO = "2.1.0"; + + // Points to the latest version in code, always update this when adding + // a new version. + public static final String OM_LATEST_VERSION = OM_SUPPORTS_S3AUTH_VIA_PROTO; + + /** + * Checks if the OM is running a version at or greater than the desired + * version. A Client might leverage a version that breaks compatibility + * with older OMs and this method can be used to check the compatability. + * If the desired version is not specified, it assumes there is no minimum + * version requirement. + * @param desiredOMVersion Minimum version that is required for OM. + * @param actualOMVersion Actual version received. + * @return true if actual OM version is at or newer than the desired version. + */ + public static boolean isOMNewerThan( + String desiredOMVersion, + String actualOMVersion) { + if (desiredOMVersion == null || desiredOMVersion.isEmpty()) { + // Empty strings assumes client is fine with any OM version. + return true; + } + ComparableVersion comparableExpectedVersion = + new ComparableVersion(desiredOMVersion); + ComparableVersion comparableOMVersion = + new ComparableVersion(actualOMVersion); + return comparableOMVersion.compareTo(comparableExpectedVersion) >= 0; + } + + private OMProtocolVersion() { + + } +} diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java index 9c7d7690faa4..4d199600ae99 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java @@ -30,6 +30,8 @@ import java.util.concurrent.TimeUnit; +import static org.apache.hadoop.ozone.OMProtocolVersion.OM_LATEST_VERSION; + /** * This class contains constants for configuration keys used in Ozone. */ @@ -465,7 +467,8 @@ public final class OzoneConfigKeys { "ozone.om.client.protocol.version"; // The version of the protocol for Client (S3G/OFS) to OM Communication. // The protocol starts at 2.0.0 and a null or empty value for older versions. - public static final String OZONE_OM_CLIENT_PROTOCOL_VERSION = "2.0.0"; + public static final String OZONE_OM_CLIENT_PROTOCOL_VERSION = + OM_LATEST_VERSION; /** * There is no need to instantiate this class. diff --git a/hadoop-hdds/common/src/test/java/org/apache/hadoop/OMProtocolVersionTest.java b/hadoop-hdds/common/src/test/java/org/apache/hadoop/OMProtocolVersionTest.java new file mode 100644 index 000000000000..286609accd35 --- /dev/null +++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/OMProtocolVersionTest.java @@ -0,0 +1,85 @@ +/** + * 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;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.apache.hadoop.ozone.OMProtocolVersion.OM_LATEST_VERSION;
+
+class OMProtocolVersionTest {
+ private enum ValidateOmVersionTestCases {
+ NULL_EXPECTED_NULL_OM(
+ null, // Expected version
+ null, // OM Version
+ true), // Should validation pass
+ EMPTY_EXPECTED_NULL_OM(
+ "",
+ null,
+ true),
+ EMPTY_EXPECTED_EMPTY_OM(
+ "",
+ "",
+ true),
+ NULL_EXPECTED_EMPTY_OM(
+ null,
+ "",
+ true),
+ OM_EXPECTED_LATEST_OM(
+ "1.0.0",
+ OM_LATEST_VERSION,
+ true),
+ OM_EXPECTED_NEWER_OM(
+ "1.1.0",
+ "1.11.0",
+ true),
+ NEWER_EXPECTED_OLD_OM(
+ "1.20.0",
+ "1.19.0",
+ false),
+ NULL_EXPECTED_OM(
+ null,
+ OM_LATEST_VERSION,
+ true);
+ private static final List
+ * 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.protocolPB;
+
+import org.apache.hadoop.ozone.ClientVersions;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OMManagerClientVersionsValidations is a collection of all the validations
+ * that need to be run to maintain compatibility with varying versions of
+ * client.
+ */
+public final class OMManagerClientVersionValidations {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(OMManagerClientVersionValidations.class);
+ private OMManagerClientVersionValidations() {
+
+ }
+
+ public static void validateClientVersionPostProcess(
+ OzoneManagerProtocolProtos.Type lookupKey,
+ OzoneManagerProtocolProtos.OMRequest request,
+ OzoneManagerProtocolProtos.InfoBucketResponse infoBucketResponse) {
+ // ToDo: Add EC specific rejection of request based on key info.
+ if (request.hasVersion()
+ &&
+ ClientVersions.isClientCompatible(
+ ClientVersions.CLIENT_EC_CAPABLE,
+ request.getVersion())){
+ return;
+ }
+ // TODO: Update the response and log message
+ LOG.debug("Request rejected as client version is not EC Compatible: {}",
+ request);
+ }
+ public static void validateClientVersionPostProcess(
+ OzoneManagerProtocolProtos.Type lookupKey,
+ OzoneManagerProtocolProtos.OMRequest request,
+ OzoneManagerProtocolProtos.LookupKeyResponse lookupKeyResponse) {
+ // ToDo: Add FSO specific rejection of request based on bucket info.
+ if (request.hasVersion()
+ &&
+ ClientVersions.isClientCompatible(
+ ClientVersions.CLIENT_FSO_CAPABLE,
+ request.getVersion())){
+ return;
+ }
+ // TODO: Update the response and log message
+ LOG.debug("Request rejected as client version is not FSO Compatible: {}",
+ request);
+ }
+
+}
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 5674d6a3152f..66cb791c04d2 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
@@ -94,6 +94,8 @@
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.MultipartUploadInfo;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartInfo;
+import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.InfoBucket;
+import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.LookupKey;
import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer.StatusAndMessages;
import org.slf4j.Logger;
@@ -146,6 +148,10 @@ public OMResponse handleReadRequest(OMRequest request) {
InfoBucketResponse infoBucketResponse = infoBucket(
request.getInfoBucketRequest());
responseBuilder.setInfoBucketResponse(infoBucketResponse);
+ OMManagerClientVersionValidations.validateClientVersionPostProcess(
+ InfoBucket,
+ request,
+ infoBucketResponse);
break;
case ListBuckets:
ListBucketsResponse listBucketsResponse = listBuckets(
@@ -156,6 +162,10 @@ public OMResponse handleReadRequest(OMRequest request) {
LookupKeyResponse lookupKeyResponse = lookupKey(
request.getLookupKeyRequest(), request.getVersion());
responseBuilder.setLookupKeyResponse(lookupKeyResponse);
+ OMManagerClientVersionValidations.validateClientVersionPostProcess(
+ LookupKey,
+ request,
+ lookupKeyResponse);
break;
case ListKeys:
ListKeysResponse listKeysResponse = listKeys(
@@ -389,10 +399,7 @@ private LookupKeyResponse lookupKey(LookupKeyRequest request,
.setHeadOp(keyArgs.getHeadOp())
.build();
OmKeyInfo keyInfo = impl.lookupKey(omKeyArgs);
-
resp.setKeyInfo(keyInfo.getProtobuf(keyArgs.getHeadOp(), clientVersion));
-
-
return resp.build();
}